fn main() {
let plist = concat!(env!("CARGO_MANIFEST_DIR"), "/resources/Info.plist");
println!("cargo:rustc-link-arg-bins=-sectcreate");
println!("cargo:rustc-link-arg-bins=__TEXT");
println!("cargo:rustc-link-arg-bins=__info_plist");
println!("cargo:rustc-link-arg-bins={plist}");
println!("cargo:rerun-if-changed=resources/Info.plist");
fix_clang_rt_search_path();
println!("cargo:rustc-link-lib=framework=ApplicationServices");
println!("cargo:rustc-link-lib=framework=CoreFoundation");
println!("cargo:rustc-link-lib=framework=CoreGraphics");
println!("cargo:rustc-link-lib=framework=AppKit");
if std::env::var("CARGO_FEATURE_CAMERA").is_ok() {
compile_camera_objc();
println!("cargo:rustc-link-lib=framework=AVFoundation");
println!("cargo:rustc-link-lib=framework=Vision");
println!("cargo:rustc-link-lib=framework=CoreImage");
println!("cargo:rustc-link-lib=framework=ImageIO");
println!("cargo:rustc-link-lib=framework=CoreMedia");
println!("cargo:rustc-link-lib=framework=CoreVideo");
}
if std::env::var("CARGO_FEATURE_CONTEXT").is_ok() {
println!("cargo:rustc-link-lib=framework=CoreLocation");
}
if std::env::var("CARGO_FEATURE_AUDIO").is_ok() {
println!("cargo:rustc-link-lib=framework=CoreAudio");
println!("cargo:rustc-link-lib=framework=AudioToolbox");
println!("cargo:rustc-link-lib=framework=AVFoundation");
println!("cargo:rustc-link-lib=framework=Speech");
println!("cargo:rustc-link-lib=framework=CoreMedia");
compile_sck_audio_objc();
println!("cargo:rustc-link-lib=framework=ScreenCaptureKit");
}
}
fn compile_camera_objc() {
cc::Build::new()
.file("src/camera_objc.m")
.flag("-fobjc-arc")
.flag("-fmodules")
.flag("-Wno-deprecated-declarations")
.compile("camera_objc");
println!("cargo:rerun-if-changed=src/camera_objc.m");
}
fn compile_sck_audio_objc() {
cc::Build::new()
.file("src/sck_audio_objc.m")
.flag("-fobjc-arc")
.flag("-fmodules")
.flag("-Wno-unguarded-availability-new")
.flag("-mmacosx-version-min=13.0")
.compile("sck_audio_objc");
println!("cargo:rerun-if-changed=src/sck_audio_objc.m");
}
fn fix_clang_rt_search_path() {
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("macos") {
return;
}
println!("cargo:rerun-if-env-changed=DEVELOPER_DIR");
let Ok(output) = std::process::Command::new("clang")
.arg("--print-search-dirs")
.output()
else {
return;
};
if !output.status.success() {
return;
}
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
let Some(eq_pos) = line.find("libraries: =") else {
continue;
};
let path = line[eq_pos + "libraries: =".len()..].trim();
if path.is_empty() {
continue;
}
let lib_darwin = std::path::Path::new(path).join("lib/darwin");
if lib_darwin.is_dir() {
return;
}
let Some(parent) = std::path::Path::new(path).parent() else {
break;
};
if let Ok(entries) = std::fs::read_dir(parent) {
let mut candidates: Vec<_> = entries
.flatten()
.map(|e| e.path().join("lib/darwin"))
.filter(|p| p.is_dir())
.collect();
candidates.sort_by_key(|p| {
p.parent()
.and_then(|d| d.file_name())
.and_then(|n| n.to_str())
.map(|s| {
s.split('.')
.filter_map(|c| c.parse::<u64>().ok())
.collect::<Vec<_>>()
})
.unwrap_or_default()
});
if let Some(found) = candidates.last() {
println!("cargo:rustc-link-search=native={}", found.display());
}
}
break;
}
}