101 lines
3.2 KiB
Rust
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)
|
|
}
|