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.

build.rs 5.7 kB

10 months ago
10 months ago
10 months ago
10 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. use std::path::{Path, PathBuf};
  2. fn main() {
  3. let mut bridge_files = vec![PathBuf::from("src/lib.rs")];
  4. #[cfg(feature = "ros2-bridge")]
  5. bridge_files.push(ros2::generate());
  6. let _build = cxx_build::bridges(&bridge_files);
  7. println!("cargo:rerun-if-changed=src/lib.rs");
  8. // rename header files
  9. let src_dir = origin_dir();
  10. let target_dir = src_dir.parent().unwrap();
  11. std::fs::copy(src_dir.join("lib.rs.h"), target_dir.join("dora-node-api.h")).unwrap();
  12. std::fs::copy(
  13. src_dir.join("lib.rs.cc"),
  14. target_dir.join("dora-node-api.cc"),
  15. )
  16. .unwrap();
  17. #[cfg(feature = "ros2-bridge")]
  18. ros2::generate_ros2_message_header(bridge_files.last().unwrap());
  19. // to avoid unnecessary `mut` warning
  20. bridge_files.clear();
  21. }
  22. fn origin_dir() -> PathBuf {
  23. let default_target = std::env::var("CARGO_TARGET_DIR")
  24. .map(PathBuf::from)
  25. .unwrap_or_else(|_| {
  26. let root = Path::new(env!("CARGO_MANIFEST_DIR"))
  27. .ancestors()
  28. .nth(3)
  29. .unwrap();
  30. root.join("target")
  31. });
  32. let cross_target = default_target
  33. .join(std::env::var("TARGET").unwrap())
  34. .join("cxxbridge")
  35. .join("dora-node-api-cxx")
  36. .join("src");
  37. if cross_target.exists() {
  38. cross_target
  39. } else {
  40. default_target
  41. .join("cxxbridge")
  42. .join("dora-node-api-cxx")
  43. .join("src")
  44. }
  45. }
  46. #[cfg(feature = "ros2-bridge")]
  47. mod ros2 {
  48. use super::origin_dir;
  49. use std::{
  50. io::{BufRead, BufReader},
  51. path::{Component, Path, PathBuf},
  52. };
  53. pub fn generate() -> PathBuf {
  54. use rust_format::Formatter;
  55. let paths = ament_prefix_paths();
  56. let generated = dora_ros2_bridge_msg_gen::generate(paths.as_slice(), true);
  57. let generated_string = rust_format::PrettyPlease::default()
  58. .format_tokens(generated)
  59. .unwrap();
  60. let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
  61. let target_file = out_dir.join("ros2_bindings.rs");
  62. std::fs::write(&target_file, generated_string).unwrap();
  63. println!(
  64. "cargo:rustc-env=ROS2_BINDINGS_PATH={}",
  65. target_file.display()
  66. );
  67. target_file
  68. }
  69. fn ament_prefix_paths() -> Vec<PathBuf> {
  70. let ament_prefix_path: String = match std::env::var("AMENT_PREFIX_PATH") {
  71. Ok(path) => path,
  72. Err(std::env::VarError::NotPresent) => {
  73. println!("cargo:warning='AMENT_PREFIX_PATH not set'");
  74. String::new()
  75. }
  76. Err(std::env::VarError::NotUnicode(s)) => {
  77. panic!(
  78. "AMENT_PREFIX_PATH is not valid unicode: `{}`",
  79. s.to_string_lossy()
  80. );
  81. }
  82. };
  83. println!("cargo:rerun-if-env-changed=AMENT_PREFIX_PATH");
  84. let paths: Vec<_> = ament_prefix_path.split(':').map(PathBuf::from).collect();
  85. for path in &paths {
  86. println!("cargo:rerun-if-changed={}", path.display());
  87. }
  88. paths
  89. }
  90. pub fn generate_ros2_message_header(source_file: &Path) {
  91. use std::io::Write as _;
  92. let out_dir = source_file.parent().unwrap();
  93. let relative_path = local_relative_path(&source_file)
  94. .ancestors()
  95. .nth(2)
  96. .unwrap()
  97. .join("out");
  98. let header_path = out_dir
  99. .join("cxxbridge")
  100. .join("include")
  101. .join("dora-node-api-cxx")
  102. .join(&relative_path)
  103. .join("ros2_bindings.rs.h");
  104. let code_path = out_dir
  105. .join("cxxbridge")
  106. .join("sources")
  107. .join("dora-node-api-cxx")
  108. .join(&relative_path)
  109. .join("ros2_bindings.rs.cc");
  110. // copy message files to target directory
  111. let target_path = origin_dir().parent().unwrap().join("dora-ros2-bindings.h");
  112. std::fs::copy(&header_path, &target_path).unwrap();
  113. println!("cargo:rerun-if-changed={}", header_path.display());
  114. let node_header =
  115. std::fs::File::open(target_path.with_file_name("dora-node-api.h")).unwrap();
  116. let mut code_file = std::fs::File::open(&code_path).unwrap();
  117. println!("cargo:rerun-if-changed={}", code_path.display());
  118. let mut code_target_file =
  119. std::fs::File::create(target_path.with_file_name("dora-ros2-bindings.cc")).unwrap();
  120. // copy both the node header and the code file to prevent import errors
  121. let mut header_reader = {
  122. let mut reader = BufReader::new(node_header);
  123. // read first line to skip `#pragma once`, which is not allowed in main files
  124. let mut first_line = String::new();
  125. reader.read_line(&mut first_line).unwrap();
  126. assert_eq!(first_line.trim(), "#pragma once");
  127. reader
  128. };
  129. std::io::copy(&mut header_reader, &mut code_target_file).unwrap();
  130. std::io::copy(&mut code_file, &mut code_target_file).unwrap();
  131. code_target_file.flush().unwrap();
  132. }
  133. // copy from cxx-build source
  134. fn local_relative_path(path: &Path) -> PathBuf {
  135. let mut rel_path = PathBuf::new();
  136. for component in path.components() {
  137. match component {
  138. Component::Prefix(_) | Component::RootDir | Component::CurDir => {}
  139. Component::ParentDir => drop(rel_path.pop()), // noop if empty
  140. Component::Normal(name) => rel_path.push(name),
  141. }
  142. }
  143. rel_path
  144. }
  145. }