Skip to content

Commit

Permalink
Merge pull request #1253 from dtolnay/symlinks
Browse files Browse the repository at this point in the history
Fix symlink paths during copy on Windows
  • Loading branch information
dtolnay authored Aug 6, 2023
2 parents 7122547 + af1a534 commit 62085f0
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 24 deletions.
14 changes: 7 additions & 7 deletions gen/build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ fn make_crate_dir(prj: &Project) -> PathBuf {
let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
let ref link = crate_dir.join(&prj.include_prefix);
let ref manifest_dir = prj.manifest_dir;
if out::symlink_dir(manifest_dir, link).is_err() && cfg!(not(unix)) {
if out::relative_symlink_dir(manifest_dir, link).is_err() && cfg!(not(unix)) {
let cachedir_tag = "\
Signature: 8a477f597d28d172789f06886806bc55\n\
# This file is a cache directory tag created by cxx.\n\
Expand All @@ -386,11 +386,11 @@ fn make_include_dir(prj: &Project) -> Result<PathBuf> {
let cxx_h = include_dir.join("rust").join("cxx.h");
let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
if let Some(ref original) = env::var_os("DEP_CXXBRIDGE1_HEADER") {
out::symlink_file(original, cxx_h)?;
out::symlink_file(original, shared_cxx_h)?;
out::absolute_symlink_file(original, cxx_h)?;
out::absolute_symlink_file(original, shared_cxx_h)?;
} else {
out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
out::symlink_file(shared_cxx_h, cxx_h)?;
out::relative_symlink_file(shared_cxx_h, cxx_h)?;
}
Ok(include_dir)
}
Expand All @@ -414,7 +414,7 @@ fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) ->
out::write(header_path, &generated.header)?;

let ref link_path = include_dir.join(rel_path);
let _ = out::symlink_file(header_path, link_path);
let _ = out::relative_symlink_file(header_path, link_path);

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

let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
let _ = out::symlink_file(header_path, shared_h);
let _ = out::symlink_file(implementation_path, shared_cc);
let _ = out::relative_symlink_file(header_path, shared_h);
let _ = out::relative_symlink_file(implementation_path, shared_cc);
Ok(())
}

Expand Down
44 changes: 34 additions & 10 deletions gen/build/src/out.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,41 @@ pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
}
}

pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
pub(crate) fn relative_symlink_file(
original: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<()> {
let original = original.as_ref();
let link = link.as_ref();

let original = best_effort_relativize_symlink(original, link);
let relativized = best_effort_relativize_symlink(original, link);

symlink_file(&relativized, original, link)
}

pub(crate) fn absolute_symlink_file(
original: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<()> {
let original = original.as_ref();
let link = link.as_ref();

symlink_file(original, original, link)
}

pub(crate) fn relative_symlink_dir(
original: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<()> {
let original = original.as_ref();
let link = link.as_ref();

let relativized = best_effort_relativize_symlink(original, link);

symlink_dir(&relativized, link)
}

fn symlink_file(path_for_symlink: &Path, path_for_copy: &Path, link: &Path) -> Result<()> {
let mut create_dir_error = None;
if fs::exists(link) {
best_effort_remove(link);
Expand All @@ -43,7 +72,7 @@ pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -
create_dir_error = fs::create_dir_all(parent).err();
}

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

pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
let original = original.as_ref();
let link = link.as_ref();

let original = best_effort_relativize_symlink(original, link);

fn symlink_dir(path_for_symlink: &Path, link: &Path) -> Result<()> {
let mut create_dir_error = None;
if fs::exists(link) {
best_effort_remove(link);
Expand All @@ -79,7 +103,7 @@ pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) ->
create_dir_error = fs::create_dir_all(parent).err();
}

match fs::symlink_dir(original, link) {
match fs::symlink_dir(path_for_symlink, link) {
// As long as symlink_dir succeeded, ignore any create_dir_all error.
Ok(()) => Ok(()),
// If create_dir_all and symlink_dir both failed, prefer the first error.
Expand Down
23 changes: 16 additions & 7 deletions gen/build/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,37 @@ impl PathExt for Path {
}

#[cfg(unix)]
pub(crate) use self::fs::symlink_file as symlink_or_copy;
pub(crate) fn symlink_or_copy(
path_for_symlink: impl AsRef<Path>,
_path_for_copy: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> fs::Result<()> {
fs::symlink_file(path_for_symlink, link)
}

#[cfg(windows)]
pub(crate) fn symlink_or_copy(
original: impl AsRef<Path>,
path_for_symlink: impl AsRef<Path>,
path_for_copy: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> fs::Result<()> {
// Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
// require Developer Mode. If it fails, fall back to copying the file.
let original = original.as_ref();
let path_for_symlink = path_for_symlink.as_ref();
let link = link.as_ref();
if fs::symlink_file(original, link).is_err() {
fs::copy(original, link)?;
if fs::symlink_file(path_for_symlink, link).is_err() {
let path_for_copy = path_for_copy.as_ref();
fs::copy(path_for_copy, link)?;
}
Ok(())
}

#[cfg(not(any(unix, windows)))]
pub(crate) fn symlink_or_copy(
original: impl AsRef<Path>,
_path_for_symlink: impl AsRef<Path>,
path_for_copy: impl AsRef<Path>,
copy: impl AsRef<Path>,
) -> fs::Result<()> {
fs::copy(original, copy)?;
fs::copy(path_for_copy, copy)?;
Ok(())
}

0 comments on commit 62085f0

Please sign in to comment.