use std::env; use std::path::{Path, PathBuf}; fn main() { let rustbuilthdr_base = PathBuf::from(env::var("OUT_DIR").unwrap()).join("rust-built-headers"); run_cbindgen(&rustbuilthdr_base); println!( "cargo:PLATFORMHEADERS={}", rustbuilthdr_base .to_str() .expect("Please use paths tha are also strings") ); let liboscore_includes = Path::new("c-src/include/"); // Err out early to get a clearer error message assert!( liboscore_includes.join("oscore/message.h").exists(), "libOSCORE headers are not avaialble at {}", liboscore_includes.display() ); assert!( rustbuilthdr_base.join("oscore_native/msg_type.h").exists(), "libOSCORE platform headers are not avaialble at {}", rustbuilthdr_base.display() ); run_bindgen(liboscore_includes, &rustbuilthdr_base); bundle_staticlib(&rustbuilthdr_base) } fn run_bindgen(liboscore_include: &Path, platform_include: &Path) { bindgen::Builder::default() // On LLVM 18 (at least 1:18.1.8-11 as shipped in Debian), stdint.h appears to be a no-op // unless a proper C standard is defined. Weird, but no harm in declaring it, and works // around / // .clang_arg("-std=c99") .clang_arg(format!("-I{}", liboscore_include.to_str().unwrap())) .clang_arg(format!("-I{}", platform_include.to_str().unwrap())) // FIXME: This is practically required for bindgen output to contain any functions when // built for wasm32-unknown-unknown -- might need a more proper solution (but this is a // good workaround from ). .clang_arg("-fvisibility=default") .use_core() // Not sure why exactly these conflict, but we don't need them .derive_copy(false) .derive_debug(false) // It's Rust code that defines them, and we're building it in the same process, so let's // avoid redefinitions .blocklist_type("oscore_msg_native_t") .blocklist_type("oscore_msgerr_native_t") .blocklist_type("oscore_crypto_aead_decryptstate_t") .blocklist_type("oscore_crypto_aead_encryptstate_t") .allowlist_function("oscore_cryptoerr_is_error") // a bit weird, this should be directly // importable (but the renaming makes it // weird) .allowlist_function("oscore_msg_protected_get_code") .allowlist_function("oscore_msg_protected_map_payload") .allowlist_function("oscore_msgerr_protected_is_error") .allowlist_function("oscore_unprotect_request") .allowlist_function("oscore_oscoreoption_parse") .allowlist_function("oscore_crypto_aead_from_number") .allowlist_function("oscore_crypto_hkdf_from_number") .allowlist_function("oscore_msg_protected_optiter_init") .allowlist_function("oscore_msg_protected_optiter_next") .allowlist_function("oscore_msg_protected_optiter_finish") .allowlist_function("oscore_context_primitive_derive") .allowlist_function("oscore_crypto_aead_get_ivlength") .allowlist_function("oscore_prepare_request") .allowlist_function("oscore_encrypt_message") .allowlist_function("oscore_msg_protected_trim_payload") .allowlist_function("oscore_msg_protected_append_option") .allowlist_function("oscore_msg_protected_set_code") .allowlist_function("oscore_release_unprotected") .allowlist_function("oscore_prepare_response") .allowlist_function("oscore_msgerr_native_is_error") .allowlist_function("oscore_msg_native_map_payload") .allowlist_function("oscore_unprotect_response") .allowlist_type("oscore_msgerr_protected_t") .allowlist_type("oscore_msg_protected_t") .allowlist_type("oscore_msg_protected_optiter_t") .allowlist_type("oscore_unprotect_request_result") .allowlist_type("oscore_context_primitive") .allowlist_type("oscore_context_primitive_immutables") .allowlist_type("oscore_") .allowlist_var("OSCORE_KEYIDCONTEXT_MAXLEN") .allowlist_var("IV_KEYID_UNUSABLE") .allowlist_var("OSCORE_KEYID_MAXLEN") .allowlist_var("PIV_BYTES") .allowlist_var("OSCORE_CRYPTO_AEAD_IV_MAXLEN") .header("oscore_all_headers.h") .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) .generate() .expect("bindgen failed") .write_to_file(PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs")) .expect("writing bindings.rs failed"); } fn run_cbindgen(rustbuilthdr_base: &Path) { let rustbuilthdr_dir = rustbuilthdr_base.join("oscore_native"); std::fs::create_dir_all(&rustbuilthdr_dir).unwrap(); let cratedir_cryptobackend; let cratedir_msgbackend; let our_dir = std::env::current_dir().unwrap(); let our_dir = our_dir .file_name() .unwrap() .to_str() .expect("No non-Unicode characters in crate names please"); let our_dir_suffix = our_dir.strip_prefix("liboscore-"); match (our_dir, our_dir_suffix) { ("liboscore", _) => { cratedir_cryptobackend = "../../rust/liboscore-cryptobackend".to_string(); cratedir_msgbackend = "../../rust/liboscore-msgbackend".to_string(); } (_, Some(suffix)) => { // FIXME: Reaching over to those places is brittle at best, but it's also the only // known path to get anything but Rust source (here: headers) across crates. cratedir_cryptobackend = format!("../liboscore-cryptobackend-{}", suffix); cratedir_msgbackend = format!("../liboscore-msgbackend-{}", suffix); } (our_dir, _) => panic!( "Can not find matching backends for own directory {:?}", our_dir ), } cbindgen::Builder::new() .with_crate(&cratedir_cryptobackend) .with_config( cbindgen::Config::from_file(format!("{cratedir_cryptobackend}/cbindgen.toml")).unwrap(), ) .generate() .expect("Failure generating cbindgen headers for the cryptobackend") .write_to_file(rustbuilthdr_dir.join("crypto_type.h")); cbindgen::Builder::new() .with_crate(&cratedir_msgbackend) .with_config( cbindgen::Config::from_file(format!("{cratedir_msgbackend}/cbindgen.toml")).unwrap(), ) .with_language(cbindgen::Language::C) .generate() .expect("Failure generating cbindgen headers for the msgbackend") .write_to_file(rustbuilthdr_dir.join("msg_type.h")); } fn bundle_staticlib(rustbuilthdr_base: &Path) { cc::Build::new() .include("c-src/include/") .include(".") .include(rustbuilthdr_base.to_str().unwrap()) .file("c-src/contextpair.c") .file("c-src/oscore_message.c") .file("c-src/protection.c") .file("c-src/context_primitive.c") .compile("liboscore_static_objects"); }