use std::env; use std::path::PathBuf; 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 output_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 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"); let bindgen_dir = env::temp_dir().join("bindgen"); let extern_src_path = bindgen_dir.join("leanextern.c"); let bindings = bindgen::Builder::default() .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) .wrap_static_fns_suffix("__leanextern") .wrap_static_fns_path(&extern_src_path) // 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") .generate() .expect("Unable to generate bindings"); bindings .write_to_file(output_path.join("lean.rs")) .expect("Couldn't write bindings!"); let extern_obj_path = bindgen_dir.join("leanextern.o"); // 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) .arg("-I") .arg(format!("{lean_root}/include")) .output() .unwrap(); if !clang_output.status.success() { panic!( "Could not compile object file:\n{}", String::from_utf8_lossy(&clang_output.stderr) ); } #[cfg(not(target_os = "windows"))] let lib_output = std::process::Command::new("ar") .arg("rcs") .arg(bindgen_dir.join("libleanextern.a")) .arg(&extern_obj_path) .output().unwrap(); #[cfg(target_os = "windows")] let lib_output = std::process::Command::new("LIB") .arg(&extern_obj_path) .arg(format!( "/OUT:{}", bindgen_dir.join("libleanextern.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={}", bindgen_dir.display()); println!("cargo:rustc-link-lib=static=leanextern"); }