Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cli/src/build/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2201,7 +2201,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() {
Expand Down
35 changes: 25 additions & 10 deletions packages/cli/src/cli/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand All @@ -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");

Expand Down Expand Up @@ -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)
Expand All @@ -257,15 +265,22 @@ 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();
let line_parsed = line_parsed.trim_end_matches('"').to_string();
let line_parsed = line_parsed.trim_start_matches('"').to_string();
line_parsed
})
.collect();
.collect()
} else {
vec![arg]
}
}
3 changes: 2 additions & 1 deletion packages/cli/src/rustcwrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down