Files
voicebox/tauri/src-tauri/build.rs
Jamie Pine ac68052945 create stub resource files when actool output is missing
Older Xcode versions don't produce Assets.car from .icon assets.
Fall back to empty stubs for all platforms so the bundler succeeds.
2026-03-17 01:07:54 -07:00

167 lines
6.7 KiB
Rust

#[cfg(target_os = "macos")]
use std::process::Command;
fn main() {
// Link Swift runtime libraries for screencapturekit crate
#[cfg(target_os = "macos")]
{
// Add Swift runtime library paths to RPATH
println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
println!("cargo:rustc-link-arg=-L/usr/lib/swift");
// Also try Xcode's Swift libraries
if let Ok(output) = Command::new("xcode-select").arg("-p").output() {
if output.status.success() {
let xcode_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
let swift_lib_path = format!(
"{}/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx",
xcode_path
);
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", swift_lib_path);
println!("cargo:rustc-link-arg=-L{}", swift_lib_path);
}
}
}
let project_root = env!("CARGO_MANIFEST_DIR");
let gen_dir = format!("{}/gen", project_root);
std::fs::create_dir_all(&gen_dir).expect("Failed to create gen directory");
// Compile macOS Liquid Glass icon
#[cfg(target_os = "macos")]
{
// voicebox.icon is in tauri/assets/voicebox.icon (one level up from src-tauri)
let icon_source = format!("{}/../assets/voicebox.icon", project_root);
if std::path::Path::new(&icon_source).exists() {
println!("cargo:rerun-if-changed={}", icon_source);
println!("cargo:rerun-if-changed={}/icon.json", icon_source);
println!("cargo:rerun-if-changed={}/Assets", icon_source);
let partial_plist = format!("{}/partial.plist", gen_dir);
let output = Command::new("xcrun")
.args([
"actool",
"--compile",
&gen_dir,
"--output-format",
"human-readable-text",
"--output-partial-info-plist",
&partial_plist,
"--app-icon",
"voicebox",
"--include-all-app-icons",
"--target-device",
"mac",
"--minimum-deployment-target",
"11.0",
"--platform",
"macosx",
&icon_source,
])
.output();
match output {
Ok(output) => {
if !output.status.success() {
eprintln!("actool stderr: {}", String::from_utf8_lossy(&output.stderr));
eprintln!("actool stdout: {}", String::from_utf8_lossy(&output.stdout));
panic!("actool failed to compile icon");
}
println!("Successfully compiled icon to {}", gen_dir);
}
Err(e) => {
eprintln!("Failed to execute xcrun actool: {}", e);
eprintln!("Make sure you have Xcode Command Line Tools installed");
panic!("Icon compilation failed");
}
}
// Generate voicebox.icns from the source PNG via sips + iconutil
let icns_path = format!("{}/voicebox.icns", gen_dir);
if !std::path::Path::new(&icns_path).exists() {
let source_png = format!("{}/Assets/Voicebox.png", icon_source);
if std::path::Path::new(&source_png).exists() {
let iconset_dir = format!("{}/voicebox.iconset", gen_dir);
std::fs::create_dir_all(&iconset_dir).ok();
let sizes: &[(u32, &str)] = &[
(16, "icon_16x16.png"),
(32, "[email protected]"),
(32, "icon_32x32.png"),
(64, "[email protected]"),
(128, "icon_128x128.png"),
(256, "[email protected]"),
(256, "icon_256x256.png"),
(512, "[email protected]"),
(512, "icon_512x512.png"),
(1024, "[email protected]"),
];
for (size, name) in sizes {
let dest = format!("{}/{}", iconset_dir, name);
let status = Command::new("sips")
.args([
"-z",
&size.to_string(),
&size.to_string(),
&source_png,
"--out",
&dest,
])
.output();
if let Ok(out) = status {
if !out.status.success() {
eprintln!(
"sips failed for {}: {}",
name,
String::from_utf8_lossy(&out.stderr)
);
}
}
}
let iconutil_output = Command::new("iconutil")
.args(["-c", "icns", "-o", &icns_path, &iconset_dir])
.output();
match iconutil_output {
Ok(out) if out.status.success() => {
println!("Generated voicebox.icns");
}
Ok(out) => {
eprintln!("iconutil failed: {}", String::from_utf8_lossy(&out.stderr));
}
Err(e) => {
eprintln!("Failed to run iconutil: {}", e);
}
}
// Clean up iconset directory
std::fs::remove_dir_all(&iconset_dir).ok();
}
}
} else {
println!(
"cargo:warning=Icon source not found at {}, skipping icon compilation",
icon_source
);
}
}
// Ensure all resource files exist so Tauri's bundler doesn't fail.
// On non-macOS these are always stubs. On macOS, actool may not produce
// Assets.car if the Xcode version doesn't support the .icon format.
{
let required = ["Assets.car", "voicebox.icns", "partial.plist"];
for name in required {
let path = format!("{}/{}", gen_dir, name);
if !std::path::Path::new(&path).exists() {
std::fs::write(&path, b"").ok();
}
}
}
tauri_build::build()
}