use std::env;
use std::path::PathBuf;
fn main() {
let wolfssl_include = env::var("DEP_WOLFCRYPT_SYS_INCLUDE")
.expect("DEP_WOLFCRYPT_SYS_INCLUDE not set; is wolfcrypt-sys a direct dependency?");
let wolfssl_settings = env::var("DEP_WOLFCRYPT_SYS_SETTINGS_INCLUDE")
.unwrap_or_else(|_| wolfssl_include.clone());
let wolfssl_vendored = env::var("DEP_WOLFCRYPT_SYS_VENDORED")
.map(|v| v == "1")
.unwrap_or(false);
let user_settings_h = PathBuf::from(&wolfssl_settings).join("user_settings.h");
let use_user_settings = wolfssl_vendored || user_settings_h.exists();
let wolftpm_include = env::var("DEP_WOLFTPM_SRC_INCLUDE")
.expect("DEP_WOLFTPM_SRC_INCLUDE not set; is wolftpm-src a direct dependency?");
let wolftpm_lib = env::var("DEP_WOLFTPM_SRC_LIB")
.expect("DEP_WOLFTPM_SRC_LIB not set");
println!("cargo:rerun-if-changed={wolftpm_include}/wolftpm/version.h");
check_wolftpm_version(&format!("{wolftpm_include}/wolftpm/version.h"));
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let mut shim = cc::Build::new();
shim.file(manifest_dir.join("src/wolftpm_rs_shim.c"))
.include(&wolftpm_lib)
.include(&wolftpm_include)
.include(format!("{wolftpm_include}/hal"))
.include(&wolfssl_include)
.include(&wolfssl_settings);
if use_user_settings {
shim.define("WOLFSSL_USER_SETTINGS", None);
} else {
shim.define("WOLFSSL_USE_OPTIONS_H", None);
}
shim.define("WOLFTPM2_NO_WOLFCRYPT", None);
shim.compile("wolftpm_rs_shim");
println!("cargo:rustc-link-search=native={wolftpm_lib}");
println!("cargo:rustc-link-lib=static=wolftpm");
let wolfssl_vendored_str = env::var("DEP_WOLFCRYPT_SYS_VENDORED").unwrap_or_default();
if wolfssl_vendored_str == "1" {
let wolfssl_root = env::var("DEP_WOLFCRYPT_SYS_ROOT").unwrap_or_default();
if !wolfssl_root.is_empty() {
println!("cargo:rustc-link-search=native={wolfssl_root}");
}
println!("cargo:rustc-link-lib=static=wolfssl");
} else {
let lib_dirs = env::var("DEP_WOLFCRYPT_SYS_LIB_DIRS").unwrap_or_default();
for dir in lib_dirs.split(':').filter(|s| !s.is_empty()) {
println!("cargo:rustc-link-search=native={dir}");
}
let libcrypto =
env::var("DEP_WOLFCRYPT_SYS_LIBCRYPTO").unwrap_or_else(|_| "wolfssl".into());
println!("cargo:rustc-link-lib={libcrypto}");
}
let bindings = bindgen::Builder::default()
.header(manifest_dir.join("wrapper.h").to_str().unwrap())
.clang_arg(format!("-I{wolftpm_lib}"))
.clang_arg(format!("-I{wolftpm_include}"))
.clang_arg(format!("-I{wolftpm_include}/hal"))
.clang_arg(format!("-I{wolfssl_include}"))
.clang_arg(format!("-I{wolfssl_settings}"))
.clang_arg(if use_user_settings {
"-DWOLFSSL_USER_SETTINGS"
} else {
"-DWOLFSSL_USE_OPTIONS_H"
})
.clang_arg("-DWOLFTPM2_NO_WOLFCRYPT")
.allowlist_type("WOLFTPM2_.*")
.allowlist_type("wolfTPM2_.*")
.allowlist_type("TpmDevType")
.allowlist_type("TPM2B_.*")
.allowlist_type("TPMA_.*")
.allowlist_type("TPMS_.*")
.allowlist_type("TPMT_.*")
.allowlist_type("TPML_.*")
.allowlist_type("TPMU_.*")
.allowlist_function("wolfTPM2_.*")
.allowlist_function("TPM2_.*")
.allowlist_function("wolftpm_rs_.*")
.allowlist_item("TPM_.*")
.allowlist_item("TPM2_.*")
.allowlist_item("WOLFTPM_.*")
.opaque_type("wc_.*")
.opaque_type("RsaKey")
.opaque_type("ecc_key")
.opaque_type("ed25519_key")
.opaque_type("ed448_key")
.opaque_type("WC_RNG")
.opaque_type("WC_SHA.*")
.opaque_type("Hmac")
.opaque_type("WOLFSSL.*")
.opaque_type("Wc.*")
.use_core()
.layout_tests(false)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("failed to generate wolftpm bindings");
bindings
.write_to_file(out_dir.join("bindings.rs"))
.expect("failed to write bindings.rs");
}
fn check_wolftpm_version(version_h_path: &str) {
const TESTED_VERSION_HEX: u64 = 0x04000000;
let content = std::fs::read_to_string(version_h_path)
.unwrap_or_else(|e| panic!("cannot read {version_h_path}: {e}"));
let found = content
.lines()
.find_map(|line| {
let rest = line.trim().strip_prefix("#define LIBWOLFTPM_VERSION_HEX")?;
let token = rest.trim().strip_prefix("0x").or_else(|| rest.trim().strip_prefix("0X")).unwrap_or(rest.trim());
u64::from_str_radix(token, 16).ok()
})
.unwrap_or_else(|| panic!(
"LIBWOLFTPM_VERSION_HEX not found in {version_h_path}; \
cannot verify wolfTPM version compatibility"
));
if found != TESTED_VERSION_HEX {
panic!(
"wolfTPM version mismatch: {version_h_path} defines \
LIBWOLFTPM_VERSION_HEX=0x{found:08x} but this crate was tested \
against 0x{TESTED_VERSION_HEX:08x} (v4.0.0 / fbbf6fe).\n\
wolftpm_rs_shim.c accesses WOLFTPM2_CTX::cmdBuf which is not a \
stable API — review shim.c for compatibility, then update \
TESTED_VERSION_HEX in wolftpm-sys/build.rs."
);
}
}