use std::{env, path::PathBuf};
use cmake::Config;
const WINDOWS_SYSTEM_LIBS: &[&str] = &["ole32", "onecore", "runtimeobject", "uiautomationcore", "rpcrt4", "powrprof"];
fn main() {
println!("cargo:rerun-if-env-changed=PRISM_LIB_DIR");
let static_link = env::var("CARGO_FEATURE_STATIC").is_ok();
if let Ok(dir) = env::var("PRISM_LIB_DIR") {
println!("cargo:rustc-link-search=native={dir}");
} else {
build_vendored(static_link);
}
let kind = if static_link { "static" } else { "dylib" };
println!("cargo:rustc-link-lib={kind}=prism");
if static_link {
link_cpp_runtime();
link_windows_import_libs();
}
}
fn link_windows_import_libs() {
if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
return;
}
for lib in WINDOWS_SYSTEM_LIBS {
println!("cargo:rustc-link-lib=dylib={lib}");
}
let Some(lib_dir) = env::var_os("OUT_DIR").map(PathBuf::from).map(|out| out.join("lib")) else { return };
let manifest = lib_dir.join("prism-static-windows.txt");
let Ok(text) = std::fs::read_to_string(&manifest) else {
println!("cargo:warning=prism-static-windows.txt is missing; the Windows backends will not link");
return;
};
let mut dlls = Vec::new();
for line in text.lines() {
let mut parts = line.split_whitespace();
let (Some(lib), Some(dll)) = (parts.next(), parts.next()) else { continue };
println!("cargo:rustc-link-lib=dylib={lib}");
dlls.push(dll);
}
println!("cargo:delay_load_dlls={}", dlls.join(";"));
}
fn build_vendored(static_link: bool) {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("cargo sets CARGO_MANIFEST_DIR"));
let source = manifest_dir.join("prism");
assert!(
source.join("CMakeLists.txt").exists(),
"vendored prism source not found at {}; run `git submodule update --init` \
or set PRISM_LIB_DIR to a directory containing a prebuilt prism library",
source.display()
);
println!("cargo:rerun-if-changed=prism/CMakeLists.txt");
println!("cargo:rerun-if-changed=prism/cmake");
println!("cargo:rerun-if-changed=prism/source");
println!("cargo:rerun-if-changed=prism/include");
let mut cfg = Config::new(&source);
let _ = cfg.define("BUILD_SHARED_LIBS", if static_link { "OFF" } else { "ON" });
if env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
let crt_static =
env::var("CARGO_CFG_TARGET_FEATURE").is_ok_and(|features| features.split(',').any(|f| f == "crt-static"));
let _ = cfg.define("CMAKE_MSVC_RUNTIME_LIBRARY", if crt_static { "MultiThreaded" } else { "MultiThreadedDLL" });
}
let dst = cfg.build();
println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
println!("cargo:rustc-link-search=native={}", dst.join("bin").display());
}
fn link_cpp_runtime() {
let os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
match (os.as_str(), target_env.as_str()) {
(_, "msvc") => println!("cargo:rustc-link-lib=delayimp"),
("macos" | "ios" | "tvos" | "watchos" | "visionos", _) => println!("cargo:rustc-link-lib=c++"),
("android", _) => println!("cargo:rustc-link-lib=c++_shared"),
_ => println!("cargo:rustc-link-lib=stdc++"),
}
}