Move to a builder struct for spirv-builder (#59)

This allows the print_metadata option
This commit is contained in:
Ashley Hauck 2020-10-14 15:48:21 +02:00 committed by GitHub
parent 377bf070f0
commit d3af0552d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 15 deletions

View File

@ -1,8 +1,8 @@
use spirv_builder::build_spirv; use spirv_builder::SpirvBuilder;
use std::error::Error; use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
// This will set the env var `example-shader.spv` to a spir-v file that can be include!()'d // This will set the env var `example-shader.spv` to a spir-v file that can be include!()'d
build_spirv("../example-shader")?; SpirvBuilder::new("../example-shader").build()?;
Ok(()) Ok(())
} }

View File

@ -24,12 +24,35 @@ impl fmt::Display for SpirvBuilderError {
impl Error for SpirvBuilderError {} impl Error for SpirvBuilderError {}
pub fn build_spirv(path_to_crate: impl AsRef<Path>) -> Result<(), SpirvBuilderError> { pub struct SpirvBuilder {
let spirv_module = invoke_rustc(path_to_crate.as_ref())?; path_to_crate: PathBuf,
let spirv_path: &Path = spirv_module.as_ref(); print_metadata: bool,
let env_var = spirv_path.file_name().unwrap().to_str().unwrap(); }
println!("cargo:rustc-env={}={}", env_var, spirv_module); impl SpirvBuilder {
Ok(()) pub fn new(path_to_crate: impl AsRef<Path>) -> Self {
Self {
path_to_crate: path_to_crate.as_ref().to_owned(),
print_metadata: true,
}
}
/// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to true.
pub fn print_metadata(&mut self, v: bool) -> &mut Self {
self.print_metadata = v;
self
}
/// Builds the module. Returns the path to the built spir-v file. If print_metadata is true,
/// you usually don't have to inspect the path, as the environment variable will already be
/// set.
pub fn build(self) -> Result<PathBuf, SpirvBuilderError> {
let spirv_module = invoke_rustc(self.path_to_crate.as_ref(), self.print_metadata)?;
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
if self.print_metadata {
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
}
Ok(spirv_module)
}
} }
// https://github.com/rust-lang/cargo/blob/1857880b5124580c4aeb4e8bc5f1198f491d61b1/src/cargo/util/paths.rs#L29-L52 // https://github.com/rust-lang/cargo/blob/1857880b5124580c4aeb4e8bc5f1198f491d61b1/src/cargo/util/paths.rs#L29-L52
@ -64,7 +87,7 @@ fn find_rustc_codegen_spirv() -> PathBuf {
panic!("Could not find {} in library path", filename); panic!("Could not find {} in library path", filename);
} }
fn invoke_rustc(path_to_crate: &Path) -> Result<String, SpirvBuilderError> { fn invoke_rustc(path_to_crate: &Path, print_metadata: bool) -> Result<PathBuf, SpirvBuilderError> {
// Okay, this is a little bonkers: in a normal world, we'd have the user clone // Okay, this is a little bonkers: in a normal world, we'd have the user clone
// rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab // rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
// the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user // the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user
@ -93,7 +116,9 @@ fn invoke_rustc(path_to_crate: &Path) -> Result<String, SpirvBuilderError> {
if build.status.success() { if build.status.success() {
let stdout = String::from_utf8(build.stdout).unwrap(); let stdout = String::from_utf8(build.stdout).unwrap();
let artifact = get_last_artifact(&stdout); let artifact = get_last_artifact(&stdout);
print_deps_of(&artifact); if print_metadata {
print_deps_of(&artifact);
}
Ok(artifact) Ok(artifact)
} else { } else {
Err(SpirvBuilderError::BuildFailed) Err(SpirvBuilderError::BuildFailed)
@ -106,7 +131,7 @@ struct RustcOutput {
filenames: Option<Vec<String>>, filenames: Option<Vec<String>>,
} }
fn get_last_artifact(out: &str) -> String { fn get_last_artifact(out: &str) -> PathBuf {
let last = out let last = out
.lines() .lines()
.filter_map(|line| match serde_json::from_str::<RustcOutput>(line) { .filter_map(|line| match serde_json::from_str::<RustcOutput>(line) {
@ -128,11 +153,11 @@ fn get_last_artifact(out: &str) -> String {
.filter(|v| v.ends_with(".spv")); .filter(|v| v.ends_with(".spv"));
let filename = filenames.next().expect("Crate had no .spv artifacts"); let filename = filenames.next().expect("Crate had no .spv artifacts");
assert_eq!(filenames.next(), None, "Crate had multiple .spv artifacts"); assert_eq!(filenames.next(), None, "Crate had multiple .spv artifacts");
filename filename.into()
} }
fn print_deps_of(artifact: &str) { fn print_deps_of(artifact: &Path) {
let deps_file = Path::new(artifact).with_extension("d"); let deps_file = artifact.with_extension("d");
let mut deps_map = HashMap::new(); let mut deps_map = HashMap::new();
depfile::read_deps_file(&deps_file, |item, deps| { depfile::read_deps_file(&deps_file, |item, deps| {
deps_map.insert(item, deps); deps_map.insert(item, deps);
@ -149,5 +174,5 @@ fn print_deps_of(artifact: &str) {
None => println!("cargo:rerun-if-changed={}", artifact), None => println!("cargo:rerun-if-changed={}", artifact),
} }
} }
recurse(&deps_map, artifact.into()); recurse(&deps_map, artifact.to_str().unwrap().into());
} }