@@ -21,6 +21,7 @@ pub struct RustcArgs {
2121 pub out_dir : Option < PathBuf > ,
2222 pub target : Option < String > ,
2323 pub print : Vec < String > ,
24+ pub codegen : Vec < String > ,
2425}
2526
2627impl RustcArgs {
@@ -35,6 +36,29 @@ impl RustcArgs {
3536 }
3637 result
3738 }
39+
40+ /// Normally `rustc` uses a C compiler such as `cc` or `clang` as linker,
41+ /// and arguments to the actual linker need to be passed prefixed with `-Wl,`.
42+ /// But it is possible to configure Cargo and rustc to call a linker directly,
43+ /// and the breakage it causes is subtle enough that people just roll with it
44+ /// and complain when cargo-auditable doesn't support this configuration:
45+ /// <https://github.com/rust-secure-code/cargo-auditable/issues/202>
46+ ///
47+ /// This function can tell you if a bare linker is in use
48+ /// and whether you need to prepend `-Wl,` or not.
49+ ///
50+ /// Such setups are exceptionally rare and frankly it's a misconfiguration
51+ /// that will break more than just `cargo auditable`, but I am feeling generous.
52+ pub fn bare_linker ( & self ) -> bool {
53+ let linker_flag = self . codegen . iter ( ) . find ( |s| s. starts_with ( "linker=" ) ) ;
54+ if let Some ( linker_flag) = linker_flag {
55+ let linker = linker_flag. strip_prefix ( "linker=" ) . unwrap ( ) ;
56+ if linker. ends_with ( "ld" ) {
57+ return true ;
58+ }
59+ }
60+ false
61+ }
3862}
3963
4064impl RustcArgs {
@@ -62,6 +86,7 @@ impl RustcArgs {
6286 } ) ?,
6387 target : parser. opt_value_from_str ( "--target" ) ?,
6488 print : parser. values_from_str ( "--print" ) ?,
89+ codegen : parser. values_from_str ( "-C" ) ?,
6590 } )
6691 }
6792}
@@ -147,16 +172,7 @@ mod tests {
147172
148173 #[ test]
149174 fn multiple_emit_values ( ) {
150- let raw_rustc_args = vec ! [
151- "--emit=dep-info,link" ,
152- "--emit" ,
153- "llvm-bc" ,
154- // end of interesting args, start of boilerplate
155- "--crate-name" ,
156- "foobar" ,
157- "--out-dir" ,
158- "/foo/bar" ,
159- ] ;
175+ let raw_rustc_args = vec ! [ "--emit=dep-info,link" , "--emit" , "llvm-bc" ] ;
160176 let raw_rustc_args: Vec < OsString > = raw_rustc_args. into_iter ( ) . map ( |s| s. into ( ) ) . collect ( ) ;
161177 let mut args = RustcArgs :: from_vec ( raw_rustc_args) . unwrap ( ) ;
162178
@@ -168,4 +184,29 @@ mod tests {
168184
169185 assert_eq ! ( args. emit, expected)
170186 }
187+
188+ #[ test]
189+ fn detect_bare_linker ( ) {
190+ let raw_rustc_args = vec ! [ "-C" , "linker=rust-lld" ] ;
191+ let raw_rustc_args: Vec < OsString > = raw_rustc_args. into_iter ( ) . map ( |s| s. into ( ) ) . collect ( ) ;
192+ let args = RustcArgs :: from_vec ( raw_rustc_args) . unwrap ( ) ;
193+ assert ! ( args. bare_linker( ) ) ;
194+ }
195+
196+ #[ test]
197+ fn multiple_codegen_options ( ) {
198+ let raw_rustc_args = vec ! [ "-Clinker=clang" , "-C" , "link-arg=-fuse-ld=/usr/bin/mold" ] ;
199+ let raw_rustc_args: Vec < OsString > = raw_rustc_args. into_iter ( ) . map ( |s| s. into ( ) ) . collect ( ) ;
200+ let mut args = RustcArgs :: from_vec ( raw_rustc_args) . unwrap ( ) ;
201+
202+ let expected = vec ! [ "linker=clang" , "link-arg=-fuse-ld=/usr/bin/mold" ] ;
203+ let mut expected: Vec < String > = expected. into_iter ( ) . map ( |s| s. into ( ) ) . collect ( ) ;
204+
205+ args. codegen . sort ( ) ;
206+ expected. sort ( ) ;
207+
208+ assert_eq ! ( args. codegen, expected) ;
209+
210+ assert ! ( !args. bare_linker( ) ) ;
211+ }
171212}
0 commit comments