You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. use dora_tracing::set_up_tracing;
  2. use eyre::{bail, Context};
  3. use std::{
  4. env::consts::{DLL_PREFIX, DLL_SUFFIX, EXE_SUFFIX},
  5. path::Path,
  6. };
  7. #[tokio::main]
  8. async fn main() -> eyre::Result<()> {
  9. set_up_tracing("c++-dataflow-runner").wrap_err("failed to set up tracing")?;
  10. if cfg!(windows) {
  11. tracing::error!(
  12. "The c++ example does not work on Windows currently because of a linker error"
  13. );
  14. return Ok(());
  15. }
  16. let root = Path::new(env!("CARGO_MANIFEST_DIR"));
  17. let target = root.join("target");
  18. std::env::set_current_dir(root.join(file!()).parent().unwrap())
  19. .wrap_err("failed to set working dir")?;
  20. tokio::fs::create_dir_all("build").await?;
  21. let build_dir = Path::new("build");
  22. build_package("dora-node-api-cxx").await?;
  23. let node_cxxbridge = target
  24. .join("cxxbridge")
  25. .join("dora-node-api-cxx")
  26. .join("src");
  27. tokio::fs::copy(
  28. node_cxxbridge.join("lib.rs.cc"),
  29. build_dir.join("node-bridge.cc"),
  30. )
  31. .await?;
  32. tokio::fs::copy(
  33. node_cxxbridge.join("lib.rs.h"),
  34. build_dir.join("dora-node-api.h"),
  35. )
  36. .await?;
  37. tokio::fs::write(
  38. build_dir.join("operator.h"),
  39. r###"#include "../operator-rust-api/operator.h""###,
  40. )
  41. .await?;
  42. build_package("dora-operator-api-cxx").await?;
  43. let operator_cxxbridge = target
  44. .join("cxxbridge")
  45. .join("dora-operator-api-cxx")
  46. .join("src");
  47. tokio::fs::copy(
  48. operator_cxxbridge.join("lib.rs.cc"),
  49. build_dir.join("operator-bridge.cc"),
  50. )
  51. .await?;
  52. tokio::fs::copy(
  53. operator_cxxbridge.join("lib.rs.h"),
  54. build_dir.join("dora-operator-api.h"),
  55. )
  56. .await?;
  57. build_package("dora-node-api-c").await?;
  58. build_package("dora-operator-api-c").await?;
  59. build_cxx_node(
  60. root,
  61. &[
  62. &dunce::canonicalize(Path::new("node-rust-api").join("main.cc"))?,
  63. &dunce::canonicalize(build_dir.join("node-bridge.cc"))?,
  64. ],
  65. "node_rust_api",
  66. &["-l", "dora_node_api_cxx"],
  67. )
  68. .await?;
  69. build_cxx_node(
  70. root,
  71. &[&dunce::canonicalize(
  72. Path::new("node-c-api").join("main.cc"),
  73. )?],
  74. "node_c_api",
  75. &["-l", "dora_node_api_c"],
  76. )
  77. .await?;
  78. build_cxx_operator(
  79. &[
  80. &dunce::canonicalize(Path::new("operator-rust-api").join("operator.cc"))?,
  81. &dunce::canonicalize(build_dir.join("operator-bridge.cc"))?,
  82. ],
  83. "operator_rust_api",
  84. &[
  85. "-l",
  86. "dora_operator_api_cxx",
  87. "-L",
  88. root.join("target").join("debug").to_str().unwrap(),
  89. ],
  90. )
  91. .await?;
  92. build_cxx_operator(
  93. &[&dunce::canonicalize(
  94. Path::new("operator-c-api").join("operator.cc"),
  95. )?],
  96. "operator_c_api",
  97. &[
  98. "-l",
  99. "dora_operator_api_c",
  100. "-L",
  101. root.join("target").join("debug").to_str().unwrap(),
  102. ],
  103. )
  104. .await?;
  105. let dataflow = Path::new("dataflow.yml").to_owned();
  106. build_package("dora-runtime").await?;
  107. run_dataflow(&dataflow).await?;
  108. Ok(())
  109. }
  110. async fn build_package(package: &str) -> eyre::Result<()> {
  111. let cargo = std::env::var("CARGO").unwrap();
  112. let mut cmd = tokio::process::Command::new(&cargo);
  113. cmd.arg("build");
  114. cmd.arg("--package").arg(package);
  115. if !cmd.status().await?.success() {
  116. bail!("failed to build {package}");
  117. };
  118. Ok(())
  119. }
  120. async fn run_dataflow(dataflow: &Path) -> eyre::Result<()> {
  121. let cargo = std::env::var("CARGO").unwrap();
  122. let mut cmd = tokio::process::Command::new(&cargo);
  123. cmd.arg("run");
  124. cmd.arg("--package").arg("dora-cli");
  125. cmd.arg("--")
  126. .arg("daemon")
  127. .arg("--run-dataflow")
  128. .arg(dataflow);
  129. if !cmd.status().await?.success() {
  130. bail!("failed to run dataflow");
  131. };
  132. Ok(())
  133. }
  134. async fn build_cxx_node(
  135. root: &Path,
  136. paths: &[&Path],
  137. out_name: &str,
  138. args: &[&str],
  139. ) -> eyre::Result<()> {
  140. let mut clang = tokio::process::Command::new("clang++");
  141. clang.args(paths);
  142. clang.arg("-std=c++17");
  143. #[cfg(target_os = "linux")]
  144. {
  145. clang.arg("-l").arg("m");
  146. clang.arg("-l").arg("rt");
  147. clang.arg("-l").arg("dl");
  148. clang.arg("-pthread");
  149. }
  150. #[cfg(target_os = "windows")]
  151. {
  152. clang.arg("-ladvapi32");
  153. clang.arg("-luserenv");
  154. clang.arg("-lkernel32");
  155. clang.arg("-lws2_32");
  156. clang.arg("-lbcrypt");
  157. clang.arg("-lncrypt");
  158. clang.arg("-lschannel");
  159. clang.arg("-lntdll");
  160. clang.arg("-liphlpapi");
  161. clang.arg("-lcfgmgr32");
  162. clang.arg("-lcredui");
  163. clang.arg("-lcrypt32");
  164. clang.arg("-lcryptnet");
  165. clang.arg("-lfwpuclnt");
  166. clang.arg("-lgdi32");
  167. clang.arg("-lmsimg32");
  168. clang.arg("-lmswsock");
  169. clang.arg("-lole32");
  170. clang.arg("-lopengl32");
  171. clang.arg("-lsecur32");
  172. clang.arg("-lshell32");
  173. clang.arg("-lsynchronization");
  174. clang.arg("-luser32");
  175. clang.arg("-lwinspool");
  176. clang.arg("-Wl,-nodefaultlib:libcmt");
  177. clang.arg("-D_DLL");
  178. clang.arg("-lmsvcrt");
  179. }
  180. #[cfg(target_os = "macos")]
  181. {
  182. clang.arg("-framework").arg("CoreServices");
  183. clang.arg("-framework").arg("Security");
  184. clang.arg("-l").arg("System");
  185. clang.arg("-l").arg("resolv");
  186. clang.arg("-l").arg("pthread");
  187. clang.arg("-l").arg("c");
  188. clang.arg("-l").arg("m");
  189. }
  190. clang.args(args);
  191. clang.arg("-L").arg(root.join("target").join("debug"));
  192. clang
  193. .arg("--output")
  194. .arg(Path::new("../build").join(format!("{out_name}{EXE_SUFFIX}")));
  195. if let Some(parent) = paths[0].parent() {
  196. clang.current_dir(parent);
  197. }
  198. if !clang.status().await?.success() {
  199. bail!("failed to compile c++ node");
  200. };
  201. Ok(())
  202. }
  203. async fn build_cxx_operator(
  204. paths: &[&Path],
  205. out_name: &str,
  206. link_args: &[&str],
  207. ) -> eyre::Result<()> {
  208. let mut object_file_paths = Vec::new();
  209. for path in paths {
  210. let mut compile = tokio::process::Command::new("clang++");
  211. compile.arg("-c").arg(path);
  212. compile.arg("-std=c++17");
  213. let object_file_path = path.with_extension("o");
  214. compile.arg("-o").arg(&object_file_path);
  215. #[cfg(unix)]
  216. compile.arg("-fPIC");
  217. if let Some(parent) = path.parent() {
  218. compile.current_dir(parent);
  219. }
  220. if !compile.status().await?.success() {
  221. bail!("failed to compile cxx operator");
  222. };
  223. object_file_paths.push(object_file_path);
  224. }
  225. let mut link = tokio::process::Command::new("clang++");
  226. link.arg("-shared").args(&object_file_paths);
  227. link.args(link_args);
  228. #[cfg(target_os = "windows")]
  229. {
  230. link.arg("-ladvapi32");
  231. link.arg("-luserenv");
  232. link.arg("-lkernel32");
  233. link.arg("-lws2_32");
  234. link.arg("-lbcrypt");
  235. link.arg("-lncrypt");
  236. link.arg("-lschannel");
  237. link.arg("-lntdll");
  238. link.arg("-liphlpapi");
  239. link.arg("-lcfgmgr32");
  240. link.arg("-lcredui");
  241. link.arg("-lcrypt32");
  242. link.arg("-lcryptnet");
  243. link.arg("-lfwpuclnt");
  244. link.arg("-lgdi32");
  245. link.arg("-lmsimg32");
  246. link.arg("-lmswsock");
  247. link.arg("-lole32");
  248. link.arg("-lopengl32");
  249. link.arg("-lsecur32");
  250. link.arg("-lshell32");
  251. link.arg("-lsynchronization");
  252. link.arg("-luser32");
  253. link.arg("-lwinspool");
  254. link.arg("-Wl,-nodefaultlib:libcmt");
  255. link.arg("-D_DLL");
  256. link.arg("-lmsvcrt");
  257. link.arg("-fms-runtime-lib=static");
  258. }
  259. #[cfg(target_os = "macos")]
  260. {
  261. link.arg("-framework").arg("CoreServices");
  262. link.arg("-framework").arg("Security");
  263. link.arg("-l").arg("System");
  264. link.arg("-l").arg("resolv");
  265. link.arg("-l").arg("pthread");
  266. link.arg("-l").arg("c");
  267. link.arg("-l").arg("m");
  268. }
  269. link.arg("-o")
  270. .arg(Path::new("../build").join(format!("{DLL_PREFIX}{out_name}{DLL_SUFFIX}")));
  271. if let Some(parent) = paths[0].parent() {
  272. link.current_dir(parent);
  273. }
  274. if !link.status().await?.success() {
  275. bail!("failed to create shared library from cxx operator (c api)");
  276. };
  277. Ok(())
  278. }