diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 97dbc334fb0..8dce388c055 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -533,15 +533,28 @@ fn link_targets<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, format!("failed to remove: {}", dst.display()) })?; } - fs::hard_link(src, dst) - .or_else(|err| { - debug!("hard link failed {}. falling back to fs::copy", err); - fs::copy(src, dst).map(|_| ()) - }) - .chain_err(|| { + + let link_result = if src.is_dir() { + #[cfg(unix)] + use std::os::unix::fs::symlink; + #[cfg(target_os = "redox")] + use std::os::redox::fs::symlink; + #[cfg(windows)] + use std::os::windows::fs::symlink_dir as symlink; + + symlink(src, dst) + } else { + fs::hard_link(src, dst) + }; + link_result + .or_else(|err| { + debug!("link failed {}. falling back to fs::copy", err); + fs::copy(src, dst).map(|_| ()) + }) + .chain_err(|| { format!("failed to link or copy `{}` to `{}`", src.display(), dst.display()) - })?; + })?; } if json_messages { diff --git a/tests/build.rs b/tests/build.rs index 0e531486dcb..bee40601430 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -3877,6 +3877,13 @@ fn uplift_dsym_of_bin_on_mac() { ); assert_that(&p.bin("foo.dSYM"), existing_dir()); assert_that(&p.bin("b.dSYM"), existing_dir()); + assert!( + p.bin("b.dSYM") + .symlink_metadata() + .expect("read metadata from b.dSYM") + .file_type() + .is_symlink() + ); assert_that(&p.bin("c.dSYM"), is_not(existing_dir())); assert_that(&p.bin("d.dSYM"), is_not(existing_dir())); } diff --git a/tests/cargotest/support/paths.rs b/tests/cargotest/support/paths.rs index bf3b6d446cc..8a74fc0f61d 100644 --- a/tests/cargotest/support/paths.rs +++ b/tests/cargotest/support/paths.rs @@ -81,15 +81,14 @@ impl CargoPathExt for Path { } for file in t!(fs::read_dir(self)) { - let file = t!(file).path(); - - if file.is_dir() { - file.rm_rf(); + let file = t!(file); + if file.file_type().map(|m| m.is_dir()).unwrap_or(false) { + file.path().rm_rf(); } else { // On windows we can't remove a readonly file, and git will // often clone files as readonly. As a result, we have some // special logic to remove readonly files on windows. - do_op(&file, "remove file", |p| fs::remove_file(p)); + do_op(&file.path(), "remove file", |p| fs::remove_file(p)); } } do_op(self, "remove dir", |p| fs::remove_dir(p));