Skip to content

Commit e7a928f

Browse files
committed
build_script: replace enum MetadataPrintout with struct BuildScriptConfig for more flexibility
1 parent 5719b27 commit e7a928f

File tree

4 files changed

+67
-56
lines changed

4 files changed

+67
-56
lines changed

crates/spirv-builder/src/lib.rs

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,10 @@ pub enum SpirvBuilderError {
123123
MissingTargetSpec,
124124
#[error("build failed")]
125125
BuildFailed,
126-
#[error("multi-module build cannot be used with print_metadata = MetadataPrintout::Full")]
127-
MultiModuleWithPrintMetadata,
126+
#[error(
127+
"`multimodule: true` build cannot be used together with `build_script.env_shader_spv_path: true`"
128+
)]
129+
MultiModuleWithEnvShaderSpvPath,
128130
#[error("multi-module metadata file missing")]
129131
MetadataFileMissing(#[from] std::io::Error),
130132
#[error("unable to parse multi-module metadata file")]
@@ -138,21 +140,6 @@ pub enum SpirvBuilderError {
138140

139141
const SPIRV_TARGET_PREFIX: &str = "spirv-unknown-";
140142

141-
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, serde::Deserialize, serde::Serialize)]
142-
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
143-
#[non_exhaustive]
144-
pub enum MetadataPrintout {
145-
/// Print no cargo metadata.
146-
#[default]
147-
None,
148-
/// Print only dependency information (eg for multiple modules).
149-
DependencyOnly,
150-
/// Print all cargo metadata.
151-
///
152-
/// Includes dependency information and spirv environment variable.
153-
Full,
154-
}
155-
156143
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, serde::Deserialize, serde::Serialize)]
157144
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
158145
#[non_exhaustive]
@@ -396,6 +383,48 @@ impl Default for ShaderCrateFeatures {
396383
}
397384
}
398385

