use std::env;
const Z3_HEADER_VAR: &str = "Z3_SYS_Z3_HEADER";
fn main() {
#[cfg(feature = "static-link-z3")]
build_z3();
println!("cargo:rerun-if-changed=build.rs");
let header = if cfg!(feature = "static-link-z3") {
"z3/src/api/z3.h".to_string()
} else if let Ok(header_path) = std::env::var(Z3_HEADER_VAR) {
header_path
} else {
"wrapper.h".to_string()
};
println!("cargo:rerun-if-env-changed={}", Z3_HEADER_VAR);
println!("cargo:rerun-if-changed={}", header);
let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
for x in &[
"ast_kind",
"ast_print_mode",
"decl_kind",
"error_code",
"goal_prec",
"param_kind",
"parameter_kind",
"sort_kind",
"symbol_kind",
] {
let mut enum_bindings = bindgen::Builder::default()
.header(&header)
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate_comments(false)
.rustified_enum(format!("Z3_{}", x))
.allowlist_type(format!("Z3_{}", x));
if env::var("TARGET").unwrap() == "wasm32-unknown-emscripten" {
enum_bindings = enum_bindings.clang_arg(format!(
"--sysroot={}/upstream/emscripten/cache/sysroot",
env::var("EMSDK").expect("$EMSDK env var missing. Is emscripten installed?")
));
}
enum_bindings
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join(format!("{}.rs", x)))
.expect("Couldn't write bindings!");
}
}
#[cfg(feature = "static-link-z3")]
fn build_z3() {
let mut cfg = cmake::Config::new("z3");
cfg
.define("Z3_BUILD_LIBZ3_SHARED", "false")
.define("Z3_BUILD_EXECUTABLE", "false")
.define("Z3_BUILD_TEST_EXECUTABLES", "false");
if cfg!(target_os = "windows") {
cfg.cxxflag("-MP");
cfg.build_arg("-m");
cfg.cxxflag("-DWIN32");
cfg.cxxflag("-D_WINDOWS");
}
let dst = cfg.build();
let cxx = match std::env::var("CXXSTDLIB") {
Ok(s) if s.is_empty() => None,
Ok(s) => Some(s),
Err(_) => {
let target = std::env::var("TARGET").unwrap();
if target.contains("msvc") {
None
} else if target.contains("apple")
| target.contains("freebsd")
| target.contains("openbsd")
{
Some("c++".to_string())
} else {
Some("stdc++".to_string())
}
}
};
let mut found_lib_dir = false;
for lib_dir in &[
"lib",
"lib64",
] {
let full_lib_dir = dst.join(lib_dir);
if full_lib_dir.exists() {
if *lib_dir == "lib64" {
assert_eq!(
std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(),
"64"
);
}
println!("cargo:rustc-link-search=native={}", full_lib_dir.display());
found_lib_dir = true;
break;
}
}
assert!(
found_lib_dir,
"Should have found the lib directory for our built Z3"
);
if cfg!(target_os = "windows") {
println!("cargo:rustc-link-lib=static=libz3");
} else {
println!("cargo:rustc-link-lib=static=z3");
}
if let Some(cxx) = cxx {
println!("cargo:rustc-link-lib={}", cxx);
}
}