Files
rustyJ/crates/ri-metal/build.rs
T
Omar SobhandClaude Opus 4.6 0fd39d7fd3 Add M9-M14: UI redesign, plugins, macros, 3D viz, binary/segmentation ops, Metal GPU, scientific LUTs
M9: TailwindCSS + shadcn/ui frontend redesign
M10: Dynamic plugin system with shared library loading
M11: Macro recording, playback, and batch processing
M12: 3D volume visualization, marching cubes, STL/OBJ export, rivol:// protocol
M13: Additional GPU shaders, enhanced auto-threshold, merge channels
M14: Binary image processing (EDT, watershed, skeleton, connected components,
     voronoi), segmentation & analysis (particles, colocalization, find maxima),
     math/noise/filter/transform ops (60+ total), scientific LUTs (Fire, Ice,
     Spectrum, Jet, Phase, HiLo + .lut file I/O), Apple Metal GPU optimization
     (metal-only feature, Apple Silicon detection, lower dispatch threshold),
     native Metal compute crate (ri-metal with MSL shaders via objc2-metal),
     7 new WGSL GPU shaders (bilateral, variance, mean, math_ops, outline,
     minmax_filter, affine transform). 25 crates, 162 tests, 75+ IPC commands.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-10 07:41:56 -07:00

133 lines
3.9 KiB
Rust

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let shader_dir = Path::new("shaders");
let metallib_path = out_dir.join("default.metallib");
println!("cargo:rerun-if-changed=shaders/");
// Only compile Metal shaders on macOS
if !cfg!(target_os = "macos") {
// Write empty dummy metallib for non-macOS builds
fs::write(&metallib_path, &[]).unwrap();
println!(
"cargo:warning=Not on macOS; Metal shaders will not be compiled. \
Using empty metallib stub."
);
return;
}
// Check if xcrun is available
let xcrun_check = Command::new("xcrun").arg("--version").output();
if xcrun_check.is_err() || !xcrun_check.unwrap().status.success() {
fs::write(&metallib_path, &[]).unwrap();
println!(
"cargo:warning=xcrun not found; Metal shaders will not be compiled. \
Using empty metallib stub."
);
return;
}
// Find all .metal shader files
let metal_files: Vec<PathBuf> = if shader_dir.exists() {
fs::read_dir(shader_dir)
.unwrap()
.filter_map(|entry| {
let entry = entry.ok()?;
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) == Some("metal") {
Some(path)
} else {
None
}
})
.collect()
} else {
Vec::new()
};
if metal_files.is_empty() {
fs::write(&metallib_path, &[]).unwrap();
println!("cargo:warning=No .metal shader files found in shaders/");
return;
}
// Compile each .metal file to .air
let mut air_files = Vec::new();
for metal_file in &metal_files {
let stem = metal_file.file_stem().unwrap().to_str().unwrap();
let air_path = out_dir.join(format!("{}.air", stem));
println!("cargo:rerun-if-changed={}", metal_file.display());
let status = Command::new("xcrun")
.args([
"metal",
"-c",
"-target",
"air64-apple-macos14.0",
"-o",
])
.arg(&air_path)
.arg(metal_file)
.status();
match status {
Ok(s) if s.success() => {
air_files.push(air_path);
}
Ok(s) => {
println!(
"cargo:warning=Failed to compile {} (exit code: {:?})",
metal_file.display(),
s.code()
);
}
Err(e) => {
println!(
"cargo:warning=Failed to run xcrun metal for {}: {}",
metal_file.display(),
e
);
}
}
}
if air_files.is_empty() {
fs::write(&metallib_path, &[]).unwrap();
println!("cargo:warning=No .air files produced; using empty metallib stub.");
return;
}
// Link all .air files into a single .metallib
let mut cmd = Command::new("xcrun");
cmd.arg("metallib").arg("-o").arg(&metallib_path);
for air in &air_files {
cmd.arg(air);
}
match cmd.status() {
Ok(s) if s.success() => {
println!("cargo:note=Successfully compiled Metal shaders into default.metallib");
}
Ok(s) => {
fs::write(&metallib_path, &[]).unwrap();
println!(
"cargo:warning=metallib linking failed (exit code: {:?}); using empty stub.",
s.code()
);
}
Err(e) => {
fs::write(&metallib_path, &[]).unwrap();
println!(
"cargo:warning=Failed to run xcrun metallib: {}; using empty stub.",
e
);
}
}
}