386+
/// Configuration for build scripts
387+
#[derive(Clone, Debug, Default)]
388+
#[non_exhaustive]
389+
pub struct BuildScriptConfig {
390+
/// Enable this if you are using `spirv-builder` from a build script to apply some recommended default options, such
391+
/// as [`Self::dependency_info`].
392+
pub defaults: bool,
393+
394+
/// Print dependency information for cargo build scripts (with `cargo::rerun-if-changed={}` and such).
395+
/// Dependency information makes cargo rerun the build script is rerun when shader source files change, thus
396+
/// rebuilding the shader.
397+
///
398+
/// Default: [`Self::defaults`]
399+
pub dependency_info: Option<bool>,
400+
401+
/// Whether to emit the env var `SHADER_SPV_PATH` pointing to the shader module file (via `cargo::rustc-env={}`).
402+
/// Not supported together with `multimodule=true` or `.watch()`.
403+
///
404+
/// Some examples on how to include the shader module in the source code:
405+
/// * wgpu:
406+
/// ```norun
407+
/// let shader: ShaderModuleDescriptorPassthrough = include_spirv_raw!(env!("SHADER_SPV_PATH"));
408+
/// ```
409+
/// * ash
410+
/// ```norun
411+
/// let bytes: &[u8] = include_bytes!(env!("SHADER_SPV_PATH"))
412+
/// let words = ash::util::read_spv(&mut std::io::Cursor::new(bytes)).unwrap();
413+
/// ```
414+
///
415+
/// Default: `false`
416+
pub env_shader_spv_path: Option<bool>,
417+
}
418+
419+
impl BuildScriptConfig {
420+
fn dependency_info(&self) -> bool {
421+
self.dependency_info.unwrap_or(self.defaults)
422+
}
423+
fn env_shader_spv_path(&self) -> bool {
424+
self.env_shader_spv_path.unwrap_or(false)
425+
}
426+
}
427+
399428
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
400429
#[cfg_attr(feature = "clap", derive(clap::Parser))]
401430
#[non_exhaustive]
@@ -410,10 +439,10 @@ pub struct SpirvBuilder {
410439
/// `--crate-type dylib`. Defaults to true if `cargo_cmd` is `None` or `Some("rustc")`.
411440
#[cfg_attr(feature = "clap", clap(skip))]
412441
pub cargo_cmd_like_rustc: Option<bool>,
413-
/// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to [`MetadataPrintout::None`].
414-
/// Within build scripts, set it to [`MetadataPrintout::DependencyOnly`] or [`MetadataPrintout::Full`] to ensure the build script is rerun on code changes.
442+
/// Configuration for build scripts
415443
#[cfg_attr(feature = "clap", clap(skip))]
416-
pub print_metadata: MetadataPrintout,
444+
#[serde(skip)]
445+
pub build_script: BuildScriptConfig,
417446
/// Build in release. Defaults to true.
418447
#[cfg_attr(feature = "clap", clap(long = "debug", default_value = "true", action = clap::ArgAction::SetFalse))]
419448
pub release: bool,
@@ -507,7 +536,7 @@ impl Default for SpirvBuilder {
507536
path_to_crate: None,
508537
cargo_cmd: None,
509538
cargo_cmd_like_rustc: None,
510-
print_metadata: MetadataPrintout::default(),
539+
build_script: BuildScriptConfig::default(),
511540
release: true,
512541
target: None,
513542
deny_warnings: false,
@@ -548,13 +577,6 @@ impl SpirvBuilder {
548577
self
549578
}
550579

551-
/// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to [`MetadataPrintout::Full`].
552-
#[must_use]
553-
pub fn print_metadata(mut self, v: MetadataPrintout) -> Self {
554-
self.print_metadata = v;
555-
self
556-
}
557-
558580
#[must_use]
559581
pub fn deny_warnings(mut self, v: bool) -> Self {
560582
self.deny_warnings = v;
@@ -704,15 +726,12 @@ impl SpirvBuilder {
704726
/// in the result, as the environment variable for the path to the module will already be set.
705727
pub fn build(&self) -> Result<CompileResult, SpirvBuilderError> {
706728
let metadata_file = invoke_rustc(self)?;
707-
match self.print_metadata {
708-
MetadataPrintout::Full | MetadataPrintout::DependencyOnly => {
709-
leaf_deps(&metadata_file, |artifact| {
710-
println!("cargo:rerun-if-changed={artifact}");
711-
})
712-
// Close enough
713-
.map_err(SpirvBuilderError::MetadataFileMissing)?;
714-
}
715-
MetadataPrintout::None => (),
729+
if self.build_script.dependency_info() {
730+
leaf_deps(&metadata_file, |artifact| {
731+
println!("cargo:rerun-if-changed={artifact}");
732+
})
733+
// Close enough
734+
.map_err(SpirvBuilderError::MetadataFileMissing)?;
716735
}
717736
let metadata = self.parse_metadata_file(&metadata_file)?;
718737

@@ -731,17 +750,11 @@ impl SpirvBuilder {
731750
match &metadata.module {
732751
ModuleResult::SingleModule(spirv_module) => {
733752
assert!(!self.multimodule);
734-
let env_var = format!(
735-
"{}.spv",
736-
at.file_name()
737-
.unwrap()
738-
.to_str()
739-
.unwrap()
740-
.strip_suffix(ARTIFACT_SUFFIX)
741-
.unwrap()
742-
);
743-
if self.print_metadata == MetadataPrintout::Full {
744-
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
753+
if self.build_script.env_shader_spv_path() {
754+
println!(
755+
"cargo::rustc-env=SHADER_SPV_PATH={}",
756+
spirv_module.display()
757+
);
745758
}
746759
}
747760
ModuleResult::MultiModule(_) => {
@@ -839,8 +852,8 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
839852
}
840853
}
841854

842-
if (builder.print_metadata == MetadataPrintout::Full) && builder.multimodule {
843-
return Err(SpirvBuilderError::MultiModuleWithPrintMetadata);
855+
if builder.build_script.env_shader_spv_path() && builder.multimodule {
856+
return Err(SpirvBuilderError::MultiModuleWithEnvShaderSpvPath);
844857
}
845858
if !path_to_crate.is_dir() {
846859
return Err(SpirvBuilderError::CratePathDoesntExist(
@@ -905,7 +918,7 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
905918

906919
// Wrapper for `env::var` that appropriately informs Cargo of the dependency.
907920
let tracked_env_var_get = |name| {
908-
if let MetadataPrintout::Full | MetadataPrintout::DependencyOnly = builder.print_metadata {
921+
if builder.build_script.dependency_info() {
909922
println!("cargo:rerun-if-env-changed={name}");
910923
}
911924
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.env_shader_spv_path() {
5959
return Err(SpirvWatcherError::WatchWithPrintMetadata.into());
6060
}
6161

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/src/lib.rs

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

130130
let crate_name = match options.shader {
@@ -142,7 +142,6 @@ fn maybe_watch(
142142
let has_debug_printf = options.force_spirv_passthru;
143143

144144
let builder = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.1")
145-
.print_metadata(MetadataPrintout::None)
146145
.shader_panic_strategy(if has_debug_printf {
147146
spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
148147
print_inputs: true,

0 commit comments

Comments
 (0)