Skip to content

Commit 027ab62

Browse files
committed
Auto merge of #7268 - benesch:dsym-uplifting, r=alexcrichton
Fix dSYM uplifting when symlink is broken We were sporadically but persistently seeing errors like failed to link or copy `.../target/debugs/deps/bin-264030cd6c8a02be.dSYM` to `.../target/debug/bin.dSYM` Caused by: the source path is not an existing regular file while running `cargo build`. Once the error occurs once, `cargo build` will fail forever with the same error until `target/debug/bin.dSYM` is manually unlinked. After some investigation, I've determined that this situation arises when the target of `bin.dSYM` goes missing. For example, if bin.dSYM is pointing at `deps/bin-86908f0fa7f1440e.dSYM`, and `deps/bin-86908f0fa7f1440e.dSYM` does not exist, then this error will occur. I'm still not clear on why the underlying dSYM bundle sporadically goes missing--perhaps it's the result of pressing Ctrl-C at the wrong moment?--but Cargo should at least be able to handle this situation better. It turns out that Cargo was getting confused by the broken symlink. When it goes to install the new `target/debug/bin.dSYM` link, it will remove the existing `target/debug/bin.dSYM` file, if it exists. Unfortunately, Cargo was checking whether the *target* of that symlink existed (e.g., `deps/bin-86908f0fa7f1440e.dSYM`, which in the buggy case would not exist), rather than the symlink itself, deciding that there was no existing symlink to remove, and crashing with EEXIST when trying to install the new symlink. This commit adjusts the existence check to evaluate whether the symlink itself exists, rather than its target. Note that while the symptoms are the same as #4671, the root cause is unrelated.
2 parents 3f700ec + b03eeda commit 027ab62

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

src/cargo/core/compiler/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,12 @@ fn hardlink_or_copy(src: &Path, dst: &Path) -> CargoResult<()> {
486486
if is_same_file(src, dst).unwrap_or(false) {
487487
return Ok(());
488488
}
489-
if dst.exists() {
489+
490+
// NB: we can't use dst.exists(), as if dst is a broken symlink,
491+
// dst.exists() will return false. This is problematic, as we still need to
492+
// unlink dst in this case. symlink_metadata(dst).is_ok() will tell us
493+
// whether dst exists *without* following symlinks, which is what we want.
494+
if fs::symlink_metadata(dst).is_ok() {
490495
paths::remove_file(&dst)?;
491496
}
492497

tests/testsuite/build.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4167,6 +4167,34 @@ fn uplift_dsym_of_bin_on_mac() {
41674167
assert!(!p.target_debug_dir().join("d.dSYM").exists());
41684168
}
41694169

4170+
#[cargo_test]
4171+
#[cfg(any(target_os = "macos", target_os = "ios"))]
4172+
fn uplift_dsym_of_bin_on_mac_when_broken_link_exists() {
4173+
let p = project()
4174+
.file("src/main.rs", "fn main() { panic!(); }")
4175+
.build();
4176+
let dsym = p.target_debug_dir().join("foo.dSYM");
4177+
4178+
p.cargo("build").run();
4179+
assert!(dsym.is_dir());
4180+
4181+
// Simulate the situation where the underlying dSYM bundle goes missing
4182+
// but the uplifted symlink to it remains. This would previously cause
4183+
// builds to permanently fail until the bad symlink was manually removed.
4184+
dsym.rm_rf();
4185+
p.symlink(
4186+
p.target_debug_dir()
4187+
.join("deps")
4188+
.join("foo-baaaaaadbaaaaaad.dSYM"),
4189+
&dsym,
4190+
);
4191+
assert!(dsym.is_symlink());
4192+
assert!(!dsym.exists());
4193+
4194+
p.cargo("build").run();
4195+
assert!(dsym.is_dir());
4196+
}
4197+
41704198
#[cargo_test]
41714199
#[cfg(all(target_os = "windows", target_env = "msvc"))]
41724200
fn uplift_pdb_of_bin_on_windows() {

0 commit comments

Comments
 (0)