Skip to content

Commit f91d4c6

Browse files
committed
build_script: replace enum MetadataPrintout with struct BuildScriptConfig for more flexibility
1 parent a30bd43 commit f91d4c6

File tree

8 files changed

+97
-81
lines changed

8 files changed

+97
-81
lines changed

crates/spirv-builder/README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ It takes care of pulling in the `SPIR-V` backend for Rust, `rustc_codegen_spirv`
1111
## Example
1212

1313
```rust,no_run
14-
use spirv_builder::{MetadataPrintout, SpirvBuilder};
15-
14+
# use spirv_builder::SpirvBuilder;
15+
#
1616
fn main() -> Result<(), Box<dyn std::error::Error>> {
17-
SpirvBuilder::new("my_shaders", "spirv-unknown-vulkan1.1")
18-
.print_metadata(MetadataPrintout::Full)
19-
.build()?;
17+
let mut builder = SpirvBuilder::new("my_shaders", "spirv-unknown-vulkan1.3");
18+
builder.build_script.defaults = true;
19+
builder.build_script.env_shader_spv_path = Some(true);
20+
builder.build()?;
2021
Ok(())
2122
}
2223
```

crates/spirv-builder/src/lib.rs

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,10 @@ pub enum SpirvBuilderError {
113113
RustcCodegenSpirvDylibDoesNotExist(PathBuf),
114114
#[error("build failed")]
115115
BuildFailed,
116-
#[error("multi-module build cannot be used with print_metadata = MetadataPrintout::Full")]
117-
MultiModuleWithPrintMetadata,
116+
#[error(
117+
"`multimodule: true` build cannot be used together with `build_script.env_shader_spv_path: true`"
118+
)]
119+
MultiModuleWithEnvShaderSpvPath,
118120
#[error("multi-module metadata file missing")]
119121
MetadataFileMissing(#[from] std::io::Error),
120122
#[error("unable to parse multi-module metadata file")]
@@ -130,21 +132,6 @@ pub enum SpirvBuilderError {
130132
WatchFailed(#[from] SpirvWatcherError),
131133
}
132134

133-
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, serde::Deserialize, serde::Serialize)]
134-
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
135-
#[non_exhaustive]
136-
pub enum MetadataPrintout {
137-
/// Print no cargo metadata.
138-
#[default]
139-
None,
140-
/// Print only dependency information (eg for multiple modules).
141-
DependencyOnly,
142-
/// Print all cargo metadata.
143-
///
144-
/// Includes dependency information and spirv environment variable.
145-
Full,
146-
}
147-
148135
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, serde::Deserialize, serde::Serialize)]
149136
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
150137
#[non_exhaustive]
@@ -388,6 +375,50 @@ impl Default for ShaderCrateFeatures {
388375
}
389376
}
390377

