[r2r_rcl] More advanced binding generation

- Add "save-bindgen" to save generated bindings file to source
  directory.
- Cache generated bindings file to speed up bindgen process.
- Add "docs-only" feature to disable linking and bindgen on docs.rs.
This commit is contained in:
aeon 2022-11-25 02:36:24 +08:00
parent 801d09d136
commit 2286dbde57
2 changed files with 89 additions and 13 deletions

View File

@ -17,3 +17,10 @@ widestring = "1.0.2"
[build-dependencies]
bindgen = "0.63.0"
r2r_common = { path = "../r2r_common", version = "0.3.2" }
[features]
save-bindgen = []
doc-only = []
[package.metadata.docs.rs]
features = ["doc-only"]

View File

@ -1,22 +1,83 @@
use std::env;
use std::fs;
use std::fs::OpenOptions;
use std::path::Path;
use std::path::PathBuf;
fn main() {
r2r_common::print_cargo_watches();
r2r_common::print_cargo_link_search();
run_bindgen();
run_dynlink();
}
let mut builder = r2r_common::setup_bindgen_builder();
builder = builder.header("src/rcl_wrapper.h");
fn run_bindgen() {
let env_hash = r2r_common::get_env_hash();
let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let bindgen_dir = out_dir.join(env_hash);
let cached_file = bindgen_dir.join("rcl_bindings.rs");
let mark_file = bindgen_dir.join("done");
let target_file = out_dir.join("rcl_bindings.rs");
let saved_file = manifest_dir.join("bindings").join("rcl_bindings.rs");
println!("cargo:rustc-link-lib=dylib=rcl");
println!("cargo:rustc-link-lib=dylib=rcl_logging_spdlog");
println!("cargo:rustc-link-lib=dylib=rcl_yaml_param_parser");
println!("cargo:rustc-link-lib=dylib=rcutils");
println!("cargo:rustc-link-lib=dylib=rmw");
println!("cargo:rustc-link-lib=dylib=rosidl_typesupport_c");
println!("cargo:rustc-link-lib=dylib=rosidl_runtime_c");
// Use saved bindings file if "docs-only" feature is enabled.
let src_file = if cfg!(feature = "doc-only") {
&saved_file
} else {
// Generate bindings if bindings file does not
// exist. Otherwise, use cached bindings file.
if !mark_file.exists() {
eprintln!("Generate bindings file '{}'", cached_file.display());
gen_bindings(&cached_file);
touch(&mark_file);
} else {
eprintln!("Use cached bindings file '{}'", cached_file.display());
}
let bindings = builder
#[cfg(feature = "save-bindgen")]
{
if let Some(dir) = saved_file.parent() {
fs::create_dir_all(dir)
.unwrap_or_else(|_| panic!("Unable to create directory '{}'", dir.display()));
}
fs::copy(&cached_file, &saved_file).expect("File copy failed");
}
&cached_file
};
fs::copy(src_file, &target_file).unwrap_or_else(|_| {
panic!(
"Unable to copy from '{}' to '{}'",
src_file.display(),
target_file.display()
)
});
}
fn run_dynlink() {
// Run dynamic linking if (1) "docs-only" feature is disabled.
#[cfg(not(feature = "doc-only"))]
{
r2r_common::print_cargo_link_search();
println!("cargo:rustc-link-lib=dylib=rcl");
println!("cargo:rustc-link-lib=dylib=rcl_logging_spdlog");
println!("cargo:rustc-link-lib=dylib=rcl_yaml_param_parser");
println!("cargo:rustc-link-lib=dylib=rcutils");
println!("cargo:rustc-link-lib=dylib=rmw");
println!("cargo:rustc-link-lib=dylib=rosidl_typesupport_c");
println!("cargo:rustc-link-lib=dylib=rosidl_runtime_c");
}
}
fn gen_bindings(out_file: &Path) {
if let Some(dir) = out_file.parent() {
fs::create_dir_all(dir)
.unwrap_or_else(|_| panic!("Unable to create directory '{}'", dir.display()));
}
let bindings = r2r_common::setup_bindgen_builder()
.header("src/rcl_wrapper.h")
.allowlist_type("rcl_.*")
.allowlist_type("rcutils_.*")
.allowlist_type("rmw_.*")
@ -25,6 +86,7 @@ fn main() {
.allowlist_var("RCUTILS_.*")
.allowlist_var("RMW_.*")
.allowlist_var("rosidl_.*")
.allowlist_var("g_rcutils_.*")
.allowlist_function("rcl_.*")
.allowlist_function("rcutils_.*")
.allowlist_function("rmw_.*")
@ -38,8 +100,15 @@ fn main() {
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("rcl_bindings.rs"))
.write_to_file(out_file)
.expect("Couldn't write bindings!");
}
fn touch(path: &Path) {
OpenOptions::new()
.create(true)
.write(true)
.open(path)
.unwrap_or_else(|_| panic!("Unable to create file '{}'", path.display()));
}