use std::env;
use std::io::Write;
use std::path::PathBuf;
fn main() {
println!("cargo:rerun-if-env-changed=WOLFTPM_SRC");
println!("cargo:rerun-if-env-changed=WOLFSSL_INCLUDE_DIR");
println!("cargo:rerun-if-env-changed=WOLFSSL_DIR");
println!("cargo:rerun-if-env-changed=WOLFSSL_SRC");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let wolftpm_src = locate_wolftpm_src();
let (wolfssl_include, wolfssl_settings_include) = locate_wolfssl_headers();
let opts_dir = out_dir.join("wolftpm");
std::fs::create_dir_all(&opts_dir).expect("create wolftpm dir in OUT_DIR");
let opts_path = opts_dir.join("options.h");
generate_wolftpm_options(&opts_path);
let mut build = cc::Build::new();
build.include(&out_dir);
build.include(&wolftpm_src);
build.include(wolftpm_src.join("hal"));
build.include(&wolfssl_include);
if let Some(ref settings_inc) = wolfssl_settings_include {
build.include(settings_inc);
}
build.define("WOLFSSL_USER_SETTINGS", None);
build.warnings(false);
build.opt_level(2);
let src_dir = wolftpm_src.join("src");
let core_sources = [
"tpm2.c",
"tpm2_wrap.c",
"tpm2_packet.c",
"tpm2_param_enc.c",
"tpm2_util.c",
"tpm2_crypto.c",
];
for name in &core_sources {
let path = src_dir.join(name);
build.file(&path);
println!("cargo:rerun-if-changed={}", path.display());
}
let optional_sources = [
"tpm2_cryptocb.c", "tpm2_linux.c", "tpm2_swtpm.c", "tpm2_tis.c", ];
for name in &optional_sources {
let path = src_dir.join(name);
if path.exists() {
build.file(&path);
println!("cargo:rerun-if-changed={}", path.display());
}
}
build.compile("wolftpm");
println!("cargo:INCLUDE={}", wolftpm_src.display());
println!("cargo:LIB={}", out_dir.display());
}
fn generate_wolftpm_options(path: &std::path::Path) {
let mut f = std::fs::File::create(path)
.unwrap_or_else(|e| panic!("cannot create {}: {e}", path.display()));
writeln!(f, "/* Auto-generated by wolftpm-src build.rs — do not edit */").unwrap();
writeln!(f, "#ifndef WOLFTPM_OPTIONS_H").unwrap();
writeln!(f, "#define WOLFTPM_OPTIONS_H").unwrap();
writeln!(f).unwrap();
let linux_dev = env::var("CARGO_FEATURE_LINUX_DEV").is_ok();
let swtpm = env::var("CARGO_FEATURE_SWTPM").is_ok();
if linux_dev {
writeln!(f, "#define WOLFTPM_LINUX_DEV").unwrap();
}
if swtpm {
writeln!(f, "#define WOLFTPM_SWTPM").unwrap();
}
if !linux_dev && !swtpm {
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
if target_os == "linux" || target_os.is_empty() {
writeln!(f, "#define WOLFTPM_LINUX_DEV").unwrap();
}
}
writeln!(f).unwrap();
writeln!(f, "#endif /* WOLFTPM_OPTIONS_H */").unwrap();
}
fn locate_wolftpm_src() -> PathBuf {
if let Ok(val) = env::var("WOLFTPM_SRC") {
if !val.is_empty() {
let path = PathBuf::from(&val);
if path.exists() {
return path;
}
panic!("WOLFTPM_SRC={val} does not exist");
}
}
let bundled = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("wolftpm");
if bundled.join("src").exists() {
return bundled;
}
panic!(
"wolfTPM source not found.\n\
Options:\n\
1. Set WOLFTPM_SRC=/path/to/wolfTPM source directory\n\
2. Run: git submodule update --init wolftpm-src/wolftpm"
);
}
fn locate_wolfssl_headers() -> (PathBuf, Option<PathBuf>) {
if let Ok(val) = env::var("WOLFSSL_INCLUDE_DIR") {
if !val.is_empty() {
let path = PathBuf::from(&val);
if path.exists() {
return (path, None);
}
panic!("WOLFSSL_INCLUDE_DIR={val} does not exist");
}
}
if let Ok(val) = env::var("WOLFSSL_DIR") {
if !val.is_empty() {
let include = PathBuf::from(&val).join("include");
if include.exists() {
return (include, None);
}
panic!("WOLFSSL_DIR={val} exists but {}/include does not", val);
}
}
if let Ok(val) = env::var("WOLFSSL_SRC") {
if !val.is_empty() {
let path = PathBuf::from(&val);
if !path.exists() {
panic!("WOLFSSL_SRC={val} does not exist");
}
let settings_include = env::var("WOLFSSL_SETTINGS_INCLUDE")
.map(PathBuf::from)
.ok();
return (path, settings_include);
}
}
panic!(
"wolfSSL headers not found. Set WOLFSSL_INCLUDE_DIR, WOLFSSL_DIR, or WOLFSSL_SRC."
);
}