378+
/// Configuration for build scripts
379+
#[derive(Clone, Debug, Default)]
380+
#[non_exhaustive]
381+
pub struct BuildScriptConfig {
382+
/// Enable this if you are using `spirv-builder` from a build script to apply some recommended default options, such
383+
/// as [`Self::dependency_info`].
384+
pub defaults: bool,
385+
386+
/// Print dependency information for cargo build scripts (with `cargo::rerun-if-changed={}` and such).
387+
/// Dependency information makes cargo rerun the build script is rerun when shader source files change, thus
388+
/// rebuilding the shader.
389+
///
390+
/// Default: [`Self::defaults`]
391+
pub dependency_info: Option<bool>,
392+
393+
/// Whether to emit an env var pointing to the shader module file (via `cargo::rustc-env={}`). The name of the env
394+
/// var is the crate name with `.spv` appended, e.g. `sky_shader.spv`.
395+
/// Not supported together with `multimodule=true` or `.watch()`.
396+
///
397+
/// Some examples on how to include the shader module in the source code:
398+
/// * wgpu:
399+
/// ```rust,ignore
400+
/// let shader: ShaderModuleDescriptorPassthrough = include_spirv_raw!(env!("my_shader.spv"));
401+
/// ```
402+
/// * ash
403+
/// ```rust,ignore
404+
/// let bytes: &[u8] = include_bytes!(env!("my_shader.spv"))
405+
/// let words = ash::util::read_spv(&mut std::io::Cursor::new(bytes)).unwrap();
406+
/// ```
407+
///
408+
/// Default: `false`
409+
pub env_shader_spv_path: Option<bool>,
410+
}
411+
412+
/// these all have the prefix `get` so the doc items link to the members, not these private fns
413+
impl BuildScriptConfig {
414+
fn get_dependency_info(&self) -> bool {
415+
self.dependency_info.unwrap_or(self.defaults)
416+
}
417+
fn get_env_shader_spv_path(&self) -> bool {
418+
self.env_shader_spv_path.unwrap_or(false)
419+
}
420+
}
421+
391422
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
392423
#[cfg_attr(feature = "clap", derive(clap::Parser))]
393424
#[non_exhaustive]
@@ -402,10 +433,10 @@ pub struct SpirvBuilder {
402433
/// `--crate-type dylib`. Defaults to true if `cargo_cmd` is `None` or `Some("rustc")`.
403434
#[cfg_attr(feature = "clap", clap(skip))]
404435
pub cargo_cmd_like_rustc: Option<bool>,
405-
/// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to [`MetadataPrintout::None`].
406-
/// Within build scripts, set it to [`MetadataPrintout::DependencyOnly`] or [`MetadataPrintout::Full`] to ensure the build script is rerun on code changes.
436+
/// Configuration for build scripts
407437
#[cfg_attr(feature = "clap", clap(skip))]
408-
pub print_metadata: MetadataPrintout,
438+
#[serde(skip)]
439+
pub build_script: BuildScriptConfig,
409440
/// Build in release. Defaults to true.
410441
#[cfg_attr(feature = "clap", clap(long = "debug", default_value = "true", action = clap::ArgAction::SetFalse))]
411442
pub release: bool,
@@ -493,7 +524,7 @@ impl Default for SpirvBuilder {
493524
path_to_crate: None,
494525
cargo_cmd: None,
495526
cargo_cmd_like_rustc: None,
496-
print_metadata: MetadataPrintout::default(),
527+
build_script: BuildScriptConfig::default(),
497528
release: true,
498529
target: None,
499530
deny_warnings: false,
@@ -523,13 +554,6 @@ impl SpirvBuilder {
523554
}
524555
}
525556

526-
/// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to [`MetadataPrintout::Full`].
527-
#[must_use]
528-
pub fn print_metadata(mut self, v: MetadataPrintout) -> Self {
529-
self.print_metadata = v;
530-
self
531-
}
532-
533557
#[must_use]
534558
pub fn deny_warnings(mut self, v: bool) -> Self {
535559
self.deny_warnings = v;
@@ -675,19 +699,15 @@ impl SpirvBuilder {
675699
self
676700
}
677701

678-
/// Builds the module. If `print_metadata` is [`MetadataPrintout::Full`], you usually don't have to inspect the path
679-
/// in the result, as the environment variable for the path to the module will already be set.
702+
/// Builds the module
680703
pub fn build(&self) -> Result<CompileResult, SpirvBuilderError> {
681704
let metadata_file = invoke_rustc(self)?;
682-
match self.print_metadata {
683-
MetadataPrintout::Full | MetadataPrintout::DependencyOnly => {
684-
leaf_deps(&metadata_file, |artifact| {
685-
println!("cargo:rerun-if-changed={artifact}");
686-
})
687-
// Close enough
688-
.map_err(SpirvBuilderError::MetadataFileMissing)?;
689-
}
690-
MetadataPrintout::None => (),
705+
if self.build_script.get_dependency_info() {
706+
leaf_deps(&metadata_file, |artifact| {
707+
println!("cargo:rerun-if-changed={artifact}");
708+
})
709+
// Close enough
710+
.map_err(SpirvBuilderError::MetadataFileMissing)?;
691711
}
692712
let metadata = self.parse_metadata_file(&metadata_file)?;
693713

@@ -706,17 +726,17 @@ impl SpirvBuilder {
706726
match &metadata.module {
707727
ModuleResult::SingleModule(spirv_module) => {
708728
assert!(!self.multimodule);
709-
let env_var = format!(
710-
"{}.spv",
711-
at.file_name()
712-
.unwrap()
713-
.to_str()
714-
.unwrap()
715-
.strip_suffix(ARTIFACT_SUFFIX)
716-
.unwrap()
717-
);
718-
if self.print_metadata == MetadataPrintout::Full {
719-
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
729+
if self.build_script.get_env_shader_spv_path() {
730+
let env_var = format!(
731+
"{}.spv",
732+
at.file_name()
733+
.unwrap()
734+
.to_str()
735+
.unwrap()
736+
.strip_suffix(ARTIFACT_SUFFIX)
737+
.unwrap()
738+
);
739+
println!("cargo::rustc-env={}={}", env_var, spirv_module.display());
720740
}
721741
}
722742
ModuleResult::MultiModule(_) => {
@@ -792,8 +812,8 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
792812
.ok_or(SpirvBuilderError::MissingTarget)?;
793813
target = SpirvTarget::parse(target_str)?;
794814

795-
if (builder.print_metadata == MetadataPrintout::Full) && builder.multimodule {
796-
return Err(SpirvBuilderError::MultiModuleWithPrintMetadata);
815+
if builder.build_script.get_env_shader_spv_path() && builder.multimodule {
816+
return Err(SpirvBuilderError::MultiModuleWithEnvShaderSpvPath);
797817
}
798818
if !path_to_crate.is_dir() {
799819
return Err(SpirvBuilderError::CratePathDoesntExist(
@@ -858,7 +878,7 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
858878

859879
// Wrapper for `env::var` that appropriately informs Cargo of the dependency.
860880
let tracked_env_var_get = |name| {
861-
if let MetadataPrintout::Full | MetadataPrintout::DependencyOnly = builder.print_metadata {
881+
if builder.build_script.get_dependency_info() {
862882
println!("cargo:rerun-if-env-changed={name}");
863883
}
864884
env::var(name)

crates/spirv-builder/src/watch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl SpirvWatcher {
5555
.as_ref()
5656
.ok_or(SpirvBuilderError::MissingCratePath)?
5757
.clone();
58-
if !matches!(builder.print_metadata, crate::MetadataPrintout::None) {
58+
if builder.build_script.get_env_shader_spv_path() {
5959
return Err(SpirvWatcherError::WatchWithPrintMetadata.into());
6060
}
6161

examples/multibuilder/src/main.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
use spirv_builder::{MetadataPrintout, SpirvBuilder};
1+
use spirv_builder::SpirvBuilder;
22

33
fn main() {
4-
let result = SpirvBuilder::new(
4+
let mut builder = SpirvBuilder::new(
55
concat!(env!("CARGO_MANIFEST_DIR"), "/../shaders/sky-shader"),
66
"spirv-unknown-spv1.3",
7-
)
8-
.print_metadata(MetadataPrintout::DependencyOnly)
9-
.multimodule(true)
10-
.build()
11-
.unwrap();
7+
);
8+
builder.multimodule = true;
9+
let result = builder.build().unwrap();
1210
println!("{result:#?}");
1311
}

examples/runners/ash/src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ use ash::util::read_spv;
7878
use clap::{Parser, ValueEnum};
7979
use raw_window_handle::HasDisplayHandle as _;
8080
use shared::ShaderConstants;
81-
use spirv_builder::{MetadataPrintout, SpirvBuilder};
81+
use spirv_builder::SpirvBuilder;
8282
use std::{
8383
fs::File,
8484
path::PathBuf,
@@ -259,7 +259,6 @@ pub fn compile_shaders(shader: &RustGPUShader) -> anyhow::Result<Vec<u32>> {
259259
.collect::<PathBuf>();
260260

261261
let compile_result = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.3")
262-
.print_metadata(MetadataPrintout::None)
263262
.shader_panic_strategy(spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
264263
print_inputs: true,
265264
print_backtrace: true,

examples/runners/wgpu/builder/src/main.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
use spirv_builder::{MetadataPrintout, SpirvBuilder};
1+
use spirv_builder::SpirvBuilder;
22
use std::env;
33
use std::error::Error;
44
use std::fs;
5-
use std::path::Path;
5+
use std::path::{Path, PathBuf};
66

77
fn build_shader(path_to_crate: &str, codegen_names: bool) -> Result<(), Box<dyn Error>> {
8-
let builder_dir = &Path::new(env!("CARGO_MANIFEST_DIR"));
9-
let path_to_crate = builder_dir.join(path_to_crate);
10-
let result = SpirvBuilder::new(path_to_crate, "spirv-unknown-vulkan1.1")
11-
.print_metadata(MetadataPrintout::Full)
12-
// Give this spirv-builder a unique target dir, so that rebuilding android and the main wgpu app's target dir
13-
// don't clash and break each other's incremental
14-
.target_dir_path("example-runner-wgpu-builder")
15-
.build()?;
8+
let path_to_crate = Path::new(env!("CARGO_MANIFEST_DIR")).join(path_to_crate);
9+
let mut builder = SpirvBuilder::new(path_to_crate, "spirv-unknown-vulkan1.1");
10+
builder.build_script.defaults = true;
11+
builder.build_script.env_shader_spv_path = Some(true);
12+
// Give this spirv-builder a unique target dir, so that rebuilding android and the main wgpu app's target dir
13+
// don't clash and break each other's incremental
14+
builder.target_dir_path = Some(PathBuf::from("example-runner-wgpu-builder"));
15+
let result = builder.build()?;
1616
if codegen_names {
1717
let out_dir = env::var_os("OUT_DIR").unwrap();
1818
let dest_path = Path::new(&out_dir).join("entry_points.rs");

examples/runners/wgpu/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ fn maybe_watch(
129129
) -> CompiledShaderModules {
130130
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
131131
{
132-
use spirv_builder::{CompileResult, MetadataPrintout, SpirvBuilder};
132+
use spirv_builder::{CompileResult, SpirvBuilder};
133133
use std::path::PathBuf;
134134

135135
let crate_name = match options.shader {
@@ -147,7 +147,6 @@ fn maybe_watch(
147147
let has_debug_printf = options.force_spirv_passthru;
148148

149149
let builder = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.1")
150-
.print_metadata(MetadataPrintout::None)
151150
.shader_panic_strategy(if has_debug_printf {
152151
spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
153152
print_inputs: true,

tests/difftests/lib/src/scaffold/shader/rust_gpu_shader.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ impl RustComputeShader {
3838
impl SpirvShader for RustComputeShader {
3939
fn spirv_bytes(&self) -> anyhow::Result<(Vec<u8>, String)> {
4040
let mut builder = SpirvBuilder::new(&self.path, &self.target)
41-
.print_metadata(spirv_builder::MetadataPrintout::None)
4241
.release(true)
4342
.multimodule(false)
4443
.shader_panic_strategy(spirv_builder::ShaderPanicStrategy::SilentExit)

0 commit comments

Comments
 (0)