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. (#5010)

Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
qouteallandEvan Almloff authored and GitHub committed 2025-12-15 10:14:22 -06:00
1 parent 5929c09cec
commit da72b63b6f
3 files changed
+28 -12

No files matched your search

+1 -1
View File
@@ -2194,7 +2194,7 @@ impl BuildRequest {
// And then remove the rest of the rlibs
//
// We also need to insert the -force_load flag to force the linker to load the archive
let mut args: Vec<_> = rustc_args.link_args.iter().skip(1).cloned().collect();
let mut args: Vec<_> = rustc_args.link_args.clone();
if let Some(last_object) = args.iter().rposition(|arg| arg.ends_with(".o")) {
if archive_has_contents {
match self.linker_flavor() {
+25 -10
View File
@@ -127,12 +127,12 @@ impl LinkAction {
/// The file will be given by the dx-magic-link-arg env var itself, so we use
/// it both for determining if we should act as a linker and the for the file name itself.
fn run_link_inner(self) -> Result<()> {
let mut args: Vec<_> = std::env::args().collect();
let args: Vec<_> = std::env::args().collect();
if args.is_empty() {
return Ok(());
}
handle_linker_command_file(&mut args);
let mut args = get_actual_linker_args_excluding_program_name(args);
if self.triple.environment == target_lexicon::Environment::Android {
args.retain(|arg| !arg.ends_with(".lib"));
@@ -149,7 +149,7 @@ impl LinkAction {
let mut cmd = std::process::Command::new(linker);
match cfg!(target_os = "windows") {
true => cmd.arg(format!("@{}", &self.link_args_file.display())),
false => cmd.args(args.iter().skip(1)),
false => cmd.args(args),
};
let res = cmd.output().expect("Failed to run linker");
@@ -240,14 +240,22 @@ impl LinkAction {
}
}
pub fn handle_linker_command_file(args: &mut Vec<String>) {
// Handle command files, usually a windows thing.
if let Some(command) = args.iter().find(|arg| arg.starts_with('@')).cloned() {
let path = command.trim().trim_start_matches('@');
pub fn get_actual_linker_args_excluding_program_name(args: Vec<String>) -> Vec<String> {
args.into_iter()
.skip(1) // the first arg is program name
.flat_map(|arg| handle_linker_arg_response_file(arg).into_iter())
.collect()
}
// handle Windows linker response file. It's designed to workaround Windows command length limit.
// https://learn.microsoft.com/en-us/cpp/build/reference/at-specify-a-linker-response-file?view=msvc-170
pub fn handle_linker_arg_response_file(arg: String) -> Vec<String> {
if arg.starts_with('@') {
let path = arg.trim().trim_start_matches('@');
let file_binary = std::fs::read(path).unwrap();
// This may be a utf-16le file. Let's try utf-8 first.
let content = String::from_utf8(file_binary.clone()).unwrap_or_else(|_| {
let mut content = String::from_utf8(file_binary.clone()).unwrap_or_else(|_| {
// Convert Vec<u8> to Vec<u16> to convert into a String
let binary_u16le: Vec<u16> = file_binary
.chunks_exact(2)
@@ -257,8 +265,13 @@ pub fn handle_linker_command_file(args: &mut Vec<String>) {
String::from_utf16_lossy(&binary_u16le)
});
// Remove byte order mark in the beginning
if content.starts_with('\u{FEFF}') {
content.remove(0);
}
// Gather linker args, and reset the args to be just the linker args
*args = content
content
.lines()
.map(|line| {
let line_parsed = line.trim().to_string();
@@ -266,6 +279,8 @@ pub fn handle_linker_command_file(args: &mut Vec<String>) {
let line_parsed = line_parsed.trim_start_matches('"').to_string();
line_parsed
})
.collect();
.collect()
} else {
vec![arg]
}
}
+2 -1
View File
@@ -26,7 +26,8 @@ pub fn is_wrapping_rustc() -> bool {
pub struct RustcArgs {
pub args: Vec<String>,
pub envs: Vec<(String, String)>,
pub link_args: Vec<String>, // I don't believe this is used anymore
/// it doesn't include first program name argument
pub link_args: Vec<String>,
}
/// Check if the arguments indicate a linking step, including those in command files.