@@ -78,6 +78,7 @@ mod target_specs;
78
78
mod watch;
79
79
80
80
use raw_string:: { RawStr , RawString } ;
81
+ use semver:: Version ;
81
82
use serde:: Deserialize ;
82
83
use std:: borrow:: Borrow ;
83
84
use std:: collections:: HashMap ;
@@ -403,6 +404,9 @@ pub struct SpirvBuilder {
403
404
// Overwrite the toolchain like `cargo +nightly`
404
405
#[ cfg_attr( feature = "clap" , clap( skip) ) ]
405
406
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 > ,
406
410
407
411
/// The path of the "target specification" file.
408
412
///
@@ -460,6 +464,7 @@ impl Default for SpirvBuilder {
460
464
path_to_target_spec : None ,
461
465
target_dir_path : None ,
462
466
toolchain_overwrite : None ,
467
+ toolchain_rustc_version : None ,
463
468
shader_panic_strategy : ShaderPanicStrategy :: default ( ) ,
464
469
validator : ValidatorOptions :: default ( ) ,
465
470
optimizer : OptimizerOptions :: default ( ) ,
@@ -781,6 +786,13 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
781
786
}
782
787
}
783
788
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
+
784
796
// Okay, this is a little bonkers: in a normal world, we'd have the user clone
785
797
// rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
786
798
// 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> {
958
970
959
971
// FIXME(eddyb) consider moving `target-specs` into `rustc_codegen_spirv_types`.
960
972
// 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
+ }
968
988
969
989
if !builder. shader_crate_features . default_features {
970
990
cargo. arg ( "--no-default-features" ) ;
@@ -1108,3 +1128,20 @@ fn leaf_deps(artifact: &Path, mut handle: impl FnMut(&RawStr)) -> std::io::Resul
1108
1128
recurse ( & deps_map, artifact. to_str ( ) . unwrap ( ) . into ( ) , & mut handle) ;
1109
1129
Ok ( ( ) )
1110
1130
}
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