use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::LazyLock;
const LIBNTIRPC_REVISION: &str = "24a7d5fca4c2e3e3cc8bb94bc301d8c2a40677a8";
static OUT_DIR: LazyLock<PathBuf> = LazyLock::new(|| PathBuf::from(env::var("OUT_DIR").unwrap()));
static LIBNTIRPC_DIR: LazyLock<PathBuf> = LazyLock::new(|| OUT_DIR.join("ntirpc"));
static LIBNTIRPC_BUILD_DIR: LazyLock<PathBuf> = LazyLock::new(|| LIBNTIRPC_DIR.join("build"));
static LIBNTIRPC_INSTALL_DIR: LazyLock<PathBuf> = LazyLock::new(|| LIBNTIRPC_DIR.join("install"));
fn run<P: AsRef<Path>>(mut cmd: Command, path: P) {
let dir = OUT_DIR.join(path.as_ref());
println!("Running {:?} in {:?}", cmd, dir);
let status = cmd
.current_dir(dir)
.status()
.expect("failed to start native dependency build command");
assert!(status.success(), "native dependency build command failed");
}
fn download_and_extract() {
let mut clone = Command::new("git");
clone.args([
"clone",
"--no-checkout",
"https://github.com/nfs-ganesha/ntirpc.git",
"ntirpc",
]);
run(clone, "");
let mut checkout = Command::new("git");
checkout.args(["checkout", "--detach", LIBNTIRPC_REVISION]);
run(checkout, "ntirpc");
let mut submodules = Command::new("git");
submodules.args(["submodule", "update", "--init", "--recursive"]);
run(submodules, "ntirpc");
}
fn prepare_source() {
let src_cmake = LIBNTIRPC_DIR.join("src/CMakeLists.txt");
let patched = std::fs::read_to_string(&src_cmake)
.expect("read ntirpc src/CMakeLists.txt")
.replace("add_library(ntirpc SHARED", "add_library(ntirpc STATIC");
std::fs::write(&src_cmake, patched).expect("patch ntirpc CMakeLists.txt to STATIC");
let root_cmake = LIBNTIRPC_DIR.join("CMakeLists.txt");
let patched = std::fs::read_to_string(&root_cmake)
.expect("read ntirpc CMakeLists.txt")
.replace(
"add_subdirectory(tests)",
"# Tests disabled by libntirpc-sys",
);
std::fs::write(&root_cmake, patched).expect("disable ntirpc C tests");
}
fn configure() {
let mut cmd = Command::new("mkdir");
cmd.arg(&*LIBNTIRPC_BUILD_DIR);
run(cmd, "");
let mut cmd = Command::new("cmake");
cmd.arg("-Wno-dev"); cmd.arg("-DUSE_LTTNG=Off");
cmd.arg("-DUSE_MONITORING=Off");
cmd.arg("-DCMAKE_BUILD_TYPE=RelWithDebInfo");
cmd.arg("-DCMAKE_INSTALL_LIBDIR=lib");
cmd.arg("-DCMAKE_POSITION_INDEPENDENT_CODE=ON");
cmd.arg(format!(
"-DCMAKE_INSTALL_PREFIX={}",
LIBNTIRPC_INSTALL_DIR.display()
));
cmd.arg(&*LIBNTIRPC_DIR);
run(cmd, &*LIBNTIRPC_BUILD_DIR);
}
fn make() {
let mut cmd = Command::new("make");
cmd.arg(format!(
"-j{}",
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(2)
));
run(cmd, &*LIBNTIRPC_BUILD_DIR);
}
fn install() {
let mut cmd = Command::new("make");
cmd.arg(format!(
"-j{}",
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(2)
));
cmd.arg("install");
run(cmd, &*LIBNTIRPC_BUILD_DIR);
}
fn main() {
if !LIBNTIRPC_DIR.exists() {
download_and_extract();
}
if !LIBNTIRPC_INSTALL_DIR.exists() {
prepare_source();
configure();
}
make();
install();
println!(
"cargo:rustc-link-search=native={}/lib",
LIBNTIRPC_INSTALL_DIR.display()
);
println!("cargo:rustc-link-lib=static=ntirpc");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=dl");
println!("cargo:rustc-link-lib=gssapi_krb5");
println!("cargo:rustc-link-lib=urcu-bp");
println!(
"cargo:include={}/include/ntirpc",
LIBNTIRPC_INSTALL_DIR.display()
);
println!("cargo:include2={}", LIBNTIRPC_BUILD_DIR.display());
bindgen::Builder::default()
.header(concat!(env!("CARGO_MANIFEST_DIR"), "/src/wrapper.h"))
.clang_arg(format!(
"-I{}/include/ntirpc",
LIBNTIRPC_INSTALL_DIR.display()
))
.clang_arg(format!("-I{}", LIBNTIRPC_BUILD_DIR.display()))
.blocklist_type("rpcblist")
.blocklist_function("xdr_quadruple")
.blocklist_function("strtold")
.blocklist_type("_Float64x")
.blocklist_function("qecvt_r")
.blocklist_function("qfcvt_r")
.blocklist_function("qecvt")
.blocklist_function("qfcvt")
.blocklist_function("qgcvt")
.generate()
.expect("Unable to generate bindings")
.write_to_file(OUT_DIR.join("bindings.rs"))
.expect("Couldn't write bindings!");
}