@@ -73,16 +73,16 @@ pub fn run(language: Language, program: &str) -> Result<Assert, Box<dyn Error>>
73
73
if msvc {
74
74
command = compiler. to_command ( ) ;
75
75
76
- command_add_compiler_flags ( & mut command, & variables) ;
76
+ command_add_compiler_flags ( & mut command, & variables, msvc ) ;
77
77
command_add_output_file ( & mut command, & output_path, msvc, compiler. is_like_clang ( ) ) ;
78
78
command. arg ( input_path. clone ( ) ) ;
79
- command . envs ( variables. clone ( ) ) ;
79
+ command_add_linker_flags_msvc ( & mut command , & variables) ;
80
80
} else {
81
81
command = Command :: new ( compiler. path ( ) ) ;
82
82
83
83
command. arg ( input_path. clone ( ) ) ; // the input must come first
84
84
command. args ( compiler. args ( ) ) ;
85
- command_add_compiler_flags ( & mut command, & variables) ;
85
+ command_add_compiler_flags ( & mut command, & variables, msvc ) ;
86
86
command_add_output_file ( & mut command, & output_path, msvc, compiler. is_like_clang ( ) ) ;
87
87
}
88
88
@@ -159,31 +159,48 @@ fn command_add_output_file(command: &mut Command, output_path: &PathBuf, msvc: b
159
159
}
160
160
}
161
161
162
- fn command_add_compiler_flags ( command : & mut Command , variables : & HashMap < String , String > ) {
163
- let get_env_flags = |env_name : & str | -> Vec < String > {
164
- variables
165
- . get ( env_name)
166
- . map ( |e| e. to_string ( ) )
167
- . ok_or_else ( || env:: var ( env_name) )
168
- . unwrap_or_default ( )
169
- . split_ascii_whitespace ( )
170
- . map ( |slice| slice. to_string ( ) )
171
- . collect ( )
172
- } ;
173
-
174
- command. args ( get_env_flags ( "CFLAGS" ) ) ;
175
- command. args ( get_env_flags ( "CPPFLAGS" ) ) ;
176
- command. args ( get_env_flags ( "CXXFLAGS" ) ) ;
177
-
178
- for linker_argument in get_env_flags ( "LDFLAGS" ) {
179
- command. arg ( format ! ( "-Wl,{}" , linker_argument) ) ;
162
+ fn get_env_flags ( variables : & HashMap < String , String > , env_name : & str ) -> Vec < String > {
163
+ variables
164
+ . get ( env_name)
165
+ . map ( |e| e. to_string ( ) )
166
+ . ok_or_else ( || env:: var ( env_name) )
167
+ . unwrap_or_default ( )
168
+ . split_ascii_whitespace ( )
169
+ . map ( |slice| slice. to_string ( ) )
170
+ . collect ( )
171
+ }
172
+
173
+ fn command_add_compiler_flags (
174
+ command : & mut Command ,
175
+ variables : & HashMap < String , String > ,
176
+ msvc : bool ,
177
+ ) {
178
+ command. args ( get_env_flags ( variables, "CFLAGS" ) ) ;
179
+ command. args ( get_env_flags ( variables, "CPPFLAGS" ) ) ;
180
+ command. args ( get_env_flags ( variables, "CXXFLAGS" ) ) ;
181
+
182
+ if !msvc {
183
+ for linker_argument in get_env_flags ( variables, "LDFLAGS" ) {
184
+ command. arg ( format ! ( "-Wl,{}" , linker_argument) ) ;
185
+ }
186
+ }
187
+ }
188
+
189
+ fn command_add_linker_flags_msvc ( command : & mut Command , variables : & HashMap < String , String > ) {
190
+ let linker_flags = get_env_flags ( variables, "LDFLAGS" ) ;
191
+ if !linker_flags. is_empty ( ) {
192
+ command. arg ( "/link" ) ;
193
+ for linker_argument in linker_flags {
194
+ command. arg ( linker_argument) ;
195
+ }
180
196
}
181
197
}
182
198
183
199
#[ cfg( test) ]
184
200
mod tests {
185
201
use super :: * ;
186
202
use crate :: predicates:: * ;
203
+ use std:: env:: { remove_var, set_var} ;
187
204
188
205
#[ test]
189
206
fn test_run_c ( ) {
@@ -203,6 +220,62 @@ mod tests {
203
220
. success ( )
204
221
. stdout ( predicate:: eq ( "Hello, World!\n " ) . normalize ( ) ) ;
205
222
}
223
+ #[ test]
224
+ fn test_run_c_ldflags ( ) {
225
+ let host = target_lexicon:: HOST . to_string ( ) ;
226
+ let msvc = host. contains ( "msvc" ) ;
227
+ if msvc {
228
+ // Use a linker flag to set the stack size and run a program that
229
+ // outputs its stack size. If the linker flags aren't set
230
+ // properly, the program will output the wrong value.
231
+
232
+ set_var ( "INLINE_C_RS_LDFLAGS" , "/STACK:0x40000" ) ;
233
+ run (
234
+ Language :: C ,
235
+ r#"
236
+ #include <Windows.h>
237
+
238
+ #include <stdio.h>
239
+
240
+ int main() {
241
+ ULONG_PTR stack_low_limit, stack_high_limit;
242
+ GetCurrentThreadStackLimits(&stack_low_limit, &stack_high_limit);
243
+ printf("%#llx", stack_high_limit-stack_low_limit);
244
+
245
+ return 0;
246
+ }
247
+ "# ,
248
+ )
249
+ . unwrap ( )
250
+ . success ( )
251
+ . stdout ( predicate:: eq ( "0x40000" ) . normalize ( ) ) ;
252
+
253
+ remove_var ( "INLINE_C_RS_LDFLAGS" ) ;
254
+ } else {
255
+ // Introduces a symbol using linker flags and builds a program that
256
+ // ODR uses that symbol. If the linker flags aren't set properly,
257
+ // there will be a linker error.
258
+
259
+ set_var ( "INLINE_C_RS_LDFLAGS" , "--defsym MY_SYMBOL=0x0" ) ;
260
+ run (
261
+ Language :: C ,
262
+ r#"
263
+ #include <stdio.h>
264
+
265
+ extern void* MY_SYMBOL;
266
+
267
+ int main() {
268
+ printf("%p", MY_SYMBOL);
269
+ return 0;
270
+ }
271
+ "# ,
272
+ )
273
+ . unwrap ( )
274
+ . success ( ) ;
275
+
276
+ remove_var ( "INLINE_C_RS_LDFLAGS" ) ;
277
+ }
278
+ }
206
279
207
280
#[ test]
208
281
fn test_run_cxx ( ) {
0 commit comments