|
- use eyre::{bail, Context};
- use std::{
- env::consts::{DLL_PREFIX, DLL_SUFFIX, EXE_SUFFIX},
- path::Path,
- };
- use tracing::metadata::LevelFilter;
- use tracing_subscriber::Layer;
-
- #[derive(Debug, Clone, clap::Parser)]
- pub struct Args {
- #[clap(long)]
- pub run_dora_runtime: bool,
- }
-
- #[tokio::main]
- async fn main() -> eyre::Result<()> {
- let Args { run_dora_runtime } = clap::Parser::parse();
-
- if run_dora_runtime {
- return tokio::task::block_in_place(dora_daemon::run_dora_runtime);
- }
- set_up_tracing().wrap_err("failed to set up tracing")?;
-
- if cfg!(windows) {
- tracing::error!(
- "The c++ example does not work on Windows currently because of a linker error"
- );
- return Ok(());
- }
-
- let root = Path::new(env!("CARGO_MANIFEST_DIR"));
- let target = root.join("target");
- std::env::set_current_dir(root.join(file!()).parent().unwrap())
- .wrap_err("failed to set working dir")?;
-
- tokio::fs::create_dir_all("build").await?;
- let build_dir = Path::new("build");
-
- build_package("dora-node-api-cxx").await?;
- let node_cxxbridge = target
- .join("cxxbridge")
- .join("dora-node-api-cxx")
- .join("src");
- tokio::fs::copy(
- node_cxxbridge.join("lib.rs.cc"),
- build_dir.join("node-bridge.cc"),
- )
- .await?;
- tokio::fs::copy(
- node_cxxbridge.join("lib.rs.h"),
- build_dir.join("dora-node-api.h"),
- )
- .await?;
- tokio::fs::write(
- build_dir.join("operator.h"),
- r###"#include "../operator-rust-api/operator.h""###,
- )
- .await?;
-
- build_package("dora-operator-api-cxx").await?;
- let operator_cxxbridge = target
- .join("cxxbridge")
- .join("dora-operator-api-cxx")
- .join("src");
- tokio::fs::copy(
- operator_cxxbridge.join("lib.rs.cc"),
- build_dir.join("operator-bridge.cc"),
- )
- .await?;
- tokio::fs::copy(
- operator_cxxbridge.join("lib.rs.h"),
- build_dir.join("dora-operator-api.h"),
- )
- .await?;
-
- build_package("dora-node-api-c").await?;
- build_package("dora-operator-api-c").await?;
- build_cxx_node(
- root,
- &[
- &dunce::canonicalize(Path::new("node-rust-api").join("main.cc"))?,
- &dunce::canonicalize(build_dir.join("node-bridge.cc"))?,
- ],
- "node_rust_api",
- &["-l", "dora_node_api_cxx"],
- )
- .await?;
- build_cxx_node(
- root,
- &[&dunce::canonicalize(
- Path::new("node-c-api").join("main.cc"),
- )?],
- "node_c_api",
- &["-l", "dora_node_api_c"],
- )
- .await?;
- build_cxx_operator(
- &[
- &dunce::canonicalize(Path::new("operator-rust-api").join("operator.cc"))?,
- &dunce::canonicalize(build_dir.join("operator-bridge.cc"))?,
- ],
- "operator_rust_api",
- &[
- "-l",
- "dora_operator_api_cxx",
- "-L",
- root.join("target").join("debug").to_str().unwrap(),
- ],
- )
- .await?;
- build_cxx_operator(
- &[&dunce::canonicalize(
- Path::new("operator-c-api").join("operator.cc"),
- )?],
- "operator_c_api",
- &[],
- )
- .await?;
-
- let dataflow = Path::new("dataflow.yml").to_owned();
- build_package("dora-runtime").await?;
- dora_daemon::Daemon::run_dataflow(&dataflow, false).await?;
-
- Ok(())
- }
-
- async fn build_package(package: &str) -> eyre::Result<()> {
- let cargo = std::env::var("CARGO").unwrap();
- let mut cmd = tokio::process::Command::new(&cargo);
- cmd.arg("build");
- cmd.arg("--package").arg(package);
- if !cmd.status().await?.success() {
- bail!("failed to build {package}");
- };
- Ok(())
- }
-
- async fn build_cxx_node(
- root: &Path,
- paths: &[&Path],
- out_name: &str,
- args: &[&str],
- ) -> eyre::Result<()> {
- let mut clang = tokio::process::Command::new("clang++");
- clang.args(paths);
- clang.arg("-std=c++17");
- #[cfg(target_os = "linux")]
- {
- clang.arg("-l").arg("m");
- clang.arg("-l").arg("rt");
- clang.arg("-l").arg("dl");
- clang.arg("-pthread");
- }
- #[cfg(target_os = "windows")]
- {
- clang.arg("-ladvapi32");
- clang.arg("-luserenv");
- clang.arg("-lkernel32");
- clang.arg("-lws2_32");
- clang.arg("-lbcrypt");
- clang.arg("-lncrypt");
- clang.arg("-lschannel");
- clang.arg("-lntdll");
- clang.arg("-liphlpapi");
-
- clang.arg("-lcfgmgr32");
- clang.arg("-lcredui");
- clang.arg("-lcrypt32");
- clang.arg("-lcryptnet");
- clang.arg("-lfwpuclnt");
- clang.arg("-lgdi32");
- clang.arg("-lmsimg32");
- clang.arg("-lmswsock");
- clang.arg("-lole32");
- clang.arg("-lopengl32");
- clang.arg("-lsecur32");
- clang.arg("-lshell32");
- clang.arg("-lsynchronization");
- clang.arg("-luser32");
- clang.arg("-lwinspool");
-
- clang.arg("-Wl,-nodefaultlib:libcmt");
- clang.arg("-D_DLL");
- clang.arg("-lmsvcrt");
- }
- #[cfg(target_os = "macos")]
- {
- clang.arg("-framework").arg("CoreServices");
- clang.arg("-framework").arg("Security");
- clang.arg("-l").arg("System");
- clang.arg("-l").arg("resolv");
- clang.arg("-l").arg("pthread");
- clang.arg("-l").arg("c");
- clang.arg("-l").arg("m");
- }
- clang.args(args);
- clang.arg("-L").arg(root.join("target").join("debug"));
- clang
- .arg("--output")
- .arg(Path::new("../build").join(format!("{out_name}{EXE_SUFFIX}")));
- if let Some(parent) = paths[0].parent() {
- clang.current_dir(parent);
- }
-
- if !clang.status().await?.success() {
- bail!("failed to compile c++ node");
- };
- Ok(())
- }
-
- async fn build_cxx_operator(
- paths: &[&Path],
- out_name: &str,
- link_args: &[&str],
- ) -> eyre::Result<()> {
- let mut object_file_paths = Vec::new();
-
- for path in paths {
- let mut compile = tokio::process::Command::new("clang++");
- compile.arg("-c").arg(path);
- compile.arg("-std=c++17");
- let object_file_path = path.with_extension("o");
- compile.arg("-o").arg(&object_file_path);
- #[cfg(unix)]
- compile.arg("-fPIC");
- if let Some(parent) = path.parent() {
- compile.current_dir(parent);
- }
- if !compile.status().await?.success() {
- bail!("failed to compile cxx operator");
- };
- object_file_paths.push(object_file_path);
- }
-
- let mut link = tokio::process::Command::new("clang++");
- link.arg("-shared").args(&object_file_paths);
- link.args(link_args);
- #[cfg(target_os = "windows")]
- {
- link.arg("-ladvapi32");
- link.arg("-luserenv");
- link.arg("-lkernel32");
- link.arg("-lws2_32");
- link.arg("-lbcrypt");
- link.arg("-lncrypt");
- link.arg("-lschannel");
- link.arg("-lntdll");
- link.arg("-liphlpapi");
-
- link.arg("-lcfgmgr32");
- link.arg("-lcredui");
- link.arg("-lcrypt32");
- link.arg("-lcryptnet");
- link.arg("-lfwpuclnt");
- link.arg("-lgdi32");
- link.arg("-lmsimg32");
- link.arg("-lmswsock");
- link.arg("-lole32");
- link.arg("-lopengl32");
- link.arg("-lsecur32");
- link.arg("-lshell32");
- link.arg("-lsynchronization");
- link.arg("-luser32");
- link.arg("-lwinspool");
-
- link.arg("-Wl,-nodefaultlib:libcmt");
- link.arg("-D_DLL");
- link.arg("-lmsvcrt");
- link.arg("-fms-runtime-lib=static");
- }
- link.arg("-o")
- .arg(Path::new("../build").join(format!("{DLL_PREFIX}{out_name}{DLL_SUFFIX}")));
- if let Some(parent) = paths[0].parent() {
- link.current_dir(parent);
- }
- if !link.status().await?.success() {
- bail!("failed to create shared library from cxx operator (c api)");
- };
-
- Ok(())
- }
-
- fn set_up_tracing() -> eyre::Result<()> {
- use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
-
- let stdout_log = tracing_subscriber::fmt::layer()
- .pretty()
- .with_filter(LevelFilter::DEBUG);
- let subscriber = tracing_subscriber::Registry::default().with(stdout_log);
- tracing::subscriber::set_global_default(subscriber)
- .context("failed to set tracing global subscriber")
- }
|