@@ -118,6 +118,8 @@ pub use rustc_codegen_spirv_types::{CompileResult, ModuleResult};
118118#[ derive( Debug ) ]
119119#[ non_exhaustive]
120120pub enum SpirvBuilderError {
121+ NonSpirvTarget { target : String } ,
122+ UnsupportedSpirvTargetEnv { target_env : String } ,
121123 CratePathDoesntExist ( PathBuf ) ,
122124 BuildFailed ,
123125 MultiModuleWithPrintMetadata ,
@@ -126,24 +128,49 @@ pub enum SpirvBuilderError {
126128 MetadataFileMalformed ( serde_json:: Error ) ,
127129}
128130
131+ const SPIRV_TARGET_PREFIX : & str = "spirv-unknown-" ;
132+
129133impl fmt:: Display for SpirvBuilderError {
130134 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
131135 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+ )
134141 }
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+ )
141154 }
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" )
144170 }
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" )
147174 }
148175 }
149176 }
@@ -453,6 +480,31 @@ impl SpirvBuilder {
453480 }
454481
455482 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+
456508 if ( self . print_metadata == MetadataPrintout :: Full ) && self . multimodule {
457509 return Err ( SpirvBuilderError :: MultiModuleWithPrintMetadata ) ;
458510 }
@@ -469,8 +521,10 @@ impl SpirvBuilder {
469521 at : & Path ,
470522 ) -> Result < CompileResult , SpirvBuilderError > {
471523 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 ) ?;
474528 match & metadata. module {
475529 ModuleResult :: SingleModule ( spirv_module) => {
476530 assert ! ( !self . multimodule) ;
@@ -691,10 +745,16 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
691745 "-Zbuild-std-features=compiler-builtins-mem" ,
692746 "--profile" ,
693747 profile,
694- "--target" ,
695- & * builder. target ,
696748 ] ) ;
697749
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+
698758 // NOTE(eddyb) see above how this is computed and why it might be missing.
699759 if let Some ( target_dir) = target_dir {
700760 cargo. arg ( "--target-dir" ) . arg ( target_dir) ;
0 commit comments