fn main() { // Optional: link a prebuilt libcstcore when HERMIT_CORE_LIB is set. // Example: // HERMIT_CORE_LIB=/path/to/libcstcore.a HERMIT_CORE_INCLUDE=/path/to/include // cargo build --features engine if std::env::var("CARGO_FEATURE_ENGINE").is_ok() { let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); // src-tauri → desktop → apps → repo root let repo_root = manifest_dir.join("../../.."); let include = std::env::var("HERMIT_CORE_INCLUDE").unwrap_or_else(|_| { repo_root .join("include") .canonicalize() .map(|p| p.display().to_string()) .unwrap_or_else(|_| repo_root.join("include").display().to_string()) }); let mut build = cc::Build::new(); build .file("src/ffi_bridge.c") .include(&include) .include("src") .warnings(false); // libcstcore pulls C11 + POSIX. build.std("c11"); build.compile("hermit_ffi_bridge"); println!("cargo:rerun-if-changed=src/ffi_bridge.c"); println!("cargo:rerun-if-changed=src/ffi_bridge.h"); let core = std::env::var("HERMIT_CORE_LIB") .ok() .map(std::path::PathBuf::from) .filter(|p| p.exists()) .or_else(|| { let fallback = repo_root.join("libcstcore.a"); fallback.exists().then_some(fallback) }); if let Some(path) = core { if let Some(dir) = path.parent() { println!("cargo:rustc-link-search=native={}", dir.display()); } let stem = path .file_stem() .and_then(|s| s.to_str()) .unwrap_or("cstcore") .trim_start_matches("lib"); println!("cargo:rustc-link-lib=static={}", stem); // libcstcore leaves sashidown symbols unresolved (same as Makefile LDLIBS). let sashidown_dir = repo_root.join("vendor/sashidown"); let sashidown_a = sashidown_dir.join("libsashidown.a"); if sashidown_a.exists() { println!( "cargo:rustc-link-search=native={}", sashidown_dir .canonicalize() .unwrap_or_else(|_| sashidown_dir.clone()) .display() ); println!("cargo:rustc-link-lib=static=sashidown"); println!("cargo:rerun-if-changed={}", sashidown_a.display()); } else { println!( "cargo:warning=missing {} (make -C vendor/sashidown libsashidown.a)", sashidown_a.display() ); } link_curl_and_sys(); println!("cargo:rerun-if-changed={}", path.display()); } else { println!( "cargo:warning=feature engine enabled but HERMIT_CORE_LIB unset and libcstcore.a missing" ); } println!("cargo:rerun-if-env-changed=HERMIT_CORE_LIB"); println!("cargo:rerun-if-env-changed=HERMIT_CORE_INCLUDE"); println!("cargo:rerun-if-env-changed=HERMIT_CURL_LIBDIR"); println!("cargo:rerun-if-env-changed=PKG_CONFIG_PATH"); println!("cargo:rustc-env=HERMIT_CORE_INCLUDE={}", include); } tauri_build::build() } /// libcstcore needs libcurl (+ pthread/m/dl). On NixOS `-lcurl` alone fails /// because curl is not on the default linker path — resolve via pkg-config, /// HERMIT_CURL_LIBDIR, or `ldd $(command -v curl)`. fn link_curl_and_sys() { if link_curl_via_pkg_config() || link_curl_via_env() || link_curl_via_ldd() { // ok } else { println!("cargo:warning=libcurl path not found; falling back to -lcurl"); println!("cargo:rustc-link-lib=curl"); } println!("cargo:rustc-link-lib=pthread"); println!("cargo:rustc-link-lib=m"); println!("cargo:rustc-link-lib=dl"); } fn apply_pkg_libs(libs: &str) -> bool { let mut saw_curl = false; for tok in libs.split_whitespace() { if let Some(dir) = tok.strip_prefix("-L") { if !dir.is_empty() { println!("cargo:rustc-link-search=native={dir}"); } } else if let Some(lib) = tok.strip_prefix("-l") { if lib == "curl" { saw_curl = true; } println!("cargo:rustc-link-lib={lib}"); } } saw_curl } fn link_curl_via_pkg_config() -> bool { let Ok(out) = std::process::Command::new("pkg-config") .args(["--libs", "libcurl"]) .output() else { return false; }; if !out.status.success() { return false; } let libs = String::from_utf8_lossy(&out.stdout); apply_pkg_libs(libs.trim()) } fn link_curl_via_env() -> bool { let Ok(dir) = std::env::var("HERMIT_CURL_LIBDIR") else { return false; }; if dir.is_empty() || !std::path::Path::new(&dir).is_dir() { return false; } println!("cargo:rustc-link-search=native={dir}"); println!("cargo:rustc-link-lib=curl"); true } fn link_curl_via_ldd() -> bool { // Parse: libcurl.so.4 => /nix/store/.../lib/libcurl.so.4 (0x...) let script = r#" set -e bin=$(command -v curl 2>/dev/null || true) [ -n "$bin" ] || exit 1 ldd "$bin" 2>/dev/null | awk '/libcurl\.so/ { print $3; exit }' "#; let Ok(out) = std::process::Command::new("sh") .arg("-c") .arg(script) .output() else { return false; }; if !out.status.success() { return false; } let so = String::from_utf8_lossy(&out.stdout); let so = so.trim(); if so.is_empty() || so == "not" { return false; } let path = std::path::Path::new(so); let Some(dir) = path.parent() else { return false; }; if !dir.is_dir() { return false; } println!("cargo:rustc-link-search=native={}", dir.display()); println!("cargo:rustc-link-lib=curl"); true }