//! Cross-platform linker paths for the C libraries we wrap. //! //! Most of our codec deps (`opus`, `jpegxl-rs`, `dav1d`, `zstd`, `xz2`, //! `libavif-sys`) already have build.rs files that probe pkg-config //! themselves. `flac-bound` does NOT — it just links `-lflac` and //! expects the linker to find it. On Homebrew macOS that lives under //! `/opt/homebrew/opt/flac/lib`, which Cargo doesn't probe. We use the //! `pkg-config` crate to discover the right path on whatever system //! the user is on (Linux distros, macOS Homebrew, BSD ports, etc.). //! //! This replaces the macOS-hardcoded `.cargo/config.toml` rustflags. #[path = "src/build_info.rs"] mod build_info; fn main() { generate_c_header(); record_build(); // Only the `codecs` feature compiles flac-bound — and pkg-config's // probe() emits a `cargo:rustc-link-lib=flac` of its own, so running // it unconditionally makes every consumer (e.g. the wasm32 world // build, the wai-world-relay binary) link libFLAC it never calls. if std::env::var_os("CARGO_FEATURE_CODECS").is_some() { link_libflac(); } } /// Record the build for a measurement report (`extensions/energy-measurement.md` /// §5, §8): the profile, from cargo's `OPT_LEVEL` (`src/build_info.rs`), the /// target triple, and the compiler's version line. /// A part that cannot be determined is left unset and reads as `null`. fn record_build() { println!("cargo:rerun-if-env-changed=OPT_LEVEL"); println!("cargo:rerun-if-env-changed=TARGET"); println!("cargo:rerun-if-env-changed=RUSTC"); let var = |k: &str| std::env::var(k).unwrap_or_default(); println!( "cargo:rustc-env=WAI_BUILD_PROFILE={}", build_info::profile_label(&var("OPT_LEVEL")) ); let target = var("TARGET"); if !target.is_empty() { println!("cargo:rustc-env=WAI_BUILD_TARGET={target}"); } let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); if let Ok(out) = std::process::Command::new(rustc).arg("-V").output() { let line = String::from_utf8_lossy(&out.stdout).trim().to_owned(); if out.status.success() && !line.is_empty() && !line.contains('\n') { println!("cargo:rustc-env=WAI_BUILD_TOOLCHAIN={line}"); } } } /// Regenerate `include/wai.h` from the FFI surface so SDK consumers can /// always grab a typed header that matches the shipped binary. Only /// regenerates when source files actually change (cargo handles this /// via `rerun-if-changed` declarations). fn generate_c_header() { println!("cargo:rerun-if-changed=src/ffi.rs"); println!("cargo:rerun-if-changed=src/ffi_codecs.rs"); println!("cargo:rerun-if-changed=src/ffi_neural.rs"); println!("cargo:rerun-if-changed=src/container.rs"); println!("cargo:rerun-if-changed=cbindgen.toml"); let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let out_path = std::path::Path::new(&crate_dir).join("include/wai.h"); if let Err(e) = std::fs::create_dir_all(out_path.parent().unwrap()) { println!("cargo:warning=cbindgen: could not create include/ dir: {e}"); return; } match cbindgen::Builder::new() .with_crate(&crate_dir) .with_config(cbindgen::Config::from_file( std::path::Path::new(&crate_dir).join("cbindgen.toml")).unwrap_or_default()) .generate() { Ok(bindings) => { bindings.write_to_file(&out_path); } Err(e) => { println!("cargo:warning=cbindgen failed: {e}"); } } } fn link_libflac() { if let Ok(lib) = pkg_config::Config::new() .atleast_version("1.3") .probe("flac") { for path in &lib.link_paths { println!("cargo:rustc-link-search=native={}", path.display()); } // pkg-config also emits the library names; flac-bound links its // own `-lflac` directive so we only need the search path. } else { // Fallback: try the canonical Homebrew location on macOS so the // common case still works without pkg-config installed. #[cfg(target_os = "macos")] { let candidates = [ "/opt/homebrew/opt/flac/lib", // arm64 macOS (Homebrew) "/usr/local/opt/flac/lib", // x86_64 macOS (Homebrew) ]; for p in candidates { if std::path::Path::new(p).exists() { println!("cargo:rustc-link-search=native={p}"); return; } } } // Linux/other: hope that the system linker finds -lflac on its own. // If not, the link error will be obvious ("cannot find -lflac") // and the user needs to install libflac-dev / equivalent. } }