@@ -78,6 +78,7 @@ mod target_specs;
7878mod watch;
7979
8080use raw_string:: { RawStr , RawString } ;
81+ use semver:: Version ;
8182use serde:: Deserialize ;
8283use std:: borrow:: Borrow ;
8384use std:: collections:: HashMap ;
@@ -403,6 +404,9 @@ pub struct SpirvBuilder {
403404 // Overwrite the toolchain like `cargo +nightly`
404405 #[ cfg_attr( feature = "clap" , clap( skip) ) ]
405406 pub toolchain_overwrite : Option < String > ,
407+ // Set the rustc version of the toolchain, used to adjust params to support older toolchains
408+ #[ cfg_attr( feature = "clap" , clap( skip) ) ]
409+ pub toolchain_rustc_version : Option < Version > ,
406410
407411 /// The path of the "target specification" file.
408412 ///
@@ -460,6 +464,7 @@ impl Default for SpirvBuilder {
460464 path_to_target_spec : None ,
461465 target_dir_path : None ,
462466 toolchain_overwrite : None ,
467+ toolchain_rustc_version : None ,
463468 shader_panic_strategy : ShaderPanicStrategy :: default ( ) ,
464469 validator : ValidatorOptions :: default ( ) ,
465470 optimizer : OptimizerOptions :: default ( ) ,
@@ -781,6 +786,13 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
781786 }
782787 }
783788
789+ let toolchain_rustc_version =
790+ if let Some ( toolchain_rustc_version) = & builder. toolchain_rustc_version {
791+ toolchain_rustc_version. clone ( )
792+ } else {
793+ query_rustc_version ( builder. toolchain_overwrite . as_deref ( ) ) ?
794+ } ;
795+
784796 // Okay, this is a little bonkers: in a normal world, we'd have the user clone
785797 // rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
786798 // the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user
@@ -958,13 +970,21 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
958970
959971 // FIXME(eddyb) consider moving `target-specs` into `rustc_codegen_spirv_types`.
960972 // FIXME(eddyb) consider the `RUST_TARGET_PATH` env var alternative.
961- cargo
962- . arg ( "--target" )
963- . arg ( builder. path_to_target_spec . clone ( ) . unwrap_or_else ( || {
964- PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) )
965- . join ( "target-specs" )
966- . join ( format ! ( "{}.json" , target) )
967- } ) ) ;
973+
974+ // NOTE(firestar99) rustc 1.76 has been tested to correctly parse modern
975+ // target_spec jsons, some later version requires them, some earlier
976+ // version fails with them (notably our 0.9.0 release)
977+ if toolchain_rustc_version >= Version :: new ( 1 , 76 , 0 ) {
978+ cargo
979+ . arg ( "--target" )
980+ . arg ( builder. path_to_target_spec . clone ( ) . unwrap_or_else ( || {
981+ PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) )
982+ . join ( "target-specs" )
983+ . join ( format ! ( "{}.json" , target) )
984+ } ) ) ;
985+ } else {
986+ cargo. arg ( "--target" ) . arg ( target) ;
987+ }
968988
969989 if !builder. shader_crate_features . default_features {
970990 cargo. arg ( "--no-default-features" ) ;
@@ -1108,3 +1128,20 @@ fn leaf_deps(artifact: &Path, mut handle: impl FnMut(&RawStr)) -> std::io::Resul
11081128 recurse ( & deps_map, artifact. to_str ( ) . unwrap ( ) . into ( ) , & mut handle) ;
11091129 Ok ( ( ) )
11101130}
1131+
1132+ pub fn query_rustc_version ( toolchain : Option < & str > ) -> std:: io:: Result < Version > {
1133+ let mut cmd = Command :: new ( "rustc" ) ;
1134+ if let Some ( toolchain) = toolchain {
1135+ cmd. arg ( format ! ( "+{}" , toolchain) ) ;
1136+ }
1137+ cmd. arg ( "--version" ) ;
1138+
1139+ let parse = |stdout| {
1140+ let output = String :: from_utf8 ( stdout) . ok ( ) ?;
1141+ let output = output. strip_prefix ( "rustc " ) ?;
1142+ let version = & output[ ..output. find ( "-" ) ?] ;
1143+ Some ( Version :: parse ( version) . expect ( "invalid version" ) )
1144+ } ;
1145+
1146+ Ok ( parse ( cmd. output ( ) ?. stdout ) . expect ( "rustc --version parsing failed" ) )
1147+ }
0 commit comments