@@ -127,12 +127,12 @@ impl LinkAction {
127127 /// The file will be given by the dx-magic-link-arg env var itself, so we use
128128 /// it both for determining if we should act as a linker and the for the file name itself.
129129 fn run_link_inner ( self ) -> Result < ( ) > {
130- let mut args: Vec < _ > = std:: env:: args ( ) . collect ( ) ;
130+ let args: Vec < _ > = std:: env:: args ( ) . collect ( ) ;
131131 if args. is_empty ( ) {
132132 return Ok ( ( ) ) ;
133133 }
134134
135- handle_linker_command_file ( & mut args) ;
135+ let mut args = get_actual_linker_args_excluding_program_name ( args) ;
136136
137137 if self . triple . environment == target_lexicon:: Environment :: Android {
138138 args. retain ( |arg| !arg. ends_with ( ".lib" ) ) ;
@@ -149,7 +149,7 @@ impl LinkAction {
149149 let mut cmd = std:: process:: Command :: new ( linker) ;
150150 match cfg ! ( target_os = "windows" ) {
151151 true => cmd. arg ( format ! ( "@{}" , & self . link_args_file. display( ) ) ) ,
152- false => cmd. args ( args. iter ( ) . skip ( 1 ) ) ,
152+ false => cmd. args ( args) ,
153153 } ;
154154 let res = cmd. output ( ) . expect ( "Failed to run linker" ) ;
155155
@@ -240,14 +240,22 @@ impl LinkAction {
240240 }
241241}
242242
243- pub fn handle_linker_command_file ( args : & mut Vec < String > ) {
244- // Handle command files, usually a windows thing.
245- if let Some ( command) = args. iter ( ) . find ( |arg| arg. starts_with ( '@' ) ) . cloned ( ) {
246- let path = command. trim ( ) . trim_start_matches ( '@' ) ;
243+ pub fn get_actual_linker_args_excluding_program_name ( args : Vec < String > ) -> Vec < String > {
244+ args. into_iter ( )
245+ . skip ( 1 ) // the first arg is program name
246+ . flat_map ( |arg| handle_linker_arg_response_file ( arg) . into_iter ( ) )
247+ . collect ( )
248+ }
249+
250+ // handle Windows linker response file. It's designed to workaround Windows command length limit.
251+ // https://learn.microsoft.com/en-us/cpp/build/reference/at-specify-a-linker-response-file?view=msvc-170
252+ pub fn handle_linker_arg_response_file ( arg : String ) -> Vec < String > {
253+ if arg. starts_with ( '@' ) {
254+ let path = arg. trim ( ) . trim_start_matches ( '@' ) ;
247255 let file_binary = std:: fs:: read ( path) . unwrap ( ) ;
248256
249257 // This may be a utf-16le file. Let's try utf-8 first.
250- let content = String :: from_utf8 ( file_binary. clone ( ) ) . unwrap_or_else ( |_| {
258+ let mut content = String :: from_utf8 ( file_binary. clone ( ) ) . unwrap_or_else ( |_| {
251259 // Convert Vec<u8> to Vec<u16> to convert into a String
252260 let binary_u16le: Vec < u16 > = file_binary
253261 . chunks_exact ( 2 )
@@ -257,15 +265,22 @@ pub fn handle_linker_command_file(args: &mut Vec<String>) {
257265 String :: from_utf16_lossy ( & binary_u16le)
258266 } ) ;
259267
268+ // Remove byte order mark in the beginning
269+ if content. starts_with ( '\u{FEFF}' ) {
270+ content. remove ( 0 ) ;
271+ }
272+
260273 // Gather linker args, and reset the args to be just the linker args
261- * args = content
274+ content
262275 . lines ( )
263276 . map ( |line| {
264277 let line_parsed = line. trim ( ) . to_string ( ) ;
265278 let line_parsed = line_parsed. trim_end_matches ( '"' ) . to_string ( ) ;
266279 let line_parsed = line_parsed. trim_start_matches ( '"' ) . to_string ( ) ;
267280 line_parsed
268281 } )
269- . collect ( ) ;
282+ . collect ( )
283+ } else {
284+ vec ! [ arg]
270285 }
271286}
0 commit comments