mirror of
https://github.com/topjohnwu/cxx.git
synced 2025-02-22 00:54:33 +00:00
Expose control of import prefix to Cargo builds
This commit is contained in:
parent
4563fb1c74
commit
e5098cb4a7
131
gen/build/src/cfg.rs
Normal file
131
gen/build/src/cfg.rs
Normal file
@ -0,0 +1,131 @@
|
||||
use std::fmt::{self, Debug};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct Cfg<'a> {
|
||||
pub include_prefix: &'a str,
|
||||
marker: PhantomData<*const ()>, // !Send + !Sync
|
||||
}
|
||||
|
||||
#[cfg(doc)]
|
||||
pub static mut CFG: Cfg = Cfg {
|
||||
include_prefix: "",
|
||||
marker: PhantomData,
|
||||
};
|
||||
|
||||
impl<'a> Debug for Cfg<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("Cfg")
|
||||
.field("include_prefix", &self.include_prefix)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(doc))]
|
||||
pub use self::r#impl::Cfg::CFG;
|
||||
|
||||
#[cfg(not(doc))]
|
||||
mod r#impl {
|
||||
use lazy_static::lazy_static;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{PoisonError, RwLock};
|
||||
|
||||
lazy_static! {
|
||||
static ref PACKAGE_NAME: Box<str> = {
|
||||
crate::env_os("CARGO_PKG_NAME")
|
||||
.map(|pkg| pkg.to_string_lossy().into_owned().into_boxed_str())
|
||||
.unwrap_or_default()
|
||||
};
|
||||
static ref INCLUDE_PREFIX: RwLock<Vec<&'static str>> = RwLock::new(vec![&PACKAGE_NAME]);
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static CONST_DEREFS: RefCell<HashMap<Handle, Box<super::Cfg<'static>>>> = RefCell::default();
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash)]
|
||||
struct Handle(*const Cfg<'static>);
|
||||
|
||||
impl<'a> Cfg<'a> {
|
||||
fn current() -> super::Cfg<'a> {
|
||||
let include_prefix = *INCLUDE_PREFIX
|
||||
.read()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.last()
|
||||
.unwrap();
|
||||
super::Cfg {
|
||||
include_prefix,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
const fn handle(self: &Cfg<'a>) -> Handle {
|
||||
Handle(<*const Cfg>::cast(self))
|
||||
}
|
||||
}
|
||||
|
||||
// Since super::Cfg is !Send and !Sync, all Cfg are thread local and will
|
||||
// drop on the same thread where they were created.
|
||||
pub enum Cfg<'a> {
|
||||
Mut(super::Cfg<'a>),
|
||||
CFG,
|
||||
}
|
||||
|
||||
impl<'a> Debug for Cfg<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Cfg::Mut(cfg) = self {
|
||||
Debug::fmt(cfg, formatter)
|
||||
} else {
|
||||
Debug::fmt(&Cfg::current(), formatter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for Cfg<'a> {
|
||||
type Target = super::Cfg<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
if let Cfg::Mut(cfg) = self {
|
||||
cfg
|
||||
} else {
|
||||
let cfg = CONST_DEREFS.with(|derefs| -> *mut super::Cfg {
|
||||
&mut **derefs
|
||||
.borrow_mut()
|
||||
.entry(self.handle())
|
||||
.or_insert_with(|| Box::new(Cfg::current()))
|
||||
});
|
||||
unsafe { &mut *cfg }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for Cfg<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
if let Cfg::CFG = self {
|
||||
CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
|
||||
*self = Cfg::Mut(Cfg::current());
|
||||
}
|
||||
match self {
|
||||
Cfg::Mut(cfg) => cfg,
|
||||
Cfg::CFG => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Cfg<'a> {
|
||||
fn drop(&mut self) {
|
||||
if let Cfg::Mut(cfg) = self {
|
||||
INCLUDE_PREFIX
|
||||
.write()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.push(Box::leak(Box::from(cfg.include_prefix)));
|
||||
} else {
|
||||
CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@
|
||||
)]
|
||||
|
||||
mod cargo;
|
||||
mod cfg;
|
||||
mod error;
|
||||
mod gen;
|
||||
mod out;
|
||||
@ -73,6 +74,8 @@ use std::iter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
|
||||
pub use crate::cfg::{Cfg, CFG};
|
||||
|
||||
/// This returns a [`cc::Build`] on which you should continue to set up any
|
||||
/// additional source files or compiler flags, and lastly call its [`compile`]
|
||||
/// method to execute the C++ build.
|
||||
@ -103,7 +106,7 @@ pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) ->
|
||||
}
|
||||
|
||||
struct Project {
|
||||
package_name: OsString,
|
||||
include_prefix: PathBuf,
|
||||
manifest_dir: PathBuf,
|
||||
// Output directory as received from Cargo.
|
||||
out_dir: PathBuf,
|
||||
@ -124,7 +127,11 @@ struct Project {
|
||||
|
||||
impl Project {
|
||||
fn init() -> Result<Self> {
|
||||
let package_name = env_os("CARGO_PKG_NAME")?;
|
||||
let include_prefix = Path::new(CFG.include_prefix);
|
||||
assert!(include_prefix.is_relative());
|
||||
assert!(!include_prefix.as_os_str().is_empty());
|
||||
let include_prefix = include_prefix.components().collect();
|
||||
|
||||
let manifest_dir = paths::manifest_dir()?;
|
||||
let out_dir = paths::out_dir()?;
|
||||
|
||||
@ -141,7 +148,7 @@ impl Project {
|
||||
};
|
||||
|
||||
Ok(Project {
|
||||
package_name,
|
||||
include_prefix,
|
||||
manifest_dir,
|
||||
out_dir,
|
||||
shared_dir,
|
||||
@ -240,7 +247,7 @@ fn env_include_dirs() -> impl Iterator<Item = PathBuf> {
|
||||
|
||||
fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
|
||||
let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
|
||||
let link = crate_dir.join(&prj.package_name);
|
||||
let link = crate_dir.join(&prj.include_prefix);
|
||||
if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
|
||||
println!("cargo:CXXBRIDGE_CRATE={}", crate_dir.to_string_lossy());
|
||||
Some(crate_dir)
|
||||
@ -270,8 +277,8 @@ fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) ->
|
||||
let ref rel_path = paths::local_relative_path(rust_source_file);
|
||||
|
||||
let cxxbridge = prj.out_dir.join("cxxbridge");
|
||||
let include_dir = cxxbridge.join("include").join(&prj.package_name);
|
||||
let sources_dir = cxxbridge.join("sources").join(&prj.package_name);
|
||||
let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
|
||||
let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);
|
||||
|
||||
let ref rel_path_h = rel_path.with_appended_extension(".h");
|
||||
let ref header_path = include_dir.join(rel_path_h);
|
||||
@ -285,8 +292,8 @@ fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) ->
|
||||
out::write(implementation_path, &generated.implementation)?;
|
||||
build.file(implementation_path);
|
||||
|
||||
let shared_h = prj.shared_dir.join(&prj.package_name).join(rel_path_h);
|
||||
let shared_cc = prj.shared_dir.join(&prj.package_name).join(rel_path_cc);
|
||||
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);
|
||||
Ok(())
|
||||
|
Loading…
x
Reference in New Issue
Block a user