use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let vulkan_feature = std::env::var_os("CARGO_FEATURE_VULKAN").is_some();
let shaders_dir = Path::new("src/vulkan/shaders");
let prebuilt_dir = Path::new("src/vulkan/spv");
if !vulkan_feature || !shaders_dir.is_dir() {
return;
}
println!("cargo:rerun-if-changed={}", shaders_dir.display());
println!("cargo:rerun-if-changed={}", prebuilt_dir.display());
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set by cargo");
let mut entries: Vec<_> = std::fs::read_dir(shaders_dir)
.unwrap_or_else(|e| panic!("failed to read {}: {e}", shaders_dir.display()))
.filter_map(|e| e.ok().map(|e| e.path()))
.filter(|p| p.extension().map(|e| e == "comp").unwrap_or(false))
.collect();
entries.sort();
if entries.is_empty() {
return;
}
let glslc = std::env::var("GLSLC").unwrap_or_else(|_| "glslc".to_string());
let have_glslc = Command::new(&glslc)
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
let glslang = std::env::var("GLSLANG").unwrap_or_else(|_| "glslangValidator".to_string());
let have_glslang = !have_glslc
&& Command::new(&glslang)
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
if !have_glslc && !have_glslang {
println!(
"cargo:warning=neither glslc nor glslangValidator found; using pre-compiled SPIR-V from {}",
prebuilt_dir.display()
);
} else if have_glslang {
println!("cargo:warning=glslc not found; compiling shaders with glslangValidator");
}
for src in &entries {
let stem = src
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or_else(|| panic!("invalid shader file name: {}", src.display()));
let dst = format!("{out_dir}/{stem}.spv");
let src_str = src.to_str().expect("non-UTF8 shader path");
println!("cargo:rerun-if-changed={src_str}");
if have_glslc {
let status = Command::new(&glslc)
.args(["--target-env=vulkan1.2", src_str, "-o", &dst])
.status()
.unwrap_or_else(|e| panic!("failed to run `{glslc}`: {e}"));
assert!(
status.success(),
"glslc failed to compile {src_str} (exit status: {status})"
);
} else if have_glslang {
let status = Command::new(&glslang)
.args(["--target-env", "vulkan1.2", "-V", src_str, "-o", &dst])
.status()
.unwrap_or_else(|e| panic!("failed to run `{glslang}`: {e}"));
assert!(
status.success(),
"glslangValidator failed to compile {src_str} (exit status: {status})"
);
} else {
let prebuilt: PathBuf = prebuilt_dir.join(format!("{stem}.spv"));
println!("cargo:rerun-if-changed={}", prebuilt.display());
std::fs::copy(&prebuilt, &dst).unwrap_or_else(|e| {
panic!(
"no glslc and no pre-compiled SPIR-V at {} (run src/vulkan/regen-spv.sh on a host with glslc): {e}",
prebuilt.display()
)
});
}
}
}