use std::env; use std::path::PathBuf; const CALLEE_NAME: &str = "Callee"; fn main() { let callee_root = env::var("CALLEE_PATH").expect("Callee path variable must be available"); let lean_root = env::var("LEAN_ROOT").expect("Lean root must exist"); let input = format!("{lean_root}/include/lean/lean.h"); println!("cargo:rustc-link-search={callee_root}"); println!("cargo:rustc-link-search={lean_root}/lib/lean"); println!("cargo:rustc-link-lib={CALLEE_NAME}"); //println!("cargo:rustc-link-lib=Init_shared"); println!("cargo:rustc-link-lib=leanshared"); // The bindgen::Builder is the main entry point // to bindgen, and lets you build up options for // the resulting bindings. let bindings = bindgen::Builder::default() // The input header we would like to generate // bindings for. .header(&input) // Tell cargo to invalidate the built crate whenever any of the // included header files changed. .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) // The following is specific to `lean.h`: There are a lot of static // function .wrap_static_fns(true) // but some functions use `_Atomic(int)` types that bindgen cannot handle, // so they are blocklisted. The types which use `_Atomic` are treated as // opaque. .blocklist_function("lean_get_rc_mt_addr") .opaque_type("lean_thunk_object") .opaque_type("lean_task_object") // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); let extern_src_path = std::env::temp_dir().join("bindgen").join("extern.c"); let extern_obj_path = std::env::temp_dir().join("bindgen").join("extern.o"); let output_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); // Write the bindings to the $OUT_DIR/bindings.rs file. let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); bindings .write_to_file(out_path.join("lean.rs")) .expect("Couldn't write bindings!"); // This is the path to the object file. let obj_path = output_path.join("extern.o"); // This is the path to the static library file. let lib_path = output_path.join("libextern.a"); // Compile the generated wrappers into an object file. let clang_output = std::process::Command::new("clang") .arg("-O") .arg("-c") .arg("-o") .arg(extern_obj_path) .arg(extern_src_path) .arg("-include") .arg(&input) .output() .unwrap(); if !clang_output.status.success() { panic!( "Could not compile object file:\n{}", String::from_utf8_lossy(&clang_output.stderr) ); } // Turn the object file into a static library #[cfg(not(target_os = "windows"))] let lib_output = std::process::Command::new("ar") .arg("rcs") .arg(output_path.join(&lib_path)) .arg(obj_path) .output() .unwrap(); #[cfg(target_os = "windows")] let lib_output = std::process::Command::new("LIB") .arg(obj_path) .arg(format!( "/OUT:{}", out_dir_path.join("libextern.lib").display() )) .output() .unwrap(); if !lib_output.status.success() { panic!( "Could not emit library file:\n{}", String::from_utf8_lossy(&lib_output.stderr) ); } // Statically link against the generated lib println!("cargo:rustc-link-search={}", output_path.display()); println!("cargo:rustc-link-lib=static=extern"); }