use std::env;
use std::io::Write;
use std::path::PathBuf;
fn main() {
println!("cargo:rerun-if-env-changed=WOLFHSM_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");
println!("cargo:rerun-if-env-changed=WOLFSSL_SETTINGS_INCLUDE");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let wolfhsm_src = locate_wolfhsm_src();
let (wolfssl_include, wolfssl_settings_include) = locate_wolfssl_headers();
let cfg_path = out_dir.join("wolfhsm_cfg.h");
generate_wolfhsm_cfg(&cfg_path);
let mut build = cc::Build::new();
build.include(&out_dir);
build.include(&wolfhsm_src);
build.include(wolfhsm_src.join("port").join("posix"));
build.include(&wolfssl_include);
if let Some(ref settings_inc) = wolfssl_settings_include {
build.include(settings_inc);
}
build.define("WOLFSSL_USER_SETTINGS", None);
build.define("WOLFHSM_CFG", None);
build.define("WOLF_CRYPTO_CB", None);
build.define("WOLFHSM_CFG_NO_WOLFCRYPT", "0");
build.warnings(false);
build.opt_level(2);
let src_dir = wolfhsm_src.join("src");
let core_sources = [
"wh_comm.c",
"wh_message_comm.c",
"wh_message_crypto.c",
"wh_message_keystore.c",
"wh_message_nvm.c",
"wh_message_counter.c",
"wh_message_auth.c",
"wh_message_she.c",
"wh_message_cert.c",
"wh_message_customcb.c",
"wh_client.c",
"wh_client_crypto.c",
"wh_client_nvm.c",
"wh_client_cryptocb.c",
"wh_client_keywrap.c",
"wh_client_auth.c",
"wh_client_cert.c",
"wh_client_she.c",
"wh_client_dma.c",
"wh_keyid.c",
"wh_lock.c",
"wh_log.c",
"wh_log_printf.c",
"wh_log_ringbuf.c",
"wh_utils.c",
"wh_auth_base.c",
"wh_crypto.c",
"wh_dma.c",
"wh_timeout.c",
"wh_transport_mem.c",
];
for name in &core_sources {
let path = src_dir.join(name);
build.file(&path);
println!("cargo:rerun-if-changed={}", path.display());
}
let posix_dir = wolfhsm_src.join("port").join("posix");
let posix_sources = [
"posix_transport_tcp.c",
"posix_transport_shm.c",
"posix_transport_uds.c", "posix_transport_tls.c",
"posix_lock.c",
"posix_timeout.c",
"posix_time.c",
];
for name in &posix_sources {
let path = posix_dir.join(name);
if path.exists() {
build.file(&path);
println!("cargo:rerun-if-changed={}", path.display());
}
}
build.compile("wolfhsm");
println!("cargo:INCLUDE={}", wolfhsm_src.display());
println!("cargo:LIB={}", out_dir.display());
}
fn generate_wolfhsm_cfg(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 wolfhsm-src build.rs — do not edit */").unwrap();
writeln!(f, "#ifndef WOLFHSM_CFG_H_").unwrap();
writeln!(f, "#define WOLFHSM_CFG_H_").unwrap();
writeln!(f).unwrap();
writeln!(f, "#include \"port/posix/posix_time.h\"").unwrap();
writeln!(f).unwrap();
writeln!(f, "#define WOLFHSM_CFG_PORT_GETTIME posixGetTime").unwrap();
writeln!(f).unwrap();
writeln!(f, "#define WOLFHSM_CFG_ENABLE_CLIENT").unwrap();
writeln!(f).unwrap();
writeln!(f, "#ifndef WOLF_CRYPTO_CB").unwrap();
writeln!(f, "#define WOLF_CRYPTO_CB").unwrap();
writeln!(f, "#endif").unwrap();
writeln!(f).unwrap();
if env::var("CARGO_FEATURE_SHE").is_ok() {
writeln!(f, "#define WOLFHSM_CFG_SHE_EXTENSION").unwrap();
writeln!(f).unwrap();
}
writeln!(f, "#endif /* WOLFHSM_CFG_H_ */").unwrap();
}
fn locate_wolfhsm_src() -> PathBuf {
if let Ok(val) = env::var("WOLFHSM_SRC")
&& !val.is_empty()
{
let path = PathBuf::from(&val);
if path.exists() {
return path;
}
panic!("WOLFHSM_SRC={val} does not exist");
}
let bundled = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("wolfhsm");
if bundled.join("src").exists() {
return bundled;
}
panic!(
"wolfHSM source not found.\n\
Options:\n\
1. Set WOLFHSM_SRC=/path/to/wolfHSM source directory\n\
2. Run: git submodule update --init wolfhsm-src/wolfhsm"
);
}
fn locate_wolfssl_headers() -> (PathBuf, Option<PathBuf>) {
if let Ok(val) = env::var("WOLFSSL_INCLUDE_DIR")
&& !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")
&& !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")
&& !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."
);
}