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;
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
build_spirv("../example-shader")?;
SpirvBuilder::new("../example-shader").build()?;
Ok(())
}

View File

@ -24,12 +24,35 @@ impl fmt::Display for SpirvBuilderError {
impl Error for SpirvBuilderError {}
pub fn build_spirv(path_to_crate: impl AsRef<Path>) -> Result<(), SpirvBuilderError> {
let spirv_module = invoke_rustc(path_to_crate.as_ref())?;
let spirv_path: &Path = spirv_module.as_ref();
let env_var = spirv_path.file_name().unwrap().to_str().unwrap();
println!("cargo:rustc-env={}={}", env_var, spirv_module);
Ok(())
pub struct SpirvBuilder {
path_to_crate: PathBuf,
print_metadata: bool,
}
impl SpirvBuilder {
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
@ -64,7 +87,7 @@ fn find_rustc_codegen_spirv() -> PathBuf {
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
// 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
@ -93,7 +116,9 @@ fn invoke_rustc(path_to_crate: &Path) -> Result<String, SpirvBuilderError> {
if build.status.success() {
let stdout = String::from_utf8(build.stdout).unwrap();
let artifact = get_last_artifact(&stdout);
if print_metadata {
print_deps_of(&artifact);
}
Ok(artifact)
} else {
Err(SpirvBuilderError::BuildFailed)
@ -106,7 +131,7 @@ struct RustcOutput {
filenames: Option<Vec<String>>,
}
fn get_last_artifact(out: &str) -> String {
fn get_last_artifact(out: &str) -> PathBuf {
let last = out
.lines()
.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"));
let filename = filenames.next().expect("Crate had no .spv artifacts");
assert_eq!(filenames.next(), None, "Crate had multiple .spv artifacts");
filename
filename.into()
}
fn print_deps_of(artifact: &str) {
let deps_file = Path::new(artifact).with_extension("d");
fn print_deps_of(artifact: &Path) {
let deps_file = artifact.with_extension("d");
let mut deps_map = HashMap::new();
depfile::read_deps_file(&deps_file, |item, deps| {
deps_map.insert(item, deps);
@ -149,5 +174,5 @@ fn print_deps_of(artifact: &str) {
None => println!("cargo:rerun-if-changed={}", artifact),
}
}
recurse(&deps_map, artifact.into());
recurse(&deps_map, artifact.to_str().unwrap().into());
}