108 lines
3.6 KiB
Rust
108 lines
3.6 KiB
Rust
use std::collections::BTreeMap;
|
|
use std::env;
|
|
use std::ffi::OsString;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Default)]
|
|
pub struct Crate {
|
|
pub include_prefix: Option<PathBuf>,
|
|
pub links: Option<OsString>,
|
|
pub header_dirs: Vec<HeaderDir>,
|
|
}
|
|
|
|
pub struct HeaderDir {
|
|
pub exported: bool,
|
|
pub path: PathBuf,
|
|
}
|
|
|
|
impl Crate {
|
|
pub fn print_to_cargo(&self) {
|
|
if let Some(include_prefix) = &self.include_prefix {
|
|
println!(
|
|
"cargo:CXXBRIDGE_PREFIX={}",
|
|
include_prefix.to_string_lossy(),
|
|
);
|
|
}
|
|
if let Some(links) = &self.links {
|
|
println!("cargo:CXXBRIDGE_LINKS={}", links.to_string_lossy());
|
|
}
|
|
for (i, header_dir) in self.header_dirs.iter().enumerate() {
|
|
if header_dir.exported {
|
|
println!(
|
|
"cargo:CXXBRIDGE_DIR{}={}",
|
|
i,
|
|
header_dir.path.to_string_lossy(),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub 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();
|
|
|
|
// Only variables set from a build script of direct dependencies are
|
|
// observable. That's exactly what we want! Your crate needs to declare a
|
|
// direct dependency on the other crate in order to be able to #include its
|
|
// headers.
|
|
//
|
|
// Also, they're only observable if the dependency's manifest contains a
|
|
// `links` key. This is important because Cargo imposes no ordering on the
|
|
// execution of build scripts without a `links` key. When exposing a
|
|
// generated header for the current crate to #include, we need to be sure
|
|
// the dependency's build script has already executed and emitted that
|
|
// generated header.
|
|
//
|
|
// References:
|
|
// - https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
|
|
// - https://doc.rust-lang.org/cargo/reference/build-script-examples.html#using-another-sys-crate
|
|
for (k, v) in env::vars_os() {
|
|
let mut k = k.to_string_lossy().into_owned();
|
|
if !k.starts_with("DEP_") {
|
|
continue;
|
|
}
|
|
|
|
if k.ends_with("_CXXBRIDGE_PREFIX") {
|
|
k.truncate(k.len() - "_CXXBRIDGE_PREFIX".len());
|
|
crates.entry(k).or_default().include_prefix = Some(PathBuf::from(v));
|
|
continue;
|
|
}
|
|
|
|
if k.ends_with("_CXXBRIDGE_LINKS") {
|
|
k.truncate(k.len() - "_CXXBRIDGE_LINKS".len());
|
|
crates.entry(k).or_default().links = Some(v);
|
|
continue;
|
|
}
|
|
|
|
let without_counter = k.trim_end_matches(|ch: char| ch.is_ascii_digit());
|
|
let counter_len = k.len() - without_counter.len();
|
|
if counter_len == 0 || !without_counter.ends_with("_CXXBRIDGE_DIR") {
|
|
continue;
|
|
}
|
|
|
|
let sort_key = k[k.len() - counter_len..]
|
|
.parse::<usize>()
|
|
.unwrap_or(usize::MAX);
|
|
k.truncate(k.len() - counter_len - "_CXXBRIDGE_DIR".len());
|
|
exported_header_dirs
|
|
.entry(k)
|
|
.or_default()
|
|
.push((sort_key, PathBuf::from(v)));
|
|
}
|
|
|
|
for (k, mut dirs) in exported_header_dirs {
|
|
dirs.sort_by_key(|(sort_key, _dir)| *sort_key);
|
|
crates
|
|
.entry(k)
|
|
.or_default()
|
|
.header_dirs
|
|
.extend(dirs.into_iter().map(|(_sort_key, dir)| HeaderDir {
|
|
exported: true,
|
|
path: dir,
|
|
}));
|
|
}
|
|
|
|
crates.into_iter().map(|entry| entry.1).collect()
|
|
}
|