cargo / aws-lc-sys / audit
cargo : aws-lc-sys @ 0.41.0
PE Patrick Elsen signed 2026-05-28 published 2026-05-28

builder/main.rs

1,471 lines · rust

// Copyright (c) 2022, Google Inc.// SPDX-License-Identifier: ISC// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.// SPDX-License-Identifier: Apache-2.0 OR ISC// Needed until MSRV >= 1.70#![allow(clippy::unnecessary_map_or)]#![allow(clippy::ref_option)]// Clippy can only be run on nightly toolchain#![cfg_attr(clippy, feature(custom_inner_attributes))]#![cfg_attr(clippy, clippy::msrv = "1.77")]use std::ffi::{OsStr, OsString};use std::fmt::Debug;use std::path::{Path, PathBuf};use std::process::Command;use std::sync::OnceLock;use std::{env, fmt};use cc_builder::CcBuilder;use cmake_builder::CmakeBuilder;// These should generally match those found in aws-lc/include/openssl/opensslconf.hconst OSSL_CONF_DEFINES: &[&str] = &[    "OPENSSL_NO_ASYNC",    "OPENSSL_NO_BF",    "OPENSSL_NO_BLAKE2",    "OPENSSL_NO_BUF_FREELISTS",    "OPENSSL_NO_CAMELLIA",    "OPENSSL_NO_CAPIENG",    "OPENSSL_NO_CAST",    "OPENSSL_NO_CMS",    "OPENSSL_NO_COMP",    "OPENSSL_NO_CRYPTO_MDEBUG",    "OPENSSL_NO_CT",    "OPENSSL_NO_DANE",    "OPENSSL_NO_DEPRECATED",    "OPENSSL_NO_DGRAM",    "OPENSSL_NO_DYNAMIC_ENGINE",    "OPENSSL_NO_EC_NISTP_64_GCC_128",    "OPENSSL_NO_EC2M",    "OPENSSL_NO_EGD",    "OPENSSL_NO_ENGINE",    "OPENSSL_NO_GMP",    "OPENSSL_NO_GOST",    "OPENSSL_NO_HEARTBEATS",    "OPENSSL_NO_HW",    "OPENSSL_NO_IDEA",    "OPENSSL_NO_JPAKE",    "OPENSSL_NO_KRB5",    "OPENSSL_NO_MD2",    "OPENSSL_NO_MDC2",    "OPENSSL_NO_OCB",    "OPENSSL_NO_RC2",    "OPENSSL_NO_RC5",    "OPENSSL_NO_RFC3779",    "OPENSSL_NO_RIPEMD",    "OPENSSL_NO_RMD160",    "OPENSSL_NO_SCTP",    "OPENSSL_NO_SEED",    "OPENSSL_NO_SM2",    "OPENSSL_NO_SM3",    "OPENSSL_NO_SM4",    "OPENSSL_NO_SRP",    "OPENSSL_NO_SSL_TRACE",    "OPENSSL_NO_SSL2",    "OPENSSL_NO_SSL3",    "OPENSSL_NO_SSL3_METHOD",    "OPENSSL_NO_STATIC_ENGINE",    "OPENSSL_NO_STORE",    "OPENSSL_NO_TS",    "OPENSSL_NO_WHIRLPOOL",];mod cc_builder;mod cmake_builder;mod nasm_builder;#[cfg(any(feature = "bindgen", feature = "fips"))]mod sys_bindgen;pub(crate) struct EnvGuard {    key: String,    original_value: Option<String>,}impl EnvGuard {    fn new<T: AsRef<OsStr>>(key: &str, new_value: T) -> Self {        let original_value = env::var(key).ok();        env::set_var(key, new_value);        Self {            key: key.to_string(),            original_value,        }    }}impl Drop for EnvGuard {    fn drop(&mut self) {        if let Some(ref value) = self.original_value {            env::set_var(&self.key, value);        } else {            env::remove_var(&self.key);        }    }}fn is_fips_build() -> bool {    is_fips_crate() || cfg!(feature = "fips")}fn is_fips_crate() -> bool {    crate_name().contains("fips")}fn is_all_bindings() -> bool {    is_fips_crate() || env::var("CARGO_FEATURE_ALL_BINDINGS").is_ok()}fn is_prebuilt_nasm() -> bool {    !is_fips_build() && env::var("CARGO_FEATURE_PREBUILT_NASM").is_ok()}fn is_disable_prebuilt_nasm() -> bool {    is_fips_build() || env::var("CARGO_FEATURE_DISABLE_PREBUILT_NASM").is_ok()}pub(crate) fn get_aws_lc_include_path(manifest_dir: &Path) -> PathBuf {    manifest_dir.join("aws-lc").join("include")}pub(crate) fn get_rust_include_path(manifest_dir: &Path) -> PathBuf {    manifest_dir.join("include")}pub(crate) fn get_generated_include_path(manifest_dir: &Path) -> PathBuf {    manifest_dir.join("generated-include")}#[allow(unknown_lints)]#[allow(static_mut_refs)]pub(crate) fn get_env_includes_path() -> Option<Vec<PathBuf>> {    unsafe { SYS_INCLUDES.clone() }}#[allow(dead_code)]#[derive(Clone, Copy, PartialEq, Eq)]enum OutputLib {    Crypto,    Ssl,}#[allow(dead_code)]#[derive(Clone, Copy, PartialEq, Eq)]enum OutputLibType {    Static,    Dynamic,}fn cargo_env<N: AsRef<str>>(name: N) -> String {    let name = name.as_ref();    env::var(name).unwrap_or_else(|_| panic!("missing env var {name:?}"))}fn env_name_for_target<K: AsRef<OsStr>>(env_var: K) -> String {    let target = target().to_lowercase();    let target = target.replace('-', "_");    format!("{}_{target}", env_var.as_ref().to_str().unwrap())}// "CFLAGS" =>// "SYS_CFLAGS_aarch64_unknown_linux_gnu" OR "SYS_CFLAGS"//    OR "CFLAGS_aarch64_unknown_linux_gnu" OR "CFLAGS"fn optional_env_optional_crate_target<N: AsRef<str>>(name: N) -> Option<String> {    let name = name.as_ref();    optional_env_crate_target(name).or(optional_env_target(name))}// "EFFECTIVE_TARGET" => "SYS_EFFECTIVE_TARGET_aarch64_unknown_linux_gnu" + "SYS_EFFECTIVE_TARGET"fn optional_env_crate_target<N: AsRef<str>>(name: N) -> Option<String> {    let name = name.as_ref();    let crate_name = crate_name().to_uppercase().replace('-', "_");    let name_for_crate = format!("{crate_name}_{name}");    let name_for_crate_target = env_name_for_target(&name_for_crate);    optional_env(name_for_crate_target).or(optional_env(name_for_crate))}fn optional_env_target<N: AsRef<str>>(name: N) -> Option<String> {    let name_for_target = env_name_for_target(name.as_ref());    optional_env(name_for_target).or(optional_env(name))}fn optional_env<N: AsRef<str>>(name: N) -> Option<String> {    let name = name.as_ref();    println!("cargo:rerun-if-env-changed={name}");    if let Ok(value) = env::var(name) {        emit_warning(format!("Environment Variable found '{name}': '{value}'"));        return Some(value);    }    None}fn set_env_for_target<K, V>(env_var: K, value: V)where    K: AsRef<OsStr>,    V: AsRef<OsStr>,{    let env_var = env_name_for_target(env_var);    #[allow(unused_unsafe)]    unsafe {        env::set_var(&env_var, &value);    }    emit_warning(format!(        "Setting {env_var}: {}",        value.as_ref().to_str().unwrap()    ));}fn set_env<K, V>(env_var: K, value: V)where    K: AsRef<OsStr>,    V: AsRef<OsStr>,{    #[allow(unused_unsafe)]    unsafe {        env::set_var(&env_var, &value);    }    emit_warning(format!(        "Setting {}: {}",        env_var.as_ref().to_str().unwrap(),        value.as_ref().to_str().unwrap()    ));}fn env_var_to_bool(name: &str) -> Option<bool> {    if let Some(value) = optional_env(name) {        return parse_to_bool(&value);    }    None}fn env_crate_var_to_bool(name: &str) -> Option<bool> {    if let Some(value) = optional_env_crate_target(name) {        return parse_to_bool(&value);    }    None}fn parse_to_bool(env_var_value: &str) -> Option<bool> {    let env_var_value = env_var_value.to_lowercase();    if env_var_value.starts_with('0')        || env_var_value.starts_with('n')        || env_var_value.starts_with("off")        || env_var_value.starts_with('f')    {        emit_warning(format!("Value: {env_var_value} is false."));        return Some(false);    }    if env_var_value.starts_with(|c: char| c.is_ascii_digit())        || env_var_value.starts_with('y')        || env_var_value.starts_with("on")        || env_var_value.starts_with('t')    {        emit_warning(format!("Value: {env_var_value} is true."));        return Some(true);    }    None}impl Default for OutputLibType {    fn default() -> Self {        if let Some(stc_lib) = env_crate_var_to_bool("STATIC") {            if stc_lib {                OutputLibType::Static            } else {                OutputLibType::Dynamic            }        } else if !is_fips_build()            || (is_fips_build()                && (target_os() == "linux" || target_os().ends_with("bsd"))                && (target_arch() == "x86_64" || target_arch() == "aarch64"))        {            OutputLibType::Static        } else {            OutputLibType::Dynamic        }    }}impl OutputLibType {    fn rust_lib_type(&self) -> &str {        match self {            OutputLibType::Static => "static",            OutputLibType::Dynamic => "dylib",        }    }}impl OutputLib {    fn libname(self, prefix: &Option<String>) -> String {        let name = match self {            OutputLib::Crypto => "crypto",            OutputLib::Ssl => "ssl",        };        if let Some(prefix) = prefix {            format!("{prefix}_{name}")        } else {            name.to_string()        }    }}const VERSION: &str = env!("CARGO_PKG_VERSION");fn prefix_string() -> String {    format!(        "aws_lc{}_{}",        if is_fips_crate() { "_fips" } else { "" },        VERSION.to_string().replace('.', "_")    )}fn target_has_prefixed_symbols() -> bool {    target_vendor() == "apple" || (target_arch() == "x86" && target_os() == "windows")}fn is_cranelift_backend() -> bool {    // CARGO_ENCODED_RUSTFLAGS contains flags separated by 0x1f (ASCII Unit Separator)    if let Some(rustflags) = optional_env("CARGO_ENCODED_RUSTFLAGS") {        for flag in rustflags.split('\x1f') {            if flag.contains("codegen-backend") && flag.contains("cranelift") {                return true;            }        }    }    false}fn target_chokes_on_u1() -> bool {    target_arch() == "mips" || target_arch() == "mips64" || is_cranelift_backend()}#[cfg(any(feature = "bindgen", feature = "fips"))]fn target_platform_prefix(name: &str) -> String {    if is_all_bindings() {        format!("{}_{}", effective_target().replace('-', "_"), name)    } else if target_has_prefixed_symbols() {        format!("universal_prefixed_{}", name.replace('-', "_"))    } else {        format!("universal_{}", name.replace('-', "_"))    }}pub(crate) struct TestCommandResult {    #[allow(dead_code)]    stderr: Box<str>,    #[allow(dead_code)]    stdout: Box<str>,    executed: bool,    status: bool,}const MAX_CMD_OUTPUT_SIZE: usize = 1 << 15;fn execute_command(executable: &OsStr, args: &[&OsStr]) -> TestCommandResult {    if let Ok(mut result) = Command::new(executable).args(args).output() {        result.stderr.truncate(MAX_CMD_OUTPUT_SIZE);        let stderr = String::from_utf8(result.stderr)            .unwrap_or_default()            .into_boxed_str();        result.stdout.truncate(MAX_CMD_OUTPUT_SIZE);        let stdout = String::from_utf8(result.stdout)            .unwrap_or_default()            .into_boxed_str();        return TestCommandResult {            stderr,            stdout,            executed: true,            status: result.status.success(),        };    }    TestCommandResult {        stderr: String::new().into_boxed_str(),        stdout: String::new().into_boxed_str(),        executed: false,        status: false,    }}#[cfg(any(feature = "bindgen", feature = "fips"))]fn generate_bindings(manifest_dir: &Path, prefix: &Option<String>, bindings_path: &PathBuf) {    let options = BindingOptions {        build_prefix: prefix.clone(),        include_ssl: cfg!(feature = "ssl"),        disable_prelude: true,    };    let bindings = sys_bindgen::generate_bindings(manifest_dir, &options);    bindings        .write(Box::new(std::fs::File::create(bindings_path).unwrap()))        .expect("written bindings");}#[cfg(any(feature = "bindgen", feature = "fips"))]fn generate_src_bindings(manifest_dir: &Path, prefix: &Option<String>, src_bindings_path: &Path) {    sys_bindgen::generate_bindings(        manifest_dir,        &BindingOptions {            build_prefix: prefix.clone(),            include_ssl: false,            ..Default::default()        },    )    .write_to_file(src_bindings_path)    .expect("write bindings");}fn emit_rustc_cfg(cfg: &str) {    let cfg = cfg.replace('-', "_");    emit_warning(format!("Emitting configuration: cargo:rustc-cfg={cfg}"));    println!("cargo:rustc-cfg={cfg}");}fn emit_warning<T: AsRef<str>>(message: T) {    println!("cargo:warning={}", message.as_ref());}#[allow(dead_code)]fn target_family() -> String {    cargo_env("CARGO_CFG_TARGET_FAMILY")}fn target_os() -> String {    cargo_env("CARGO_CFG_TARGET_OS")}fn target_arch() -> String {    cargo_env("CARGO_CFG_TARGET_ARCH")}#[allow(unused)]fn target_env() -> String {    cargo_env("CARGO_CFG_TARGET_ENV")}#[allow(unused)]fn target_vendor() -> String {    cargo_env("CARGO_CFG_TARGET_VENDOR")}fn target() -> String {    cargo_env("TARGET")}fn crate_name() -> String {    cargo_env("CARGO_PKG_NAME")}fn effective_target() -> String {    #[allow(unknown_lints)]    #[allow(static_mut_refs)]    unsafe {        if !SYS_EFFECTIVE_TARGET.is_empty() {            return SYS_EFFECTIVE_TARGET.clone();        }    }    let target = target();    match target.as_str() {        "x86_64-alpine-linux-musl" => "x86_64-unknown-linux-musl".to_string(),        "aarch64-alpine-linux-musl" => "aarch64-unknown-linux-musl".to_string(),        _ => target,    }}#[allow(unused)]fn target_underscored() -> String {    effective_target().replace('-', "_")}fn out_dir() -> PathBuf {    let out = PathBuf::from(cargo_env("OUT_DIR"));    #[cfg(windows)]    let out = to_short_path(&out);    out}/// On Windows, convert a path to its 8.3 short form to avoid MAX_PATH (260 char) limits/// when cl.exe is invoked with deeply nested source trees (e.g. Bazel runfiles).#[cfg(windows)]fn to_short_path(path: &Path) -> PathBuf {    use std::os::windows::ffi::{OsStrExt, OsStringExt};    extern "system" {        fn GetShortPathNameW(            lpszLongPath: *const u16,            lpszShortPath: *mut u16,            cchBuffer: u32,        ) -> u32;    }    let wide: Vec<u16> = path        .as_os_str()        .encode_wide()        .chain(std::iter::once(0))        .collect();    let len = unsafe { GetShortPathNameW(wide.as_ptr(), std::ptr::null_mut(), 0) };    if len == 0 {        return path.to_path_buf();    }    let mut buf = vec![0u16; len as usize];    let result = unsafe { GetShortPathNameW(wide.as_ptr(), buf.as_mut_ptr(), len) };    if result == 0 {        return path.to_path_buf();    }    buf.truncate(result as usize);    let short_path = PathBuf::from(std::ffi::OsString::from_wide(&buf));    const MAX_PATH: usize = 260;    let original_len = wide.len() - 1;    if original_len >= MAX_PATH && (result as usize) >= MAX_PATH {        emit_warning(format!(            "Path length ({}) exceeds MAX_PATH ({}) and 8.3 short name conversion was ineffective. \             8.3 short names may be disabled on this volume. \             See: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/fsutil-8dot3name",            original_len, MAX_PATH,        ));    }    short_path}fn current_dir() -> PathBuf {    std::env::current_dir().unwrap()}fn get_builder(prefix: &Option<String>, manifest_dir: &Path, out_dir: &Path) -> Box<dyn Builder> {    let cmake_builder_builder = || {        Box::new(CmakeBuilder::new(            manifest_dir.to_path_buf(),            out_dir.to_path_buf(),            prefix.clone(),            OutputLibType::default(),        ))    };    if is_fips_build() {        return cmake_builder_builder();    }    let cc_builder_builder = || {        Box::new(CcBuilder::new(            manifest_dir.to_path_buf(),            out_dir.to_path_buf(),            prefix.clone(),            OutputLibType::default(),        ))    };    if let Some(val) = is_cmake_builder() {        let builder: Box<dyn Builder> = if val {            cmake_builder_builder()        } else {            cc_builder_builder()        };        builder.check_dependencies().unwrap();        return builder;    } else if is_no_asm() || sanitizer().is_some() {        let builder = cmake_builder_builder();        builder.check_dependencies().unwrap();        return builder;    } else if !is_bindgen_required() {        let cc_builder = cc_builder_builder();        if cc_builder.check_dependencies().is_ok() {            return cc_builder;        }    }    let cmake_builder = cmake_builder_builder();    cmake_builder.check_dependencies().unwrap();    cmake_builder}trait Builder {    fn check_dependencies(&self) -> Result<(), String>;    fn build(&self) -> Result<(), String>;    fn name(&self) -> &str;}#[derive(Clone, Copy, Debug, PartialEq, Eq)]pub(crate) enum CStdRequested {    C99,    C11,    None,}impl CStdRequested {    fn from_env() -> Self {        if let Some(val) = optional_env_crate_target("C_STD") {            let cstd = match val.as_str() {                "99" => CStdRequested::C99,                "11" => CStdRequested::C11,                _ => CStdRequested::None,            };            emit_warning(format!("SYS_C_STD environment variable set: {cstd:?}"));            return cstd;        }        CStdRequested::None    }}static mut PREGENERATED: bool = false;static mut SYS_NO_PREFIX: bool = false;static mut SYS_PREGENERATING_BINDINGS: bool = false;static mut SYS_EXTERNAL_BINDGEN: Option<bool> = None;static mut SYS_NO_ASM: bool = false;static mut SYS_PREBUILT_NASM: Option<bool> = None;static mut SYS_CMAKE_BUILDER: Option<bool> = None;static mut SYS_NO_PREGENERATED_SRC: bool = false;static mut SYS_EFFECTIVE_TARGET: String = String::new();static mut SYS_NO_JITTER_ENTROPY: Option<bool> = None;static mut SYS_NO_U1_BINDINGS: Option<bool> = None;static mut SYS_INCLUDES: Option<Vec<PathBuf>> = None;static mut SYS_SANITIZER: Option<String> = None;static mut SYS_C_STD: CStdRequested = CStdRequested::None;fn initialize() {    unsafe {        SYS_NO_PREFIX = env_crate_var_to_bool("NO_PREFIX").unwrap_or(false);        SYS_PREGENERATING_BINDINGS =            env_crate_var_to_bool("PREGENERATING_BINDINGS").unwrap_or(false);        SYS_EXTERNAL_BINDGEN = env_crate_var_to_bool("EXTERNAL_BINDGEN");        SYS_NO_ASM = env_crate_var_to_bool("NO_ASM").unwrap_or(false);        SYS_PREBUILT_NASM = env_crate_var_to_bool("PREBUILT_NASM");        SYS_C_STD = CStdRequested::from_env();        SYS_CMAKE_BUILDER = env_crate_var_to_bool("CMAKE_BUILDER");        SYS_NO_PREGENERATED_SRC = env_crate_var_to_bool("NO_PREGENERATED_SRC").unwrap_or(false);        SYS_EFFECTIVE_TARGET = optional_env_crate_target("EFFECTIVE_TARGET").unwrap_or_default();        SYS_NO_JITTER_ENTROPY = env_crate_var_to_bool("NO_JITTER_ENTROPY");        SYS_NO_U1_BINDINGS = env_crate_var_to_bool("NO_U1_BINDINGS");        SYS_INCLUDES =            optional_env_crate_target("INCLUDES").map(|v| std::env::split_paths(&v).collect());        SYS_SANITIZER = optional_env_crate_target("SANITIZER").map(|v| v.to_lowercase());    }    assert!(        !is_fips_crate() || is_fips_build(),        "aws-lc-fips-sys requires 'fips' feature to be enabled.",    );    if !is_external_bindgen_requested().unwrap_or(false)        && (is_pregenerating_bindings() || !has_bindgen_feature())        && !cfg!(feature = "ssl")    {        if is_all_bindings() {            assert!(                use_no_u1_bindings() != Some(true),                "Bindgen currently cannot generate prefixed bindings w/o the \\x01 prefix.",            );            let target = effective_target();            let supported_platform = match (is_fips_crate(), target.as_str()) {                (                    _,                    "aarch64-apple-darwin"                    | "aarch64-unknown-linux-gnu"                    | "aarch64-unknown-linux-musl"                    | "x86_64-apple-darwin"                    | "x86_64-unknown-linux-gnu"                    | "x86_64-unknown-linux-musl",                )                | (                    false,                    "aarch64-linux-android"                    | "aarch64-pc-windows-msvc"                    | "i686-pc-windows-msvc"                    | "i686-unknown-linux-gnu"                    | "riscv64gc-unknown-linux-gnu"                    | "x86_64-pc-windows-gnu"                    | "x86_64-pc-windows-msvc",                ) => Some(target),                _ => None,            };            if let Some(platform) = supported_platform {                emit_rustc_cfg(platform.as_str());                unsafe {                    PREGENERATED = true;                }            }        } else if !is_fips_crate() {            if use_no_u1_bindings() == Some(true)                || (target_chokes_on_u1() && use_no_u1_bindings().is_none())            {                if is_cranelift_backend() {                    emit_warning(                        "Cranelift codegen backend detected. Using universal_no_u1 bindings.",                    );                }                if target_has_prefixed_symbols() {                    emit_rustc_cfg("universal-no-u1-prefixed");                } else {                    emit_rustc_cfg("universal-no-u1");                }            } else if target_has_prefixed_symbols() {                emit_rustc_cfg("universal-prefixed");            } else {                emit_rustc_cfg("universal");            }            unsafe {                PREGENERATED = true;            }        }    }}fn is_bindgen_required() -> bool {    is_no_prefix()        || is_pregenerating_bindings()        || is_external_bindgen_requested().unwrap_or(false)        || has_bindgen_feature()        || !has_pregenerated()}#[cfg(any(feature = "bindgen", feature = "fips"))]fn internal_bindgen_supported() -> bool {    let cv = bindgen::clang_version();    emit_warning(format!("Clang version: {}", cv.full));    true}fn is_no_prefix() -> bool {    unsafe { SYS_NO_PREFIX }}fn is_pregenerating_bindings() -> bool {    unsafe { SYS_PREGENERATING_BINDINGS }}fn is_external_bindgen_requested() -> Option<bool> {    unsafe { SYS_EXTERNAL_BINDGEN }}fn is_no_asm() -> bool {    unsafe { SYS_NO_ASM }}#[allow(static_mut_refs)]fn sanitizer() -> Option<String> {    unsafe { SYS_SANITIZER.clone() }}fn is_cmake_builder() -> Option<bool> {    if is_no_pregenerated_src() {        Some(true)    } else {        unsafe { SYS_CMAKE_BUILDER }    }}fn is_no_pregenerated_src() -> bool {    unsafe { SYS_NO_PREGENERATED_SRC }}fn disable_jitter_entropy() -> Option<bool> {    unsafe { SYS_NO_JITTER_ENTROPY }}/// Returns true if jitter entropy should be built. This is false when the user/// explicitly set `AWS_LC_SYS_NO_JITTER_ENTROPY=1`, or when auto-detection/// determined that required headers are unavailable.fn should_build_jitter_entropy() -> bool {    static AVAILABLE: OnceLock<bool> = OnceLock::new();    // If the user explicitly set the env var, respect it unconditionally.    if let Some(val) = disable_jitter_entropy() {        return !val;    }    *AVAILABLE.get_or_init(|| {        // The current FIPS branch does not include jitter entropy.        if is_fips_build() {            return true;        }        // Only Apple targets need the CoreServices header.        if target_vendor() != "apple" {            return true;        }        probe_apple_core_services()    })}/// Probes whether `CoreServices/CoreServices.h` is available for the current/// target toolchain. On Apple targets, jitterentropy requires this header which/// is only present when the macOS SDK is installed. When cross-compiling to/// Apple targets from non-macOS hosts (e.g., Linux → macOS via cargo-zigbuild),/// this header is typically missing.fn probe_apple_core_services() -> bool {    let probe_dir = out_dir().join("out-apple_core_services_check");    let src_dir = probe_dir.join("src");    let _ = std::fs::create_dir_all(&src_dir);    let source_file = src_dir.join("apple_core_services_check.c");    if std::fs::write(&source_file, "#include <CoreServices/CoreServices.h>\n").is_err() {        emit_warning("Failed to write CoreServices probe file; assuming available.");        return true;    }    let mut cc_build = cc::Build::default();    cc_build.file(&source_file).out_dir(&probe_dir);    let available = cc_build.try_compile_intermediates().is_ok();    let _ = std::fs::remove_dir_all(&probe_dir);    if !available {        emit_warning(            "CoreServices/CoreServices.h not available; \             automatically disabling CPU jitter entropy.",        );    }    available}fn use_no_u1_bindings() -> Option<bool> {    unsafe { SYS_NO_U1_BINDINGS }}fn get_crate_cc() -> Option<String> {    optional_env_optional_crate_target("TARGET_CC").or(optional_env_optional_crate_target("CC"))}fn get_crate_cxx() -> Option<String> {    optional_env_optional_crate_target("TARGET_CXX").or(optional_env_optional_crate_target("CXX"))}fn get_crate_cflags() -> Option<String> {    optional_env_optional_crate_target("TARGET_CFLAGS")        .or(optional_env_optional_crate_target("CFLAGS"))}fn use_prebuilt_nasm() -> bool {    target_os() == "windows"        && target_arch() == "x86_64"        && !is_no_asm()        && !test_nasm_command() // NASM not found in environment        && Some(false) != allow_prebuilt_nasm() // not prevented by environment        && !is_disable_prebuilt_nasm() // not prevented by feature        // permitted by environment or by feature        && (Some(true) == allow_prebuilt_nasm() || is_prebuilt_nasm())}fn allow_prebuilt_nasm() -> Option<bool> {    unsafe { SYS_PREBUILT_NASM }}fn requested_c_std() -> CStdRequested {    unsafe { SYS_C_STD }}fn has_bindgen_feature() -> bool {    cfg!(feature = "bindgen")}fn has_pregenerated() -> bool {    unsafe { PREGENERATED }}fn test_nasm_command() -> bool {    let status = execute_command("nasm".as_ref(), &["-version".as_ref()]).status;    if !status {        emit_warning("NASM command not found or failed to execute.");    }    status}fn find_clang_cl() -> Option<OsString> {    static CACHE: OnceLock<Option<OsString>> = OnceLock::new();    CACHE        .get_or_init(|| {            // Check if clang-cl is directly available (e.g., in PATH)            if execute_command("clang-cl".as_ref(), &["--version".as_ref()]).status {                return Some("clang-cl".into());            }            // Try to find clang-cl in a Visual Studio installation            find_clang_cl_in_vs()        })        .clone()}fn find_clang_cl_in_vs() -> Option<OsString> {    // Use the cc crate's VS discovery (which calls vswhere internally) to    // locate the VS installation, then look for clang-cl relative to it.    let tool = cc::windows_registry::find_tool(&target(), "cl.exe")?;    let cl_path = tool.path().to_path_buf();    // cl.exe lives deep inside the VS installation:    //   <VS>/VC/Tools/MSVC/<ver>/bin/<host>/<target>/cl.exe    // clang-cl lives at:    //   <VS>/VC/Tools/Llvm/<arch>/bin/clang-cl.exe    // Walk up from cl.exe until we find the VS root.    for ancestor in cl_path.ancestors() {        let vc_llvm = ancestor.join("VC").join("Tools").join("Llvm");        if vc_llvm.exists() {            for arch_dir in &["ARM64", "x64"] {                let clang_cl = vc_llvm.join(arch_dir).join("bin").join("clang-cl.exe");                if clang_cl.exists()                    && execute_command(clang_cl.as_os_str(), &["--version".as_ref()]).status                {                    emit_warning(format!("Found clang-cl at: {}", clang_cl.display()));                    return Some(clang_cl.into_os_string());                }            }            break;        }    }    None}fn test_clang_cl_command() -> bool {    find_clang_cl().is_some()}fn prepare_cargo_cfg() {    if cfg!(clippy) {        println!("cargo:rustc-check-cfg=cfg(use_bindgen_pregenerated)");        println!("cargo:rustc-check-cfg=cfg(aarch64_linux_android)");        println!("cargo:rustc-check-cfg=cfg(aarch64_apple_darwin)");        println!("cargo:rustc-check-cfg=cfg(aarch64_pc_windows_msvc)");        println!("cargo:rustc-check-cfg=cfg(aarch64_unknown_linux_gnu)");        println!("cargo:rustc-check-cfg=cfg(aarch64_unknown_linux_musl)");        println!("cargo:rustc-check-cfg=cfg(cpu_jitter_entropy)");        println!("cargo:rustc-check-cfg=cfg(i686_pc_windows_msvc)");        println!("cargo:rustc-check-cfg=cfg(i686_unknown_linux_gnu)");        println!("cargo:rustc-check-cfg=cfg(riscv64gc_unknown_linux_gnu)");        println!("cargo:rustc-check-cfg=cfg(x86_64_apple_darwin)");        println!("cargo:rustc-check-cfg=cfg(x86_64_pc_windows_gnu)");        println!("cargo:rustc-check-cfg=cfg(x86_64_pc_windows_msvc)");        println!("cargo:rustc-check-cfg=cfg(x86_64_unknown_linux_gnu)");        println!("cargo:rustc-check-cfg=cfg(x86_64_unknown_linux_musl)");        println!("cargo:rustc-check-cfg=cfg(universal)");        println!("cargo:rustc-check-cfg=cfg(universal_no_u1)");        println!("cargo:rustc-check-cfg=cfg(universal_no_u1_prefixed)");        println!("cargo:rustc-check-cfg=cfg(universal_prefixed)");    }}fn is_crt_static() -> bool {    let features = cargo_env("CARGO_CFG_TARGET_FEATURE");    features.contains("crt-static")}#[cfg(any(feature = "bindgen", feature = "fips"))]fn handle_bindgen(manifest_dir: &Path, prefix: &Option<String>) -> bool {    if internal_bindgen_supported() && !is_external_bindgen_requested().unwrap_or(false) {        emit_warning(format!(            "Generating bindings - internal bindgen. Platform: {}",            effective_target()        ));        let gen_bindings_path = out_dir().join("bindings.rs");        generate_bindings(manifest_dir, prefix, &gen_bindings_path);        emit_rustc_cfg("use_bindgen_pregenerated");        true    } else {        false    }}#[cfg(not(any(feature = "bindgen", feature = "fips")))]fn handle_bindgen(_manifest_dir: &Path, _prefix: &Option<String>) -> bool {    false}fn canonicalized_manifest_dir() -> PathBuf {    let manifest_dir = current_dir();    let manifest_dir = dunce::canonicalize(Path::new(&manifest_dir)).unwrap();    #[cfg(windows)]    let manifest_dir = to_short_path(&manifest_dir);    manifest_dir}#[cfg(not(test))]fn main() {    initialize();    prepare_cargo_cfg();    let manifest_dir = canonicalized_manifest_dir();    let prefix = (!is_no_prefix()).then(prefix_string);    let builder = get_builder(&prefix, &manifest_dir, &out_dir());    emit_warning(format!("Building with: {}", builder.name()));    emit_warning(format!("Symbol Prefix: {prefix:?}"));    builder.check_dependencies().unwrap();    #[allow(unused_assignments)]    let mut bindings_available = false;    emit_warning(format!("Target platform: '{}'", target()));    if is_pregenerating_bindings() {        #[cfg(any(feature = "bindgen", feature = "fips"))]        {            let src_bindings_path = Path::new(&manifest_dir)                .join("src")                .join(format!("{}.rs", target_platform_prefix("crypto")));            if is_external_bindgen_requested().unwrap_or(false) {                assert!(                    !is_pregenerating_bindings(),                    "Pregenerated bindings not supported using external bindgen.",                );                invoke_external_bindgen(&manifest_dir, &prefix, &src_bindings_path).unwrap();            } else {                generate_src_bindings(&manifest_dir, &prefix, &src_bindings_path);            }            bindings_available = true;        }    } else if is_bindgen_required() {        assert!(            use_no_u1_bindings() != Some(true),            "Bindgen currently cannot generate prefixed bindings w/o the \\x01 prefix.",        );        emit_warning("######");        emit_warning(            "If bindgen is unable to locate a header file, use the \            BINDGEN_EXTRA_CLANG_ARGS environment variable to specify additional include paths.",        );        emit_warning(            "See: https://github.com/rust-lang/rust-bindgen?tab=readme-ov-file#environment-variables",        );        emit_warning("######");        let aws_lc_crypto_dir = Path::new(&manifest_dir).join("aws-lc").join("crypto");        if !aws_lc_crypto_dir.exists() {            emit_warning("######");            emit_warning("###### WARNING: MISSING GIT SUBMODULE ######");            emit_warning(format!(                "  -- Did you initialize the repo's git submodules? Unable to find crypto directory: {}.",                aws_lc_crypto_dir.display()            ));            emit_warning("  -- run 'git submodule update --init --recursive' to initialize.");            emit_warning("######");            emit_warning("######");        }        bindings_available = handle_bindgen(&manifest_dir, &prefix);    } else {        bindings_available = true;    }    if !bindings_available {        if cfg!(feature = "ssl") {            emit_warning(                "External bindgen required, but external bindgen unable to produce SSL bindings.",            );        } else {            assert!(                use_no_u1_bindings() != Some(true),                "Bindgen currently cannot generate prefixed bindings w/o the \\x01 prefix.",            );            let gen_bindings_path = out_dir().join("bindings.rs");            let result = invoke_external_bindgen(&manifest_dir, &prefix, &gen_bindings_path);            match result {                Ok(()) => {                    emit_rustc_cfg("use_bindgen_pregenerated");                    bindings_available = true;                }                Err(msg) => eprintln!("Failure invoking external bindgen! {msg}"),            }        }    }    assert!(        bindings_available,        "aws-lc-sys build failed. Please enable the 'bindgen' feature on aws-lc-rs or aws-lc-sys.\        For more information, see the aws-lc-rs User Guide: https://aws.github.io/aws-lc-rs/index.html"    );    builder.build().unwrap();    // MinGW win7 targets use the BCryptGenRandom path (AWSLC_WINDOWS_7_COMPAT),    // which requires linking against bcrypt. MinGW ignores the MSVC    // `#pragma comment(lib, "bcrypt.lib")` in the source, so we link explicitly.    // See: https://github.com/aws/aws-lc/pull/3239    if target().contains("-win7-windows-gnu") {        println!("cargo:rustc-link-lib=bcrypt");    }    println!(        "cargo:include={}",        setup_include_paths(&out_dir(), &manifest_dir).display()    );    // export the artifact names    println!("cargo:libcrypto={}_crypto", prefix_string());    if cfg!(feature = "ssl") {        println!("cargo:libssl={}_ssl", prefix_string());    }    println!("cargo:conf={}", OSSL_CONF_DEFINES.join(","));    println!("cargo:rerun-if-changed=builder/");    println!("cargo:rerun-if-changed=aws-lc/");}fn setup_include_paths(out_dir: &Path, manifest_dir: &Path) -> PathBuf {    let mut include_paths = vec![        get_rust_include_path(manifest_dir),        get_generated_include_path(manifest_dir),        get_aws_lc_include_path(manifest_dir),    ];    if let Some(extra_paths) = get_env_includes_path() {        include_paths.extend(extra_paths);    }    let include_dir = out_dir.join("include");    std::fs::create_dir_all(&include_dir).unwrap();    // iterate over all the include paths and copy them into the final output    for path in include_paths {        for child in std::fs::read_dir(path).into_iter().flatten().flatten() {            if child.path().is_file() {                std::fs::copy(                    child.path(),                    include_dir.join(child.path().file_name().unwrap()),                )                .expect("Failed to copy include file during build setup");                continue;            }            // prefer the earliest paths            let options = fs_extra::dir::CopyOptions::new()                .skip_exist(true)                .copy_inside(true);            fs_extra::dir::copy(child.path(), &include_dir, &options)                .expect("Failed to copy include directory during build setup");        }    }    include_dir}#[derive(Default)]#[allow(dead_code)]pub(crate) struct BindingOptions {    pub build_prefix: Option<String>,    pub include_ssl: bool,    pub disable_prelude: bool,}impl Debug for BindingOptions {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        f.debug_struct("BindingOptions")            .field("build_prefix", &self.build_prefix)            .field("include_ssl", &self.include_ssl)            .field("disable_prelude", &self.disable_prelude)            .finish()    }}fn verify_bindgen() -> Result<(), String> {    if !is_external_bindgen_requested().unwrap_or(true) {        return Err("external bindgen usage prevented by SYS_EXTERNAL_BINDGEN=0".to_string());    }    let result = execute_command("bindgen".as_ref(), &["--version".as_ref()]);    if !result.status {        if result.executed {            eprintln!(                "bindgen-cli exited with an error status:\nSTDOUT: {}\n\nSTDERR: {}",                result.stdout, result.stderr            );        } else {            eprintln!(                "Consider installing the bindgen-cli: \            `cargo install --force --locked bindgen-cli`\            \n\            See our User Guide for more information about bindgen:\            https://aws.github.io/aws-lc-rs/index.html"            );        }        return Err("External bindgen command failed.".to_string());    }    let mut major_version: u32 = 0;    let mut minor_version: u32 = 0;    let mut patch_version: u32 = 0;    let bindgen_version = result.stdout.split(' ').nth(1);    if let Some(version) = bindgen_version {        let version_parts: Vec<&str> = version.trim().split('.').collect();        if version_parts.len() == 3 {            major_version = version_parts[0].parse::<u32>().unwrap_or(0);            minor_version = version_parts[1].parse::<u32>().unwrap_or(0);            patch_version = version_parts[2].parse::<u32>().unwrap_or(0);        }    }    // We currently expect to support all bindgen versions >= 0.69.5    if major_version == 0 && (minor_version < 69 || (minor_version == 69 && patch_version < 5)) {        eprintln!(            "bindgen-cli was used. Detected version was: \            {major_version}.{minor_version}.{patch_version} \n\        Consider upgrading : \        `cargo install --force --locked bindgen-cli`\        \n\        See our User Guide for more information about bindgen:\        https://aws.github.io/aws-lc-rs/index.html"        );    }    Ok(())}const PRELUDE: &str = r"#![allow(    clippy::cast_lossless,    clippy::cast_possible_truncation,    clippy::cast_possible_wrap,    clippy::default_trait_access,    clippy::doc_markdown,    clippy::missing_safety_doc,    clippy::must_use_candidate,    clippy::not_unsafe_ptr_arg_deref,    clippy::ptr_as_ptr,    clippy::ptr_offset_with_cast,    clippy::pub_underscore_fields,    clippy::semicolon_if_nothing_returned,    clippy::too_many_lines,    clippy::unreadable_literal,    clippy::used_underscore_binding,    clippy::useless_transmute,    dead_code,    improper_ctypes,    non_camel_case_types,    non_snake_case,    non_upper_case_globals,    unpredictable_function_pointer_comparisons,    unused_imports)]";fn invoke_external_bindgen(    manifest_dir: &Path,    prefix: &Option<String>,    gen_bindings_path: &Path,) -> Result<(), String> {    verify_bindgen()?;    emit_warning(format!(        "Generating bindings - external bindgen. Platform: {}",        effective_target()    ));    let _guard_target = EnvGuard::new("TARGET", effective_target());    let options = BindingOptions {        // We collect the symbols w/o the prefix added        build_prefix: None,        include_ssl: false,        disable_prelude: true,    };    let clang_args = prepare_clang_args(manifest_dir, &options);    let header = get_rust_include_path(manifest_dir)        .join("rust_wrapper.h")        .display()        .to_string();    let sym_prefix: String;    let mut bindgen_params = vec![];    if let Some(prefix_str) = prefix {        sym_prefix = if target_os().to_lowercase() == "macos"            || target_os().to_lowercase() == "ios"            || target_os().to_lowercase() == "tvos"            || (target_os().to_lowercase() == "windows" && target_arch() == "x86")        {            format!("_{prefix_str}_")        } else {            format!("{prefix_str}_")        };        bindgen_params.extend(vec!["--prefix-link-name", sym_prefix.as_str()]);    }    // These flags needs to be kept in sync with the setup in bindgen::prepare_bindings_builder    // If `bindgen-cli` makes backwards incompatible changes, we will update the parameters below    // to conform with the most recent release. We will guide consumers to likewise use the    // latest version of bindgen-cli.    bindgen_params.extend(vec![        "--allowlist-file",        r".*(/|\\)openssl((/|\\)[^/\\]+)+\.h",        "--allowlist-file",        r".*(/|\\)rust_wrapper\.h",        "--rustified-enum",        r"point_conversion_form_t",        "--default-macro-constant-type",        r"signed",        "--with-derive-default",        "--with-derive-partialeq",        "--with-derive-eq",        "--raw-line",        COPYRIGHT,        "--generate",        "functions,types,vars,methods,constructors,destructors",        header.as_str(),        "--rust-target",        r"1.70",        "--output",        gen_bindings_path.to_str().unwrap(),        "--formatter",        r"rustfmt",    ]);    if !options.disable_prelude {        bindgen_params.extend(["--raw-line", PRELUDE]);    }    bindgen_params.push("--");    for x in &clang_args {        bindgen_params.push(x.as_str());    }    let cmd_params: Vec<OsString> = bindgen_params.iter().map(OsString::from).collect();    let cmd_params: Vec<&OsStr> = cmd_params.iter().map(OsString::as_os_str).collect();    let result = execute_command("bindgen".as_ref(), cmd_params.as_ref());    if !result.status {        return Err(format!(            "\n\n\            bindgen-PARAMS: {}\n\            bindgen-STDOUT: {}\n\            bindgen-STDERR: {}",            bindgen_params.join(" "),            result.stdout.as_ref(),            result.stderr.as_ref()        ));    }    Ok(())}fn add_header_include_path(args: &mut Vec<String>, path: String) {    args.push("-I".to_string());    args.push(path);}fn prepare_clang_args(manifest_dir: &Path, options: &BindingOptions) -> Vec<String> {    let mut clang_args: Vec<String> = Vec::new();    add_header_include_path(        &mut clang_args,        get_rust_include_path(manifest_dir).display().to_string(),    );    if options.build_prefix.is_some() {        // NOTE: It's possible that the prefix embedded in the header files doesn't match the prefix        // specified. This only happens when the version number as changed in Cargo.toml, but the        // new headers have not yet been generated.        add_header_include_path(            &mut clang_args,            get_generated_include_path(manifest_dir)                .display()                .to_string(),        );    }    add_header_include_path(        &mut clang_args,        get_aws_lc_include_path(manifest_dir).display().to_string(),    );    if let Some(include_paths) = get_env_includes_path() {        for path in include_paths {            add_header_include_path(&mut clang_args, path.display().to_string());        }    }    clang_args}const COPYRIGHT: &str = r"// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.// SPDX-License-Identifier: Apache-2.0 OR ISC";// =============================================================================// Tests - run via: rustc --test builder/main.rs --edition 2021 -o /tmp/builder_test && /tmp/builder_test// Or via the Makefile target: make test-builder// =============================================================================#[cfg(test)]mod tests {    use super::*;    // -------------------------------------------------------------------------    // parse_to_bool tests    // -------------------------------------------------------------------------    #[test]    fn test_parse_to_bool_true_values() {        assert_eq!(parse_to_bool("1"), Some(true));        assert_eq!(parse_to_bool("2"), Some(true));        assert_eq!(parse_to_bool("9"), Some(true));        assert_eq!(parse_to_bool("ON"), Some(true));        assert_eq!(parse_to_bool("on"), Some(true));        assert_eq!(parse_to_bool("On"), Some(true));        assert_eq!(parse_to_bool("YES"), Some(true));        assert_eq!(parse_to_bool("yes"), Some(true));        assert_eq!(parse_to_bool("TRUE"), Some(true));        assert_eq!(parse_to_bool("true"), Some(true));        assert_eq!(parse_to_bool("y"), Some(true));        assert_eq!(parse_to_bool("Y"), Some(true));        assert_eq!(parse_to_bool("t"), Some(true));        assert_eq!(parse_to_bool("T"), Some(true));    }    #[test]    fn test_parse_to_bool_false_values() {        assert_eq!(parse_to_bool("0"), Some(false));        assert_eq!(parse_to_bool("OFF"), Some(false));        assert_eq!(parse_to_bool("off"), Some(false));        assert_eq!(parse_to_bool("NO"), Some(false));        assert_eq!(parse_to_bool("no"), Some(false));        assert_eq!(parse_to_bool("FALSE"), Some(false));        assert_eq!(parse_to_bool("false"), Some(false));        assert_eq!(parse_to_bool("n"), Some(false));        assert_eq!(parse_to_bool("N"), Some(false));        assert_eq!(parse_to_bool("f"), Some(false));        assert_eq!(parse_to_bool("F"), Some(false));    }    #[test]    fn test_parse_to_bool_none_values() {        assert_eq!(parse_to_bool(""), None);        assert_eq!(parse_to_bool("invalid"), None);        assert_eq!(parse_to_bool("maybe"), None);        assert_eq!(parse_to_bool("   "), None);    }    // -------------------------------------------------------------------------    // OutputLib tests    // -------------------------------------------------------------------------    #[test]    fn test_output_lib_crypto_libname_with_prefix() {        let prefix = Some("test_prefix".to_string());        let name = OutputLib::Crypto.libname(&prefix);        assert_eq!(name, "test_prefix_crypto");    }    #[test]    fn test_output_lib_crypto_libname_without_prefix() {        let name = OutputLib::Crypto.libname(&None);        assert_eq!(name, "crypto");    }    #[test]    fn test_output_lib_ssl_libname_with_prefix() {        let prefix = Some("my_prefix".to_string());        let name = OutputLib::Ssl.libname(&prefix);        assert_eq!(name, "my_prefix_ssl");    }    #[test]    fn test_output_lib_ssl_libname_without_prefix() {        let name = OutputLib::Ssl.libname(&None);        assert_eq!(name, "ssl");    }    // -------------------------------------------------------------------------    // OutputLibType tests    // -------------------------------------------------------------------------    #[test]    fn test_output_lib_type_rust_lib_type() {        assert_eq!(OutputLibType::Static.rust_lib_type(), "static");        assert_eq!(OutputLibType::Dynamic.rust_lib_type(), "dylib");    }    // -------------------------------------------------------------------------    // Version/Prefix tests    // -------------------------------------------------------------------------    #[test]    fn test_version_constant_exists() {        assert!(!VERSION.is_empty(), "VERSION should not be empty");    }}