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.

run.rs 8.3 kB

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

DORA (Dataflow-Oriented Robotic Architecture) is middleware designed to streamline and simplify the creation of AI-based robotic applications. It offers low latency, composable, and distributed datafl