YrXtals/build.rs

101 lines
3.2 KiB
Rust

// embeds assets/Icon.svg into the windows .exe via rsvg-convert, magick, llvm-windres, and rustc-link-arg-bins.
fn main() {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
if target_os != "windows" {
return;
}
let svg = "assets/Icon.svg";
let out_dir = std::env::var("OUT_DIR").expect("cargo OUT_DIR");
let tmp = format!("{out_dir}/icon_tmp");
let ico = format!("{out_dir}/icon.ico");
let rc = format!("{out_dir}/icon.rc");
let res = format!("{out_dir}/icon.res");
println!("cargo:rerun-if-changed={svg}");
println!("cargo:rerun-if-changed=build.rs");
if !std::path::Path::new(svg).exists() {
println!("cargo:warning=no {svg} — skipping windows icon embed");
return;
}
let _ = std::fs::create_dir_all(&tmp);
let sizes = [16, 24, 32, 48, 64, 128, 256];
let mut pngs: Vec<String> = Vec::new();
for size in sizes {
let out = format!("{tmp}/icon_{size}.png");
let s = size.to_string();
if !run(&["rsvg-convert", "--width", &s, "--height", &s, svg, "-o", &out]) {
println!("cargo:warning=rsvg-convert failed — windows icon not embedded (brew install librsvg)");
let _ = std::fs::remove_dir_all(&tmp);
return;
}
pngs.push(out);
}
let mut magick_args: Vec<&str> = pngs.iter().map(|s| s.as_str()).collect();
magick_args.push(&ico);
if !run_vec("magick", &magick_args) {
println!("cargo:warning=magick failed — windows icon not embedded (brew install imagemagick)");
let _ = std::fs::remove_dir_all(&tmp);
return;
}
let _ = std::fs::remove_dir_all(&tmp);
if std::fs::write(&rc, "1 ICON \"icon.ico\"\r\n").is_err() {
println!("cargo:warning=could not write {rc} — windows icon not embedded");
return;
}
let Some(windres) = locate_llvm_windres() else {
println!("cargo:warning=llvm-windres not found — windows icon not embedded (brew install llvm)");
return;
};
if !run(&[&windres, "-I", &out_dir, &rc, "-o", &res]) {
println!("cargo:warning=llvm-windres failed — windows icon not embedded");
return;
}
println!("cargo:rustc-link-arg-bins={res}");
}
/// resolves llvm-windres from $LLVM_WINDRES, Homebrew's keg-only llvm prefix on Apple Silicon and Intel, or $PATH.
fn locate_llvm_windres() -> Option<String> {
if let Ok(p) = std::env::var("LLVM_WINDRES") {
if std::path::Path::new(&p).exists() {
return Some(p);
}
}
let candidates = [
"/opt/homebrew/opt/llvm/bin/llvm-windres",
"/usr/local/opt/llvm/bin/llvm-windres",
];
for c in candidates {
if std::path::Path::new(c).exists() {
return Some(c.to_string());
}
}
if run(&["sh", "-c", "command -v llvm-windres"]) {
return Some("llvm-windres".to_string());
}
None
}
fn run(args: &[&str]) -> bool {
std::process::Command::new(args[0])
.args(&args[1..])
.status()
.map(|s| s.success())
.unwrap_or(false)
}
fn run_vec(cmd: &str, args: &[&str]) -> bool {
std::process::Command::new(cmd)
.args(args)
.status()
.map(|s| s.success())
.unwrap_or(false)
}