FIX: build iOS fixes, parse the CMake-generated options.h to extract all #define directives

This commit is contained in:
JohnE 2026-03-13 19:26:20 -07:00
parent b1873b27be
commit c9fd4542d7
1 changed files with 62 additions and 24 deletions

View File

@ -171,6 +171,32 @@ fn build_wolfssl_cmake(source_dir: &Path, _out_dir: &Path) -> (PathBuf, PathBuf)
(include_dir, lib_dir) (include_dir, lib_dir)
} }
/// Parse the CMake-generated `options.h` to extract all `#define` directives.
/// Returns a list of `-DNAME` clang args.
fn parse_options_defines(include_dir: &Path) -> Vec<String> {
let options_h = include_dir.join("wolfssl/options.h");
if !options_h.exists() {
return Vec::new();
}
let content = std::fs::read_to_string(&options_h).expect("failed to read options.h");
let mut defines = Vec::new();
for line in content.lines() {
let line = line.trim();
if !line.starts_with("#define ") {
continue;
}
let rest = &line["#define ".len()..];
let name = rest.split_whitespace().next().unwrap_or("");
// Skip the header guard macro.
if name.is_empty() || name == "WOLFSSL_OPTIONS_H" {
continue;
}
defines.push(format!("-D{}", name));
}
defines
}
/// Run bindgen over the wolfCrypt headers we actually use. /// Run bindgen over the wolfCrypt headers we actually use.
fn generate_bindings(include_dir: &Path, out_dir: &Path) { fn generate_bindings(include_dir: &Path, out_dir: &Path) {
let header = include_dir.join("wolfssl/wolfcrypt/aes.h"); let header = include_dir.join("wolfssl/wolfcrypt/aes.h");
@ -187,7 +213,17 @@ fn generate_bindings(include_dir: &Path, out_dir: &Path) {
return; return;
} }
let bindings = bindgen::Builder::default() // Parse the CMake-generated options.h so that bindgen's clang sees the
// exact same preprocessor flags as the compiled wolfSSL library. This is
// essential for correct struct layout — e.g. GCM_TABLE_4BIT adds a 512-byte
// M0 table to the Gcm struct that changes the size of Aes.
let options_defines = parse_options_defines(include_dir);
// For cross-compilation, tell bindgen's clang the target triple so that
// platform-specific types (pointer size, alignment, builtins) are correct.
let target = env::var("TARGET").unwrap_or_default();
let mut builder = bindgen::Builder::default()
// Include all wolfCrypt headers we need. // Include all wolfCrypt headers we need.
.header(include_dir.join("wolfssl/wolfcrypt/aes.h").to_str().unwrap()) .header(include_dir.join("wolfssl/wolfcrypt/aes.h").to_str().unwrap())
.header(include_dir.join("wolfssl/wolfcrypt/chacha20_poly1305.h").to_str().unwrap()) .header(include_dir.join("wolfssl/wolfcrypt/chacha20_poly1305.h").to_str().unwrap())
@ -201,31 +237,33 @@ fn generate_bindings(include_dir: &Path, out_dir: &Path) {
.header(include_dir.join("wolfssl/wolfcrypt/curve25519.h").to_str().unwrap()) .header(include_dir.join("wolfssl/wolfcrypt/curve25519.h").to_str().unwrap())
.header(include_dir.join("wolfssl/wolfcrypt/curve448.h").to_str().unwrap()) .header(include_dir.join("wolfssl/wolfcrypt/curve448.h").to_str().unwrap())
.header(include_dir.join("wolfssl/wolfcrypt/random.h").to_str().unwrap()) .header(include_dir.join("wolfssl/wolfcrypt/random.h").to_str().unwrap())
.clang_arg(format!("-I{}", include_dir.display())) .clang_arg(format!("-I{}", include_dir.display()));
// Pass all required preprocessor defines explicitly so that bindgen's
// libclang sees the same feature flags as the C build, regardless of // Pass all defines from the generated options.h. This includes critical
// whether wolfSSL's options.h is correctly resolved by clang. // struct-affecting flags like GCM_TABLE_4BIT, HAVE___UINT128_T,
// // WOLFSSL_USE_ALIGN, etc. that change the layout of Gcm, Aes, and other types.
// AES-GCM (wc_AesGcmSetKey etc. are behind #ifdef HAVE_AESGCM) for def in &options_defines {
.clang_arg("-DHAVE_AESGCM") builder = builder.clang_arg(def);
// ChaCha20 / Poly1305 / XChaCha20 }
.clang_arg("-DHAVE_CHACHA")
.clang_arg("-DHAVE_POLY1305") // Pass additional defines that are added via .cflag() in the CMake build
// (not cmake options, so they don't appear in options.h).
builder = builder
.clang_arg("-DHAVE_XCHACHA") .clang_arg("-DHAVE_XCHACHA")
// BLAKE2 is not a cmake option — enable via clang preprocessor flags
// so that the headers expose the BLAKE2b/BLAKE2s function prototypes.
.clang_arg("-DHAVE_BLAKE2") .clang_arg("-DHAVE_BLAKE2")
.clang_arg("-DHAVE_BLAKE2B") .clang_arg("-DHAVE_BLAKE2B");
// Required so sha512.h exposes SHA384 typedef + functions.
.clang_arg("-DWOLFSSL_SHA384") // Set the cross-compilation target if it differs from the host.
.clang_arg("-DWOLFSSL_SHA512") if !target.is_empty() {
// SHA3 functions (wc_InitSha3_256, etc.) // Map Rust target triples to clang-compatible triples.
.clang_arg("-DWOLFSSL_SHA3") let clang_target = match target.as_str() {
// HKDF via TLS-1.3 primitives (wc_Tls13_HKDF_Extract/Expand_Label) "aarch64-apple-ios-sim" => "arm64-apple-ios-simulator".to_string(),
.clang_arg("-DHAVE_HKDF") other => other.to_string(),
// Curve25519 / Curve448 need HAVE_CURVE25519 / HAVE_CURVE448 };
.clang_arg("-DHAVE_CURVE25519") builder = builder.clang_arg(format!("--target={}", clang_target));
.clang_arg("-DHAVE_CURVE448") }
let bindings = builder
// Only generate bindings for the types/functions we use. // Only generate bindings for the types/functions we use.
.allowlist_function("wc_Aes.*") .allowlist_function("wc_Aes.*")
.allowlist_function("wc_AesGcm.*") .allowlist_function("wc_AesGcm.*")