@@ -76,11 +76,11 @@ mod watch;
7676
7777use raw_string:: { RawStr , RawString } ;
7878use serde:: Deserialize ;
79+ use std:: borrow:: Borrow ;
7980use std:: collections:: HashMap ;
8081use std:: env;
8182use std:: error:: Error ;
8283use std:: fmt;
83- use std:: fmt:: Write ;
8484use std:: fs:: File ;
8585use std:: io:: BufReader ;
8686use std:: path:: { Path , PathBuf } ;
@@ -362,6 +362,21 @@ fn find_rustc_codegen_spirv() -> PathBuf {
362362 panic ! ( "Could not find {} in library path" , filename) ;
363363}
364364
365+ /// Joins strings together while ensuring none of the strings contain the separator.
366+ // NOTE(eddyb) this intentionally consumes the `Vec` to limit accidental misuse.
367+ fn join_checking_for_separators ( strings : Vec < impl Borrow < str > > , sep : & str ) -> String {
368+ for s in & strings {
369+ let s = s. borrow ( ) ;
370+ assert ! (
371+ !s. contains( sep) ,
372+ "{:?} may not contain separator {:?}" ,
373+ s,
374+ sep
375+ ) ;
376+ }
377+ strings. join ( sep)
378+ }
379+
365380// Returns path to the metadata json.
366381fn invoke_rustc ( builder : & SpirvBuilder ) -> Result < PathBuf , SpirvBuilderError > {
367382 // Okay, this is a little bonkers: in a normal world, we'd have the user clone
@@ -374,7 +389,13 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
374389 // to copy cargo's understanding of library lookup and find the library and its full path.
375390 let rustc_codegen_spirv = find_rustc_codegen_spirv ( ) ;
376391
377- let mut llvm_args = Vec :: new ( ) ;
392+ let mut rustflags = vec ! [
393+ format!( "-Zcodegen-backend={}" , rustc_codegen_spirv. display( ) ) ,
394+ //FIXME: reintroduce v0 mangling, see issue #642
395+ "-Zsymbol-mangling-version=legacy" . to_string( ) ,
396+ ] ;
397+
398+ let mut llvm_args = vec ! [ ] ;
378399 if builder. multimodule {
379400 llvm_args. push ( "--module-output=multiple" ) ;
380401 }
@@ -399,47 +420,22 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
399420 if builder. skip_block_layout {
400421 llvm_args. push ( "--skip-block-layout" ) ;
401422 }
423+ let llvm_args = join_checking_for_separators ( llvm_args, " " ) ;
424+ if !llvm_args. is_empty ( ) {
425+ rustflags. push ( [ "-Cllvm-args=" , & llvm_args] . concat ( ) ) ;
426+ }
402427
403- let llvm_args = if llvm_args. is_empty ( ) {
404- String :: new ( )
405- } else {
406- // Cargo's handling of RUSTFLAGS is a little cursed. -Cllvm-args is documented as "The list
407- // must be separated by spaces", but if we set RUSTFLAGS='-C llvm-args="--foo --bar"', then
408- // cargo will pass -C 'llvm-args="--foo' '--bar"' to rustc. Like, really? c'mon.
409- // Thankfully, passing -C llvm-args multiple times appends to a list, instead of
410- // overwriting.
411- let mut result = String :: new ( ) ;
412- for arg in llvm_args {
413- write ! ( result, " -C llvm-args={}" , arg) . unwrap ( ) ;
414- }
415- result
416- } ;
417-
418- let mut target_features = Vec :: new ( ) ;
419-
428+ let mut target_features = vec ! [ ] ;
420429 target_features. extend ( builder. capabilities . iter ( ) . map ( |cap| format ! ( "+{:?}" , cap) ) ) ;
421430 target_features. extend ( builder. extensions . iter ( ) . map ( |ext| format ! ( "+ext:{}" , ext) ) ) ;
431+ let target_features = join_checking_for_separators ( target_features, "," ) ;
432+ if !target_features. is_empty ( ) {
433+ rustflags. push ( [ "-Ctarget-feature=" , & target_features] . concat ( ) ) ;
434+ }
422435
423- let feature_flag = if target_features. is_empty ( ) {
424- String :: new ( )
425- } else {
426- format ! ( " -C target-feature={}" , target_features. join( "," ) )
427- } ;
428-
429- let deny_warnings = if builder. deny_warnings {
430- " -D warnings"
431- } else {
432- ""
433- } ;
434-
435- //FIXME: reintroduce v0 mangling, see issue #642
436- let rustflags = format ! (
437- "-Z codegen-backend={} -Zsymbol-mangling-version=legacy{}{}{}" ,
438- rustc_codegen_spirv. display( ) ,
439- feature_flag,
440- llvm_args,
441- deny_warnings,
442- ) ;
436+ if builder. deny_warnings {
437+ rustflags. push ( "-Dwarnings" . to_string ( ) ) ;
438+ }
443439
444440 let mut cargo = Command :: new ( "cargo" ) ;
445441 cargo. args ( & [
@@ -477,10 +473,12 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
477473 }
478474 }
479475
476+ let cargo_encoded_rustflags = join_checking_for_separators ( rustflags, "\x1f " ) ;
477+
480478 let build = cargo
481479 . stderr ( Stdio :: inherit ( ) )
482480 . current_dir ( & builder. path_to_crate )
483- . env ( "RUSTFLAGS " , rustflags )
481+ . env ( "CARGO_ENCODED_RUSTFLAGS " , cargo_encoded_rustflags )
484482 . output ( )
485483 . expect ( "failed to execute cargo build" ) ;
486484
0 commit comments