use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_APPLE_FM");
let feature_enabled = std::env::var("CARGO_FEATURE_APPLE_FM").is_ok();
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
if !feature_enabled || target_os != "macos" {
return;
}
build_apple_fm();
}
fn build_apple_fm() {
let manifest_dir =
std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set by cargo");
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set by cargo");
let pkg_dir = Path::new(&manifest_dir).join("vendor/foundation-models-c");
if !pkg_dir.join("Package.swift").exists() {
panic!(
"apple-fm feature is enabled but the vendored SwiftPM package was not found at {}. \
Expected Package.swift there.",
pkg_dir.display()
);
}
println!("cargo:rerun-if-changed=build.rs");
println!(
"cargo:rerun-if-changed={}",
pkg_dir.join("Package.swift").display()
);
println!(
"cargo:rerun-if-changed={}",
pkg_dir.join("Sources").display()
);
let status = Command::new("swift")
.args([
"build",
"-c",
"release",
"--product",
"FoundationModels",
"--package-path",
])
.arg(&pkg_dir)
.status()
.unwrap_or_else(|e| {
panic!(
"apple-fm feature is enabled but `swift build` could not be spawned: {e}. \
Is the Swift toolchain installed and on PATH?"
)
});
if !status.success() {
panic!(
"apple-fm feature is enabled but `swift build -c release` failed in {} \
(exit status: {status}). Fix the Swift build or disable the apple-fm feature.",
pkg_dir.display()
);
}
let lib_name = "libFoundationModels.dylib";
let built_lib = pkg_dir.join(".build/release").join(lib_name);
if !built_lib.exists() {
panic!(
"apple-fm: swift build succeeded but {} was not found",
built_lib.display()
);
}
let out_lib = Path::new(&out_dir).join(lib_name);
copy(&built_lib, &out_lib);
println!("cargo:rustc-env=TOKMESH_FM_DYLIB={}", out_lib.display());
if let Some(profile_dir) = profile_dir_from_out(&out_dir) {
let staged = profile_dir.join(lib_name);
copy(&built_lib, &staged);
println!("cargo:warning=apple-fm: staged {}", staged.display());
}
}
fn profile_dir_from_out(out_dir: &str) -> Option<PathBuf> {
Path::new(out_dir)
.parent() .and_then(Path::parent) .and_then(Path::parent) .map(Path::to_path_buf)
}
fn copy(from: &Path, to: &Path) {
std::fs::copy(from, to).unwrap_or_else(|e| {
panic!(
"apple-fm: failed to copy {} -> {}: {e}",
from.display(),
to.display()
)
});
}