Skip to content

Commit dd840d9

Browse files
committed
Fix the wrong removal of first linker arg in Windows. Linker argument file no longer include first program name argument. Small refactor of handling of linker response file.
1 parent 84efc00 commit dd840d9

File tree

3 files changed

+28
-12
lines changed

3 files changed

+28
-12
lines changed

packages/cli/src/build/request.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2201,7 +2201,7 @@ impl BuildRequest {
22012201
// And then remove the rest of the rlibs
22022202
//
22032203
// We also need to insert the -force_load flag to force the linker to load the archive
2204-
let mut args: Vec<_> = rustc_args.link_args.iter().skip(1).cloned().collect();
2204+
let mut args: Vec<_> = rustc_args.link_args.clone();
22052205
if let Some(last_object) = args.iter().rposition(|arg| arg.ends_with(".o")) {
22062206
if archive_has_contents {
22072207
match self.linker_flavor() {

packages/cli/src/cli/link.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

packages/cli/src/rustcwrapper.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ pub fn is_wrapping_rustc() -> bool {
2626
pub struct RustcArgs {
2727
pub args: Vec<String>,
2828
pub envs: Vec<(String, String)>,
29-
pub link_args: Vec<String>, // I don't believe this is used anymore
29+
/// it doesn't include first program name argument
30+
pub link_args: Vec<String>,
3031
}
3132

3233
/// Check if the arguments indicate a linking step, including those in command files.

0 commit comments

Comments
 (0)