aboutsummaryrefslogtreecommitdiff
path: root/gen/build
diff options
context:
space:
mode:
Diffstat (limited to 'gen/build')
-rw-r--r--gen/build/Cargo.toml19
-rw-r--r--gen/build/src/deps.rs8
-rw-r--r--gen/build/src/intern.rs6
-rw-r--r--gen/build/src/lib.rs26
-rw-r--r--gen/build/src/out.rs229
-rw-r--r--gen/build/src/paths.rs23
-rw-r--r--gen/build/src/vec.rs6
7 files changed, 257 insertions, 60 deletions
diff --git a/gen/build/Cargo.toml b/gen/build/Cargo.toml
index 9b74255b..ee20e2b7 100644
--- a/gen/build/Cargo.toml
+++ b/gen/build/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "cxx-build"
-version = "1.0.93"
+version = "1.0.119"
authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["development-tools::build-utils", "development-tools::ffi"]
description = "C++ code generator for integrating `cxx` crate into a Cargo build."
documentation = "https://docs.rs/cxx-build"
-edition = "2018"
+edition = "2021"
exclude = ["build.rs"]
homepage = "https://cxx.rs"
keywords = ["ffi", "build-dependencies"]
@@ -19,21 +19,22 @@ parallel = ["cc/parallel"]
experimental-async-fn = []
[dependencies]
-cc = "1.0.49"
+cc = "1.0.83"
codespan-reporting = "0.11.1"
-once_cell = "1.9"
-proc-macro2 = { version = "1.0.39", default-features = false, features = ["span-locations"] }
-quote = { version = "1.0", default-features = false }
-scratch = "1.0"
-syn = { version = "2.0.1", default-features = false, features = ["parsing", "printing", "clone-impls", "full"] }
+once_cell = "1.18"
+proc-macro2 = { version = "1.0.74", default-features = false, features = ["span-locations"] }
+quote = { version = "1.0.35", default-features = false }
+scratch = "1.0.5"
+syn = { version = "2.0.46", default-features = false, features = ["clone-impls", "full", "parsing", "printing"] }
[dev-dependencies]
cxx = { version = "1.0", path = "../.." }
cxx-gen = { version = "0.7", path = "../lib" }
-pkg-config = "0.3"
+pkg-config = "0.3.27"
[lib]
doc-scrape-examples = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = ["--generate-link-to-definition"]
diff --git a/gen/build/src/deps.rs b/gen/build/src/deps.rs
index fb80072c..36f2066a 100644
--- a/gen/build/src/deps.rs
+++ b/gen/build/src/deps.rs
@@ -4,19 +4,19 @@ use std::ffi::OsString;
use std::path::PathBuf;
#[derive(Default)]
-pub struct Crate {
+pub(crate) struct Crate {
pub include_prefix: Option<PathBuf>,
pub links: Option<OsString>,
pub header_dirs: Vec<HeaderDir>,
}
-pub struct HeaderDir {
+pub(crate) struct HeaderDir {
pub exported: bool,
pub path: PathBuf,
}
impl Crate {
- pub fn print_to_cargo(&self) {
+ pub(crate) fn print_to_cargo(&self) {
if let Some(include_prefix) = &self.include_prefix {
println!(
"cargo:CXXBRIDGE_PREFIX={}",
@@ -38,7 +38,7 @@ impl Crate {
}
}
-pub fn direct_dependencies() -> Vec<Crate> {
+pub(crate) fn direct_dependencies() -> Vec<Crate> {
let mut crates: BTreeMap<String, Crate> = BTreeMap::new();
let mut exported_header_dirs: BTreeMap<String, Vec<(usize, PathBuf)>> = BTreeMap::new();
diff --git a/gen/build/src/intern.rs b/gen/build/src/intern.rs
index c8b57d89..753e3f31 100644
--- a/gen/build/src/intern.rs
+++ b/gen/build/src/intern.rs
@@ -3,15 +3,15 @@ use once_cell::sync::OnceCell;
use std::sync::{Mutex, PoisonError};
#[derive(Copy, Clone, Default)]
-pub struct InternedString(&'static str);
+pub(crate) struct InternedString(&'static str);
impl InternedString {
- pub fn str(self) -> &'static str {
+ pub(crate) fn str(self) -> &'static str {
self.0
}
}
-pub fn intern(s: &str) -> InternedString {
+pub(crate) fn intern(s: &str) -> InternedString {
static INTERN: OnceCell<Mutex<Set<&'static str>>> = OnceCell::new();
let mut set = INTERN
diff --git a/gen/build/src/lib.rs b/gen/build/src/lib.rs
index b6b843a6..4fcb9459 100644
--- a/gen/build/src/lib.rs
+++ b/gen/build/src/lib.rs
@@ -45,17 +45,17 @@
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```
-#![doc(html_root_url = "https://docs.rs/cxx-build/1.0.93")]
+#![doc(html_root_url = "https://docs.rs/cxx-build/1.0.119")]
#![allow(
clippy::cast_sign_loss,
clippy::default_trait_access,
clippy::derive_partial_eq_without_eq,
clippy::doc_markdown,
- clippy::drop_copy,
clippy::enum_glob_use,
clippy::explicit_auto_deref,
clippy::if_same_then_else,
clippy::inherent_to_string,
+ clippy::into_iter_without_iter,
clippy::items_after_statements,
clippy::match_bool,
clippy::match_on_vec_items,
@@ -65,7 +65,6 @@
clippy::needless_pass_by_value,
clippy::new_without_default,
clippy::nonminimal_bool,
- clippy::option_if_let_else,
clippy::or_fun_call,
clippy::redundant_else,
clippy::shadow_unrelated,
@@ -73,12 +72,13 @@
clippy::similar_names,
clippy::single_match_else,
clippy::struct_excessive_bools,
+ clippy::struct_field_names,
clippy::too_many_arguments,
clippy::too_many_lines,
clippy::toplevel_ref_arg,
+ clippy::unconditional_recursion, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/12133
+ clippy::uninlined_format_args,
clippy::upper_case_acronyms,
- // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6983
- clippy::wrong_self_convention
)]
mod cargo;
@@ -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\
@@ -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)
}
@@ -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);
@@ -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(())
}
@@ -455,7 +455,7 @@ fn best_effort_copy_headers(src: &Path, dst: &Path, max_depth: usize) {
Ok(file_type) if file_type.is_file() => {
let src = entry.path();
match src.extension().and_then(OsStr::to_str) {
- Some("h") | Some("hh") | Some("hpp") => {}
+ Some("h" | "hh" | "hpp") => {}
_ => continue,
}
if !dst_created && fs::create_dir_all(dst).is_err() {
diff --git a/gen/build/src/out.rs b/gen/build/src/out.rs
index a52aab25..0095666f 100644
--- a/gen/build/src/out.rs
+++ b/gen/build/src/out.rs
@@ -1,8 +1,8 @@
use crate::error::{Error, Result};
use crate::gen::fs;
use crate::paths;
-use std::io;
-use std::path::Path;
+use std::path::{Component, Path, PathBuf};
+use std::{env, io};
pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
let path = path.as_ref();
@@ -29,19 +29,61 @@ 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 mut create_dir_error = None;
+ let parent_directory_error = prepare_parent_directory_for_symlink(link).err();
+ let relativized = best_effort_relativize_symlink(original, link);
+
+ symlink_file(&relativized, original, link, parent_directory_error)
+}
+
+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();
+
+ let parent_directory_error = prepare_parent_directory_for_symlink(link).err();
+
+ symlink_file(original, original, link, parent_directory_error)
+}
+
+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 parent_directory_error = prepare_parent_directory_for_symlink(link).err();
+ let relativized = best_effort_relativize_symlink(original, link);
+
+ symlink_dir(&relativized, link, parent_directory_error)
+}
+
+fn prepare_parent_directory_for_symlink(link: &Path) -> fs::Result<()> {
if fs::exists(link) {
best_effort_remove(link);
+ Ok(())
} else {
let parent = link.parent().unwrap();
- create_dir_error = fs::create_dir_all(parent).err();
+ fs::create_dir_all(parent)
}
+}
- match paths::symlink_or_copy(original, link) {
+fn symlink_file(
+ path_for_symlink: &Path,
+ path_for_copy: &Path,
+ link: &Path,
+ parent_directory_error: Option<fs::Error>,
+) -> Result<()> {
+ 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) => {
@@ -57,29 +99,22 @@ pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -
} else {
// If create_dir_all and symlink_or_copy both failed, prefer the
// first error.
- Err(Error::Fs(create_dir_error.unwrap_or(err)))
+ Err(Error::Fs(parent_directory_error.unwrap_or(err)))
}
}
}
}
-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 mut create_dir_error = None;
- if fs::exists(link) {
- best_effort_remove(link);
- } else {
- let parent = link.parent().unwrap();
- create_dir_error = fs::create_dir_all(parent).err();
- }
-
- match fs::symlink_dir(original, link) {
+fn symlink_dir(
+ path_for_symlink: &Path,
+ link: &Path,
+ parent_directory_error: Option<fs::Error>,
+) -> Result<()> {
+ 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.
- Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
+ Err(err) => Err(Error::Fs(parent_directory_error.unwrap_or(err))),
}
}
@@ -117,3 +152,155 @@ fn best_effort_remove(path: &Path) {
}
}
}
+
+fn best_effort_relativize_symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> PathBuf {
+ let original = original.as_ref();
+ let link = link.as_ref();
+
+ let relative_path = match abstractly_relativize_symlink(original, link) {
+ Some(relative_path) => relative_path,
+ None => return original.to_path_buf(),
+ };
+
+ // Sometimes "a/b/../c" refers to a different canonical location than "a/c".
+ // This can happen if 'b' is a symlink. The '..' canonicalizes to the parent
+ // directory of the symlink's target, not back to 'a'. In cxx-build's case
+ // someone could be using `--target-dir` with a location containing such
+ // symlinks.
+ if let Ok(original_canonical) = original.canonicalize() {
+ if let Ok(relative_canonical) = link.parent().unwrap().join(&relative_path).canonicalize() {
+ if original_canonical == relative_canonical {
+ return relative_path;
+ }
+ }
+ }
+
+ original.to_path_buf()
+}
+
+fn abstractly_relativize_symlink(
+ original: impl AsRef<Path>,
+ link: impl AsRef<Path>,
+) -> Option<PathBuf> {
+ let original = original.as_ref();
+ let link = link.as_ref();
+
+ // Relativization only makes sense if there is a semantically meaningful
+ // base directory shared between the two paths.
+ //
+ // For example /Volumes/code/library/src/lib.rs
+ // and /Volumes/code/library/target/path/to/something.a
+ // have a meaningful shared base of /Volumes/code/library. The target and
+ // source directory only likely ever get relocated as one unit.
+ //
+ // On the other hand, /Volumes/code/library/src/lib.rs
+ // and /Volumes/shared_target
+ // do not, since upon moving library to a different location it should
+ // continue referring to the original location of that shared Cargo target
+ // directory.
+ let likely_no_semantic_prefix = env::var_os("CARGO_TARGET_DIR").is_some();
+
+ if likely_no_semantic_prefix
+ || original.is_relative()
+ || link.is_relative()
+ || path_contains_intermediate_components(original)
+ || path_contains_intermediate_components(link)
+ {
+ return None;
+ }
+
+ let (common_prefix, rest_of_original, rest_of_link) = split_after_common_prefix(original, link);
+
+ if common_prefix == Path::new("") {
+ return None;
+ }
+
+ let mut rest_of_link = rest_of_link.components();
+ rest_of_link
+ .next_back()
+ .expect("original can't be a subdirectory of link");
+
+ let mut path_to_common_prefix = PathBuf::new();
+ while rest_of_link.next_back().is_some() {
+ path_to_common_prefix.push(Component::ParentDir);
+ }
+
+ Some(path_to_common_prefix.join(rest_of_original))
+}
+
+fn path_contains_intermediate_components(path: impl AsRef<Path>) -> bool {
+ path.as_ref()
+ .components()
+ .any(|component| component == Component::ParentDir)
+}
+
+fn split_after_common_prefix<'first, 'second>(
+ first: &'first Path,
+ second: &'second Path,
+) -> (&'first Path, &'first Path, &'second Path) {
+ let entire_first = first;
+ let mut first = first.components();
+ let mut second = second.components();
+ loop {
+ let rest_of_first = first.as_path();
+ let rest_of_second = second.as_path();
+ match (first.next(), second.next()) {
+ (Some(first_component), Some(second_component))
+ if first_component == second_component => {}
+ _ => {
+ let mut common_prefix = entire_first;
+ for _ in rest_of_first.components().rev() {
+ if let Some(parent) = common_prefix.parent() {
+ common_prefix = parent;
+ } else {
+ common_prefix = Path::new("");
+ break;
+ }
+ }
+ return (common_prefix, rest_of_first, rest_of_second);
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::out::abstractly_relativize_symlink;
+ use std::path::Path;
+
+ #[cfg(not(windows))]
+ #[test]
+ fn test_relativize_symlink_unix() {
+ assert_eq!(
+ abstractly_relativize_symlink("/foo/bar/baz", "/foo/spam/eggs").as_deref(),
+ Some(Path::new("../bar/baz")),
+ );
+ assert_eq!(
+ abstractly_relativize_symlink("/foo/bar/../baz", "/foo/spam/eggs"),
+ None,
+ );
+ assert_eq!(
+ abstractly_relativize_symlink("/foo/bar/baz", "/foo/spam/./eggs").as_deref(),
+ Some(Path::new("../bar/baz")),
+ );
+ }
+
+ #[cfg(windows)]
+ #[test]
+ fn test_relativize_symlink_windows() {
+ use std::path::PathBuf;
+
+ let windows_target = PathBuf::from_iter(["c:\\", "windows", "foo"]);
+ let windows_link = PathBuf::from_iter(["c:\\", "users", "link"]);
+ let windows_different_volume_link = PathBuf::from_iter(["d:\\", "users", "link"]);
+
+ assert_eq!(
+ abstractly_relativize_symlink(&windows_target, windows_link).as_deref(),
+ Some(Path::new("..\\windows\\foo")),
+ );
+ assert_eq!(
+ abstractly_relativize_symlink(&windows_target, windows_different_volume_link),
+ None,
+ );
+ }
+}
diff --git a/gen/build/src/paths.rs b/gen/build/src/paths.rs
index c514a570..53445dee 100644
--- a/gen/build/src/paths.rs
+++ b/gen/build/src/paths.rs
@@ -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(())
}
diff --git a/gen/build/src/vec.rs b/gen/build/src/vec.rs
index ac9235ec..ccc98955 100644
--- a/gen/build/src/vec.rs
+++ b/gen/build/src/vec.rs
@@ -1,7 +1,7 @@
use crate::intern::{self, InternedString};
use std::path::Path;
-pub trait InternedVec<T>
+pub(crate) trait InternedVec<T>
where
T: ?Sized,
{
@@ -17,14 +17,14 @@ where
}
}
-pub fn intern<T>(elements: &[&T]) -> Vec<InternedString>
+pub(crate) fn intern<T>(elements: &[&T]) -> Vec<InternedString>
where
T: ?Sized + Element,
{
elements.iter().copied().map(Element::intern).collect()
}
-pub trait Element {
+pub(crate) trait Element {
fn intern(&self) -> InternedString;
fn unintern(_: InternedString) -> &'static Self;
}