@@ -118,6 +118,8 @@ pub use rustc_codegen_spirv_types::{CompileResult, ModuleResult};
118
118
#[ derive( Debug ) ]
119
119
#[ non_exhaustive]
120
120
pub enum SpirvBuilderError {
121
+ NonSpirvTarget { target : String } ,
122
+ UnsupportedSpirvTargetEnv { target_env : String } ,
121
123
CratePathDoesntExist ( PathBuf ) ,
122
124
BuildFailed ,
123
125
MultiModuleWithPrintMetadata ,
@@ -126,24 +128,49 @@ pub enum SpirvBuilderError {
126
128
MetadataFileMalformed ( serde_json:: Error ) ,
127
129
}
128
130
131
+ const SPIRV_TARGET_PREFIX : & str = "spirv-unknown-" ;
132
+
129
133
impl fmt:: Display for SpirvBuilderError {
130
134
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
131
135
match self {
132
- SpirvBuilderError :: CratePathDoesntExist ( path) => {
133
- write ! ( f, "Crate path {} does not exist" , path. display( ) )
136
+ Self :: NonSpirvTarget { target } => {
137
+ write ! (
138
+ f,
139
+ "expected `{SPIRV_TARGET_PREFIX}...` target, found `{target}`"
140
+ )
134
141
}
135
- SpirvBuilderError :: BuildFailed => f. write_str ( "Build failed" ) ,
136
- SpirvBuilderError :: MultiModuleWithPrintMetadata => f. write_str (
137
- "Multi-module build cannot be used with print_metadata = MetadataPrintout::Full" ,
138
- ) ,
139
- SpirvBuilderError :: WatchWithPrintMetadata => {
140
- f. write_str ( "Watching within build scripts will prevent build completion" )
142
+ Self :: UnsupportedSpirvTargetEnv { target_env } if target_env. starts_with ( "opencl" ) => {
143
+ write ! (
144
+ f,
145
+ "OpenCL targets like `{SPIRV_TARGET_PREFIX}-{target_env}` are not supported"
146
+ )
147
+ }
148
+ Self :: UnsupportedSpirvTargetEnv { target_env } if target_env. starts_with ( "webgpu" ) => {
149
+ write ! (
150
+ f,
151
+ "WebGPU targets like `{SPIRV_TARGET_PREFIX}-{target_env}` are not supported, \
152
+ consider using `{SPIRV_TARGET_PREFIX}-vulkan1.0` instead"
153
+ )
141
154
}
142
- SpirvBuilderError :: MetadataFileMissing ( _) => {
143
- f. write_str ( "Multi-module metadata file missing" )
155
+ Self :: UnsupportedSpirvTargetEnv { target_env } => {
156
+ write ! (
157
+ f,
158
+ "SPIR-V target `{SPIRV_TARGET_PREFIX}-{target_env}` is not supported"
159
+ )
160
+ }
161
+ Self :: CratePathDoesntExist ( path) => {
162
+ write ! ( f, "crate path {} does not exist" , path. display( ) )
163
+ }
164
+ Self :: BuildFailed => f. write_str ( "build failed" ) ,
165
+ Self :: MultiModuleWithPrintMetadata => f. write_str (
166
+ "multi-module build cannot be used with print_metadata = MetadataPrintout::Full" ,
167
+ ) ,
168
+ Self :: WatchWithPrintMetadata => {
169
+ f. write_str ( "watching within build scripts will prevent build completion" )
144
170
}
145
- SpirvBuilderError :: MetadataFileMalformed ( _) => {
146
- f. write_str ( "Unable to parse multi-module metadata file" )
171
+ Self :: MetadataFileMissing ( _) => f. write_str ( "multi-module metadata file missing" ) ,
172
+ Self :: MetadataFileMalformed ( _) => {
173
+ f. write_str ( "unable to parse multi-module metadata file" )
147
174
}
148
175
}
149
176
}
@@ -453,6 +480,31 @@ impl SpirvBuilder {
453
480
}
454
481
455
482
pub ( crate ) fn validate_running_conditions ( & mut self ) -> Result < ( ) , SpirvBuilderError > {
483
+ let target_env = self
484
+ . target
485
+ . strip_prefix ( SPIRV_TARGET_PREFIX )
486
+ . ok_or_else ( || SpirvBuilderError :: NonSpirvTarget {
487
+ target : self . target . clone ( ) ,
488
+ } ) ?;
489
+ // HACK(eddyb) used only to split the full list into groups.
490
+ #[ allow( clippy:: match_same_arms) ]
491
+ match target_env {
492
+ // HACK(eddyb) hardcoded list to avoid checking if the JSON file
493
+ // for a particular target exists (and sanitizing strings for paths).
494
+ //
495
+ // FIXME(eddyb) consider moving this list, or even `target-specs`,
496
+ // into `rustc_codegen_spirv_types`'s code/source.
497
+ "spv1.0" | "spv1.1" | "spv1.2" | "spv1.3" | "spv1.4" | "spv1.5" => { }
498
+ "opengl4.0" | "opengl4.1" | "opengl4.2" | "opengl4.3" | "opengl4.5" => { }
499
+ "vulkan1.0" | "vulkan1.1" | "vulkan1.1spv1.4" | "vulkan1.2" => { }
500
+
501
+ _ => {
502
+ return Err ( SpirvBuilderError :: UnsupportedSpirvTargetEnv {
503
+ target_env : target_env. into ( ) ,
504
+ } ) ;
505
+ }
506
+ }
507
+
456
508
if ( self . print_metadata == MetadataPrintout :: Full ) && self . multimodule {
457
509
return Err ( SpirvBuilderError :: MultiModuleWithPrintMetadata ) ;
458
510
}
@@ -469,8 +521,10 @@ impl SpirvBuilder {
469
521
at : & Path ,
470
522
) -> Result < CompileResult , SpirvBuilderError > {
471
523
let metadata_contents = File :: open ( at) . map_err ( SpirvBuilderError :: MetadataFileMissing ) ?;
472
- let metadata: CompileResult = serde_json:: from_reader ( BufReader :: new ( metadata_contents) )
473
- . map_err ( SpirvBuilderError :: MetadataFileMalformed ) ?;
524
+ // FIXME(eddyb) move this functionality into `rustc_codegen_spirv_types`.
525
+ let metadata: CompileResult =
526
+ rustc_codegen_spirv_types:: serde_json:: from_reader ( BufReader :: new ( metadata_contents) )
527
+ . map_err ( SpirvBuilderError :: MetadataFileMalformed ) ?;
474
528
match & metadata. module {
475
529
ModuleResult :: SingleModule ( spirv_module) => {
476
530
assert ! ( !self . multimodule) ;
@@ -691,10 +745,16 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
691
745
"-Zbuild-std-features=compiler-builtins-mem" ,
692
746
"--profile" ,
693
747
profile,
694
- "--target" ,
695
- & * builder. target ,
696
748
] ) ;
697
749
750
+ // FIXME(eddyb) consider moving `target-specs` into `rustc_codegen_spirv_types`.
751
+ // FIXME(eddyb) consider the `RUST_TARGET_PATH` env var alternative.
752
+ cargo. arg ( "--target" ) . arg (
753
+ Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) )
754
+ . join ( "target-specs" )
755
+ . join ( & format ! ( "{}.json" , builder. target) ) ,
756
+ ) ;
757
+
698
758
// NOTE(eddyb) see above how this is computed and why it might be missing.
699
759
if let Some ( target_dir) = target_dir {
700
760
cargo. arg ( "--target-dir" ) . arg ( target_dir) ;
0 commit comments