瀏覽代碼

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
Jonathan Kelley 1 月之前
父節點
當前提交
021c877361
共有 2 個文件被更改,包括 33 次插入57 次删除
  1. 31 55
      packages/cli/src/build/request.rs
  2. 2 2
      packages/cli/src/cli/link.rs

+ 31 - 55
packages/cli/src/build/request.rs

@@ -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
packages/cli/src/cli/link.rs

@@ -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");