Skip to content
Open
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
48 changes: 46 additions & 2 deletions packages/cli/src/build/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,10 @@ impl BuildRequest {
out_args.extend(out_arg.iter().map(Into::into));

if cfg!(windows) {
let linker_flavor = self.linker_flavor();
let cmd_contents: String = out_args
.iter()
.map(|s| format!("\"{}\"", s.to_string_lossy()))
.map(|s| quote_linker_command_file_argument(&s.to_string_lossy(), &linker_flavor))
.join(" ");
std::fs::write(self.windows_command_file(), cmd_contents)
.context("Failed to write linker command file")?;
Expand Down Expand Up @@ -1144,7 +1145,11 @@ impl BuildRequest {
// Handle windows command files
let mut out_args = args.clone();
if cfg!(windows) {
let cmd_contents: String = out_args.iter().map(|f| format!("\"{f}\"")).join(" ");
let linker_flavor = self.linker_flavor();
let cmd_contents: String = out_args
.iter()
.map(|arg| quote_linker_command_file_argument(arg, &linker_flavor))
.join(" ");
std::fs::write(self.windows_command_file(), cmd_contents)
.context("Failed to write linker command file")?;
out_args = vec![format!("@{}", self.windows_command_file().display())];
Expand Down Expand Up @@ -1485,6 +1490,45 @@ impl BuildRequest {
}
}

fn quote_linker_command_file_argument(arg: &str, linker_flavor: &LinkerFlavor) -> String {
let arg = if linker_flavor == &LinkerFlavor::Msvc {
arg.to_owned()
} else {
arg.replace('\\', "\\\\").replace('"', "\\\"")
};
format!("\"{arg}\"")
}

#[cfg(test)]
mod linker_response_file_tests {
use super::*;

#[test]
fn response_file_arguments_use_the_target_linker_quoting() {
assert_eq!(
quote_linker_command_file_argument(
r#"C:\Users\me\objects with spaces\file.o"#,
&LinkerFlavor::Gnu,
),
r#""C:\\Users\\me\\objects with spaces\\file.o""#
);
assert_eq!(
quote_linker_command_file_argument(
r#"C:\path\with spaces "quoted".o"#,
&LinkerFlavor::Darwin,
),
r#""C:\\path\\with spaces \"quoted\".o""#
);
assert_eq!(
quote_linker_command_file_argument(
r#"C:\Users\me\objects with spaces\file.o"#,
&LinkerFlavor::Msvc,
),
r#""C:\Users\me\objects with spaces\file.o""#
);
}
}

/// Reconstruct the dep-info `.d` path that rustc will write for an invocation, by parsing the
/// `--out-dir`, `--crate-name`, and `-C extra-filename=` from the captured args. This mirrors
/// rustc's own naming convention: `<out_dir>/<crate_name><extra_filename>.d`.
Expand Down
Loading