fix windows subsecond, add DX_LINKER and DX_HOST_LINKER env var overrides (#4164)

* fix: subsecond on windows

an off-by-one error and improper escaping for response files was causing windows to fail

this fixes that

* add linker selection
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2025-05-21 15:43:39 +01:00
1 parent 78e65f240c
commit 021c877361
2 files changed
+33 -57

No files matched your search

+31 -55
View File
@@ -1247,35 +1247,12 @@ impl BuildRequest {
//
// We dump its output directly into the patch exe location which is different than how rustc
// does it since it uses llvm-objcopy into the `target/debug/` folder.
let res = match cfg!(target_os = "windows") {
// Handle windows response files
// https://learn.microsoft.com/en-us/cpp/build/reference/at-specify-a-linker-response-file?view=msvc-170
true => {
let cmd_file = tempfile::NamedTempFile::new()?;
let mut contents = String::new();
for arg in object_files.iter() {
contents.push_str(&format!("{}\n", dunce::canonicalize(arg)?.display()));
}
for arg in self.thin_link_args(&args)? {
contents.push_str(&format!("{}\n", arg));
}
for arg in out_arg.iter() {
contents.push_str(&format!("{}\n", arg));
}
Command::new(linker)
.arg(format!("@{}", cmd_file.path().display()))
.output()
.await?
}
false => {
Command::new(linker)
.args(object_files.iter())
.args(self.thin_link_args(&args)?)
.args(out_arg)
.output()
.await?
}
};
let res = Command::new(linker)
.args(object_files.iter())
.args(self.thin_link_args(&args)?)
.args(out_arg)
.output()
.await?;
if !res.stderr.is_empty() {
let errs = String::from_utf8_lossy(&res.stderr);
@@ -1704,31 +1681,11 @@ impl BuildRequest {
_ => vec!["-o".to_string(), exe.display().to_string()],
};
let res = match cfg!(target_os = "windows") {
// Handle windows response files
// https://learn.microsoft.com/en-us/cpp/build/reference/at-specify-a-linker-response-file?view=msvc-170
true => {
let cmd_file = tempfile::NamedTempFile::new()?;
let mut contents = String::new();
for arg in args.iter().skip(1) {
contents.push_str(&format!("{}\n", arg));
}
for arg in out_arg.iter() {
contents.push_str(&format!("{}\n", arg));
}
Command::new(linker)
.arg(format!("@{}", cmd_file.path().display()))
.output()
.await?
}
false => {
Command::new(linker)
.args(args.iter().skip(1))
.args(out_arg)
.output()
.await?
}
};
let res = Command::new(linker)
.args(args.iter().skip(1))
.args(out_arg)
.output()
.await?;
if !res.stderr.is_empty() {
let errs = String::from_utf8_lossy(&res.stderr);
@@ -1761,6 +1718,20 @@ impl BuildRequest {
/// cause issues with a custom linker setup. In theory, rust translates most flags to the right
/// linker format.
fn select_linker(&self) -> Result<PathBuf, Error> {
// Use a custom linker for non-crosscompile and crosscompile targets
if matches!(
self.triple.operating_system,
OperatingSystem::Darwin(_) | OperatingSystem::Linux | OperatingSystem::Windows
) {
if let Ok(linker) = std::env::var("DX_HOST_LINKER") {
return Ok(PathBuf::from(linker));
}
}
if let Ok(linker) = std::env::var("DX_LINKER") {
return Ok(PathBuf::from(linker));
}
let cc = match self.triple.operating_system {
OperatingSystem::Unknown if self.platform == Platform::Web => self.workspace.wasm_ld(),
@@ -3594,9 +3565,14 @@ impl BuildRequest {
///
/// This might stop working if/when cargo stabilizes contents-based fingerprinting.
fn bust_fingerprint(&self, ctx: &BuildContext) -> Result<()> {
// if matches!(ctx.mode, BuildMode::Fat | BuildMode::Base) {
if !matches!(ctx.mode, BuildMode::Thin { .. }) {
std::fs::File::open(&self.crate_target.src_path)?.set_modified(SystemTime::now())?;
// read and write the file to update the mtime
if cfg!(target_os = "windows") {
let contents = std::fs::read_to_string(&self.crate_target.src_path)?;
_ = std::fs::write(&self.crate_target.src_path, contents);
}
}
Ok(())
}
+2 -2
View File
@@ -122,7 +122,7 @@ 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.
async fn run_link_inner(self) -> Result<()> {
let mut args: Vec<_> = std::env::args().skip(1).collect();
let mut args: Vec<_> = std::env::args().collect();
if args.is_empty() {
return Ok(());
}
@@ -140,7 +140,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),
false => cmd.args(args.iter().skip(1)),
};
let res = cmd.output().expect("Failed to run linker");