Skip to content

Commit 62085f0

Browse files
authored
Merge pull request #1253 from dtolnay/symlinks
Fix symlink paths during copy on Windows
2 parents 7122547 + af1a534 commit 62085f0

File tree

3 files changed

+57
-24
lines changed

3 files changed

+57
-24
lines changed

gen/build/src/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ fn make_crate_dir(prj: &Project) -> PathBuf {
369369
let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
370370
let ref link = crate_dir.join(&prj.include_prefix);
371371
let ref manifest_dir = prj.manifest_dir;
372-
if out::symlink_dir(manifest_dir, link).is_err() && cfg!(not(unix)) {
372+
if out::relative_symlink_dir(manifest_dir, link).is_err() && cfg!(not(unix)) {
373373
let cachedir_tag = "\
374374
Signature: 8a477f597d28d172789f06886806bc55\n\
375375
# This file is a cache directory tag created by cxx.\n\
@@ -386,11 +386,11 @@ fn make_include_dir(prj: &Project) -> Result<PathBuf> {
386386
let cxx_h = include_dir.join("rust").join("cxx.h");
387387
let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
388388
if let Some(ref original) = env::var_os("DEP_CXXBRIDGE1_HEADER") {
389-
out::symlink_file(original, cxx_h)?;
390-
out::symlink_file(original, shared_cxx_h)?;
389+
out::absolute_symlink_file(original, cxx_h)?;
390+
out::absolute_symlink_file(original, shared_cxx_h)?;
391391
} else {
392392
out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
393-
out::symlink_file(shared_cxx_h, cxx_h)?;
393+
out::relative_symlink_file(shared_cxx_h, cxx_h)?;
394394
}
395395
Ok(include_dir)
396396
}
@@ -414,7 +414,7 @@ fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) ->
414414
out::write(header_path, &generated.header)?;
415415

416416
let ref link_path = include_dir.join(rel_path);
417-
let _ = out::symlink_file(header_path, link_path);
417+
let _ = out::relative_symlink_file(header_path, link_path);
418418

419419
let ref rel_path_cc = rel_path.with_appended_extension(".cc");
420420
let ref implementation_path = sources_dir.join(rel_path_cc);
@@ -423,8 +423,8 @@ fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) ->
423423

424424
let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
425425
let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
426-
let _ = out::symlink_file(header_path, shared_h);
427-
let _ = out::symlink_file(implementation_path, shared_cc);
426+
let _ = out::relative_symlink_file(header_path, shared_h);
427+
let _ = out::relative_symlink_file(implementation_path, shared_cc);
428428
Ok(())
429429
}
430430

gen/build/src/out.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,41 @@ pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
2929
}
3030
}
3131

32-
pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
32+
pub(crate) fn relative_symlink_file(
33+
original: impl AsRef<Path>,
34+
link: impl AsRef<Path>,
35+
) -> Result<()> {
3336
let original = original.as_ref();
3437
let link = link.as_ref();
3538

36-
let original = best_effort_relativize_symlink(original, link);
39+
let relativized = best_effort_relativize_symlink(original, link);
3740

41+
symlink_file(&relativized, original, link)
42+
}
43+
44+
pub(crate) fn absolute_symlink_file(
45+
original: impl AsRef<Path>,
46+
link: impl AsRef<Path>,
47+
) -> Result<()> {
48+
let original = original.as_ref();
49+
let link = link.as_ref();
50+
51+
symlink_file(original, original, link)
52+
}
53+
54+
pub(crate) fn relative_symlink_dir(
55+
original: impl AsRef<Path>,
56+
link: impl AsRef<Path>,
57+
) -> Result<()> {
58+
let original = original.as_ref();
59+
let link = link.as_ref();
60+
61+
let relativized = best_effort_relativize_symlink(original, link);
62+
63+
symlink_dir(&relativized, link)
64+
}
65+
66+
fn symlink_file(path_for_symlink: &Path, path_for_copy: &Path, link: &Path) -> Result<()> {
3867
let mut create_dir_error = None;
3968
if fs::exists(link) {
4069
best_effort_remove(link);
@@ -43,7 +72,7 @@ pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -
4372
create_dir_error = fs::create_dir_all(parent).err();
4473
}
4574

46-
match paths::symlink_or_copy(original, link) {
75+
match paths::symlink_or_copy(path_for_symlink, path_for_copy, link) {
4776
// As long as symlink_or_copy succeeded, ignore any create_dir_all error.
4877
Ok(()) => Ok(()),
4978
Err(err) => {
@@ -65,12 +94,7 @@ pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -
6594
}
6695
}
6796

68-
pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
69-
let original = original.as_ref();
70-
let link = link.as_ref();
71-
72-
let original = best_effort_relativize_symlink(original, link);
73-
97+
fn symlink_dir(path_for_symlink: &Path, link: &Path) -> Result<()> {
7498
let mut create_dir_error = None;
7599
if fs::exists(link) {
76100
best_effort_remove(link);
@@ -79,7 +103,7 @@ pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) ->
79103
create_dir_error = fs::create_dir_all(parent).err();
80104
}
81105

82-
match fs::symlink_dir(original, link) {
106+
match fs::symlink_dir(path_for_symlink, link) {
83107
// As long as symlink_dir succeeded, ignore any create_dir_all error.
84108
Ok(()) => Ok(()),
85109
// If create_dir_all and symlink_dir both failed, prefer the first error.

gen/build/src/paths.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,37 @@ impl PathExt for Path {
4040
}
4141

4242
#[cfg(unix)]
43-
pub(crate) use self::fs::symlink_file as symlink_or_copy;
43+
pub(crate) fn symlink_or_copy(
44+
path_for_symlink: impl AsRef<Path>,
45+
_path_for_copy: impl AsRef<Path>,
46+
link: impl AsRef<Path>,
47+
) -> fs::Result<()> {
48+
fs::symlink_file(path_for_symlink, link)
49+
}
4450

4551
#[cfg(windows)]
4652
pub(crate) fn symlink_or_copy(
47-
original: impl AsRef<Path>,
53+
path_for_symlink: impl AsRef<Path>,
54+
path_for_copy: impl AsRef<Path>,
4855
link: impl AsRef<Path>,
4956
) -> fs::Result<()> {
5057
// Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
5158
// require Developer Mode. If it fails, fall back to copying the file.
52-
let original = original.as_ref();
59+
let path_for_symlink = path_for_symlink.as_ref();
5360
let link = link.as_ref();
54-
if fs::symlink_file(original, link).is_err() {
55-
fs::copy(original, link)?;
61+
if fs::symlink_file(path_for_symlink, link).is_err() {
62+
let path_for_copy = path_for_copy.as_ref();
63+
fs::copy(path_for_copy, link)?;
5664
}
5765
Ok(())
5866
}
5967

6068
#[cfg(not(any(unix, windows)))]
6169
pub(crate) fn symlink_or_copy(
62-
original: impl AsRef<Path>,
70+
_path_for_symlink: impl AsRef<Path>,
71+
path_for_copy: impl AsRef<Path>,
6372
copy: impl AsRef<Path>,
6473
) -> fs::Result<()> {
65-
fs::copy(original, copy)?;
74+
fs::copy(path_for_copy, copy)?;
6675
Ok(())
6776
}

0 commit comments

Comments
 (0)