use std::{env, path::Path, process::Command};
#[cfg(all(not(windows), not(nobindgen)))]
fn create_bindings(include_path: &Path, home_dir: &Path) {
let hacl_includes = vec![
format!("-I{}", include_path.display()),
format!("-I{}", include_path.join("hacl").display()),
format!("-I{}", include_path.join("krml").display()),
format!("-I{}", include_path.join("vale").display()),
];
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.clang_args(hacl_includes.iter())
.allowlist_function("EverCrypt_AutoConfig2_.*")
.allowlist_function("EverCrypt_AEAD_.*")
.allowlist_function("EverCrypt_Curve25519_.*")
.allowlist_function("EverCrypt_Ed25519_.*")
.allowlist_function("EverCrypt_Hash_.*")
.allowlist_function("EverCrypt_HKDF_.*")
.allowlist_function("EverCrypt_HMAC_.*")
.allowlist_function("Hacl_P256_.*")
.allowlist_function("Hacl_RSAPSS_.*")
.allowlist_function("Hacl_SHA3_.*")
.allowlist_function("Hacl_Chacha20Poly1305_.*")
.allowlist_function("Hacl_Hash_.*")
.allowlist_function("Hacl_Streaming_.*")
.allowlist_function("Hacl_Blake2.*")
.allowlist_function("Hacl_Curve25519_.*")
.allowlist_function("Hacl_HKDF_.*")
.allowlist_function("Hacl_HMAC_.*")
.allowlist_function("Hacl_HMAC_DRBG_.*")
.allowlist_function("Hacl_Bignum64_.*")
.allowlist_function("Hacl_Ed25519_.*")
.allowlist_var("EverCrypt_Error_.*")
.allowlist_var("Spec_.*")
.allowlist_type("Spec_.*")
.allowlist_type("Hacl_Streaming_SHA2_state.*")
.allowlist_type("Hacl_Streaming_Keccak_state.*")
.allowlist_type("Hacl_HMAC_DRBG_.*")
.blocklist_type("EverCrypt_AEAD_state_s.*")
.blocklist_type("FStar_UInt128_uint128")
.blocklist_function("Hacl_Streaming_SHA2_update_last_384")
.blocklist_function("Hacl_Streaming_SHA2_update_last_512")
.blocklist_function("Hacl_Blake2b_32_blake2b_update_multi")
.blocklist_function("Hacl_Blake2b_32_blake2b_update_last")
.blocklist_function("Hacl_Blake2b_256_blake2b_update_multi")
.blocklist_function("Hacl_Blake2b_256_blake2b_update_last")
.layout_tests(false)
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let home_bindings = home_dir.join("src/bindings/bindings.rs");
bindings
.write_to_file(home_bindings)
.expect("Couldn't write bindings!");
}
#[cfg(any(windows, nobindgen))]
fn create_bindings(_: &Path, _: &Path) {}
fn build_hacl_c(path: &Path, cross_target: Option<String>) {
eprintln!(" >>> Building HACL C in {}", path.display());
let mut cmake_cmd = Command::new("cmake");
let toolchain_file = cross_target
.clone()
.map(|s| match s.as_str() {
"x86_64-apple-darwin" => vec!["-D", "CMAKE_TOOLCHAIN_FILE=config/x64-darwin.cmake"],
"aarch64-apple-darwin" => {
vec!["-D", "CMAKE_TOOLCHAIN_FILE=config/aarch64-darwin.cmake"]
}
_ => vec![],
})
.unwrap_or_default();
let mut cmake_args = cross_target
.map(|s| match s.as_str() {
"i686-unknown-linux-gnu" => vec!["-DCMAKE_C_FLAGS=-m32", "-D", "CMAKE_CXX_FLAGS=-m32"],
"i686-pc-windows-msvc" => vec!["-DCMAKE_C_FLAGS=-m32", "-D", "CMAKE_CXX_FLAGS=-m32"],
_ => vec![],
})
.unwrap_or_default();
if !toolchain_file.is_empty() {
cmake_args.extend_from_slice(&toolchain_file);
}
cmake_args.extend_from_slice(&[
"-B",
"build",
"-G",
"Ninja",
"-D",
"CMAKE_BUILD_TYPE=Release",
]);
let cmake_cmd = cmake_cmd.current_dir(path).args(&cmake_args);
eprintln!(" >>> CMAKE: {cmake_cmd:?}");
let cmake_status = cmake_cmd.status().expect("Failed to run cmake.");
if !cmake_status.success() {
panic!("Failed to run cmake.")
}
let mut ninja_cmd = Command::new("ninja");
let ninja_status = ninja_cmd
.current_dir(path)
.args(&["-f", "build.ninja", "-C", "build"])
.status()
.expect("Failed to run ninja.");
if !ninja_status.success() {
panic!("Failed to run ninja.")
}
let install_path = path.join("build").join("installed");
eprintln!(" >>> Installing HACL C into {}", install_path.display());
let mut cmake_cmd = Command::new("cmake");
let cmake_status = cmake_cmd
.current_dir(path)
.args(&[
"--install",
"build",
"--prefix",
install_path.to_str().unwrap(),
])
.status()
.expect("Failed to install C library.");
if !cmake_status.success() {
panic!("Failed to install C library.")
}
}
fn copy_hacl_to_out(out_dir: &Path) {
use fs_extra::{
dir::{copy, create_all, CopyOptions},
file,
};
let build_dir = out_dir.join("build");
create_all(&build_dir, true).unwrap();
let local_c_path = Path::new(".c");
let options = CopyOptions::new().overwrite(true);
copy(&local_c_path.join("config"), &out_dir, &options).unwrap();
copy(&local_c_path.join("src"), &out_dir, &options).unwrap();
copy(&local_c_path.join("vale"), &out_dir, &options).unwrap();
copy(&local_c_path.join("karamel"), &out_dir, &options).unwrap();
copy(&local_c_path.join("include"), &out_dir, &options).unwrap();
let options = file::CopyOptions::new().overwrite(true);
file::copy(
&local_c_path.join("config").join("default_config.cmake"),
&out_dir.join("build").join("config.cmake"),
&options,
)
.unwrap();
file::copy(
&local_c_path.join("CMakeLists.txt"),
out_dir.join("CMakeLists.txt"),
&options,
)
.unwrap();
}
fn main() {
let home_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let home_dir = Path::new(&home_dir);
let mach_build = env::var("MACH_BUILD").ok().is_some();
let target = env::var("TARGET").unwrap();
let host = env::var("HOST").unwrap();
let out_dir = env::var("OUT_DIR").unwrap();
let out_dir = Path::new(&out_dir);
eprintln!("mach_build: {}", mach_build);
let cross_target = if target != host { Some(target.clone()) } else { None };
let hacl_path = if !mach_build {
let c_out_dir = out_dir.join("c");
if !c_out_dir.join("build").join("installed").exists() {
eprintln!(" >>> Copying HACL C file");
eprintln!(" from {}", home_dir.join(".c").display());
eprintln!(" to {}", c_out_dir.display());
copy_hacl_to_out(&c_out_dir);
}
build_hacl_c(&c_out_dir, cross_target);
c_out_dir.join("build").join("installed")
} else {
home_dir
.join("..")
.join("..")
.join("build")
.join("installed")
};
let hacl_lib_path = hacl_path.join("lib");
let hacl_include_path = hacl_path.join("include");
let library_name = "hacl_static";
println!("cargo:rerun-if-changed=build.rs");
create_bindings(&hacl_include_path, home_dir);
println!("cargo:rustc-link-search=native={}", hacl_lib_path.display());
println!("cargo:lib={}", hacl_lib_path.display());
println!("cargo:rustc-link-lib=static={library_name}");
}