Now build SimpleITK into static libs and use (auto)cxx.

This commit is contained in:
Wim Pomp
2025-09-12 18:03:24 +02:00
parent 0c6a38e4fa
commit 5750fd7f99
17 changed files with 8110 additions and 1426 deletions

148
build.rs
View File

@@ -1,61 +1,99 @@
use cmake::Config;
use git2::Repository;
use std::ffi::OsStr;
use std::env;
use std::error::Error;
use std::fs;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::process::Command;
fn main() {
if std::env::var("DOCS_RS").is_err() {
let out_dir = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR is undefined"));
let mut target_dir = out_dir.clone();
while target_dir.file_name() != Some(OsStr::new("target")) {
if !target_dir.pop() {
panic!("Could not find target directory");
}
}
fn main() -> Result<(), Box<dyn Error>> {
if env::var("DOCS_RS").is_err() & !cfg!(feature = "sitk_no_build") {
let sitk_dir = PathBuf::from("SimpleITK");
let sitk_dir = if let Some(d) = target_dir.parent() {
d.join("sitk").to_path_buf()
} else {
target_dir.join("sitk")
};
if !sitk_dir.exists() {
Repository::clone("https://github.com/SimpleITK/SimpleITK.git", &sitk_dir)
.expect("unable to clone sitk");
}
let sitk_build_dir = sitk_dir.join("build");
if !sitk_build_dir.exists() {
println!("cargo::warning=Simple ITK; this will take a long time...");
Config::new(sitk_dir.join("SuperBuild"))
.out_dir(&sitk_dir)
.no_build_target(true)
.define("BUILD_TESTING", "OFF")
.define("WRAP_CSHARP", "OFF")
.define("WRAP_JAVA", "OFF")
.define("WRAP_LUA", "OFF")
.define("WRAP_R", "OFF")
.define("WRAP_RUBY", "OFF")
.define("WRAP_TCL", "OFF")
.define("WRAP_PYTHON", "OFF")
.define("WRAP_DEFAULT", "OFF")
.define("SimpleITK_USE_ELASTIX", "ON")
.build();
}
println!(
"cargo::rustc-env=CMAKE_INSTALL_PREFIX={}",
out_dir.display()
);
let path = Config::new("cpp")
.very_verbose(true)
.define("Elastix_DIR", sitk_build_dir.join("Elastix-build"))
.define("ITK_DIR", sitk_build_dir.join("ITK-build"))
.define("SimpleITK_DIR", sitk_build_dir.join("SimpleITK-build"))
.define("CMAKE_INSTALL_PREFIX", out_dir)
// use cmake to compile the SimpleITK C++ code
let dst = cmake::Config::new(sitk_dir.join("SuperBuild"))
.no_build_target(true)
.define("BUILD_EXAMPLES", "OFF")
.define("BUILD_TESTING", "OFF")
.define("WRAP_CSHARP", "OFF")
.define("WRAP_JAVA", "OFF")
.define("WRAP_LUA", "OFF")
.define("WRAP_R", "OFF")
.define("WRAP_RUBY", "OFF")
.define("WRAP_TCL", "OFF")
.define("WRAP_PYTHON", "OFF")
.define("WRAP_DEFAULT", "OFF")
.define("SimpleITK_USE_ELASTIX", "ON")
.build();
println!("cargo::rustc-link-arg=-Wl,-rpath,{}", path.display());
println!("cargo::rustc-link-search={}", path.join("build").display());
println!("cargo::rustc-link-lib=dylib=sitk_adapter");
println!("cargo::rerun-if-changed=build.rs");
println!("cargo::rerun-if-changed=cpp");
// there does not seem to be any way to tell cargo to group libraries together
// when linking, so we group all objects together in three big static libraries
let merged_lib = cmake::Config::new("merged_lib")
.out_dir(dst.join("merged_lib"))
.no_build_target(true)
.build();
let mut b = autocxx_build::Builder::new(
"src/lib.rs",
["cxx", dst.join("include/SimpleITK-3.0").to_str().unwrap()],
)
.extra_clang_args(&["-std=c++17"])
.build()?;
b.flag("-std=c++17").compile("sitk_autocxx");
cc::Build::new()
.include(dst.join("include/SimpleITK-3.0"))
.file("cxx/ffi_extra.cxx")
.compile("sitk_ffi_extra");
let cxx_file = dst.join("autocxx-build-dir/rs/autocxx-ffi-default-gen.rs");
let mut cxx = String::new();
let _ = fs::File::open(&cxx_file)?.read_to_string(&mut cxx)?;
let ra = regex::Regex::new(r"\s*(#|\s(fn|use|mod|pub|struct|enum)\s)\s*")?;
let rb = regex::Regex::new(r"\s(;)\s")?;
let pointer = regex::Regex::new(r"pub type pointer = root\s+::\s+pointer;")?;
let cpp_string = regex::Regex::new(r"pub mod simple \{")?;
let rb_tree = regex::Regex::new(
r"pub type _Rb_tree_insert_return_type = root :: std :: _Node_insert_return < _Iterator , _NodeHandle >;",
)?;
{
let mut f = fs::OpenOptions::new()
.write(true)
.truncate(true)
.open(&cxx_file)?;
write!(
f,
"#[allow(unused_imports)]\n#[allow(unsafe_op_in_unsafe_fn)]\n#[allow(clippy::missing_safety_doc)]\n"
)?;
let cxx = ra.replace_all(&cxx, "\n$1");
let cxx = rb.replace_all(&cxx, "$1\n");
let cxx = pointer.replace_all(&cxx, r"// $0");
let cxx = rb_tree.replace_all(&cxx, r"// $0");
let cxx =
cpp_string.replace_all(&cxx, "pub mod simple {\nuse crate::ffi::ToCppString;");
write!(f, "{}", cxx)?;
}
fs::copy(dst.join(&cxx_file), "src/autocxx-ffi-default-gen_unfmt.rs")?;
Command::new("rustfmt").arg(&cxx_file).status()?;
fs::copy(dst.join(&cxx_file), "src/autocxx-ffi-default-gen.rs")?;
println!("cargo:warning=merged_lib={}", merged_lib.join("build").display());
println!("cargo:rustc-link-search={}", merged_lib.join("build").display());
println!("cargo:rustc-link-lib=static=sitk_ffi_extra");
println!("cargo:rustc-link-lib=static=sitk");
println!("cargo:rustc-link-lib=static=elastix");
println!("cargo:rustc-link-lib=static=itk");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src/lib.rs");
println!("cargo:rerun-if-changed=cxx/ffi_extra.h");
println!("cargo:rerun-if-changed=cxx/ffi_extra.cxx");
} else {
let dst = PathBuf::from(env::var("OUT_DIR")?);
fs::create_dir_all(dst.join("autocxx-build-dir/rs"))?;
fs::copy(
"src/autocxx-ffi-default-gen.rs",
dst.join("autocxx-build-dir/rs/autocxx-ffi-default-gen.rs"),
)?;
}
Ok(())
}