pub mod bgx;
pub mod bin;
pub mod cargo;
pub mod cmkabe;
pub mod metadata;
pub mod rustc;
pub mod target;
pub use ::bindgen;
pub use ::std::{
cell::RefCell,
collections::HashSet,
env, fs,
io::{self, BufRead, Write},
path::{Path, PathBuf},
};
pub use filetime::{self, FileTime};
pub use regex::{self, Regex, RegexSet};
pub use semver;
pub use walkdir::{self, DirEntry, WalkDir};
#[macro_export]
macro_rules! warning {
($($args:tt)*) => {
$crate::warning(format!($($args)*))
};
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct InvalidInput(String);
impl InvalidInput {
pub fn input(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for InvalidInput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid input: {:?}", self.0)
}
}
impl std::error::Error for InvalidInput {
fn description(&self) -> &str {
"invalid input"
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Atomic {
Integer { bits: u8 },
Pointer,
}
impl std::fmt::Display for Atomic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Atomic::Integer { bits } => write!(f, "{bits}"),
Atomic::Pointer => write!(f, "ptr"),
}
}
}
impl std::str::FromStr for Atomic {
type Err = InvalidInput;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "ptr" {
Ok(Atomic::Pointer)
} else if let Ok(bits) = s.parse::<u8>() {
Ok(Atomic::Integer { bits })
} else {
Err(InvalidInput(s.to_owned()))
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Endianness {
Big,
Little,
}
impl std::fmt::Display for Endianness {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Endianness::Big => write!(f, "big"),
Endianness::Little => write!(f, "little"),
}
}
}
impl std::str::FromStr for Endianness {
type Err = InvalidInput;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"big" => Ok(Endianness::Big),
"little" => Ok(Endianness::Little),
_ => Err(InvalidInput(s.to_owned())),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum LibKind {
Static,
DyLib,
Framework,
}
impl std::fmt::Display for LibKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LibKind::Static => write!(f, "static"),
LibKind::DyLib => write!(f, "dylib"),
LibKind::Framework => write!(f, "framework"),
}
}
}
impl std::str::FromStr for LibKind {
type Err = InvalidInput;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"static" => Ok(LibKind::Static),
"dylib" => Ok(LibKind::DyLib),
"framework" => Ok(LibKind::Framework),
_ => Err(InvalidInput(s.to_owned())),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Profile {
Debug,
Release,
}
impl std::fmt::Display for Profile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Profile::Debug => write!(f, "debug"),
Profile::Release => write!(f, "release"),
}
}
}
impl std::str::FromStr for Profile {
type Err = InvalidInput;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"debug" => Ok(Profile::Debug),
"release" => Ok(Profile::Release),
_ => Err(InvalidInput(s.to_owned())),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum SearchKind {
Dependency,
Crate,
Native,
Framework,
All,
}
impl std::fmt::Display for SearchKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SearchKind::Dependency => write!(f, "dependency"),
SearchKind::Crate => write!(f, "crate"),
SearchKind::Native => write!(f, "native"),
SearchKind::Framework => write!(f, "framework"),
SearchKind::All => write!(f, "all"),
}
}
}
impl std::str::FromStr for SearchKind {
type Err = InvalidInput;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"dependency" => Ok(SearchKind::Dependency),
"crate" => Ok(SearchKind::Crate),
"native" => Ok(SearchKind::Native),
"framework" => Ok(SearchKind::Framework),
"all" => Ok(SearchKind::All),
_ => Err(InvalidInput(s.to_owned())),
}
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Triple {
raw: String,
arch: String,
vendor: String,
os: String,
env: Option<String>,
}
impl Triple {
pub fn new(triple: String) -> Triple {
let segments: Vec<&str> = triple.splitn(4, '-').collect();
let arch = segments.first().map(|&s| s.to_owned()).unwrap_or_default();
let vendor = segments.get(1).map(|&s| s.to_owned()).unwrap_or_default();
let os = segments.get(2).map(|&s| s.to_owned()).unwrap_or_default();
let env = segments
.get(3)
.filter(|&s| !s.is_empty())
.map(|&s| s.to_owned());
Triple {
raw: triple,
arch,
vendor,
os,
env,
}
}
pub fn as_str(&self) -> &str {
&self.raw
}
pub fn arch(&self) -> &str {
&self.arch
}
pub fn env(&self) -> Option<&str> {
self.env.as_deref()
}
pub fn family(&self) -> &str {
&self.vendor
}
pub fn os(&self) -> &str {
&self.os
}
}
impl std::fmt::Display for Triple {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.raw.fmt(f)
}
}
impl std::str::FromStr for Triple {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Triple::new(s.to_owned()))
}
}
pub fn debug() -> bool {
std::env::var("DEBUG").expect("DEBUG env var is not set") == "true"
}
pub fn host() -> Triple {
Triple::new(std::env::var("HOST").expect("HOST env var is not set"))
}
pub fn num_jobs() -> u32 {
let raw = std::env::var("NUM_JOBS").expect("NUM_JOBS env var is not set");
raw.parse().expect("NUM_JOBS is not a valid integer")
}
pub fn opt_level() -> String {
std::env::var("OPT_LEVEL").expect("OPT_LEVEL env var is not set")
}
pub fn out_dir() -> PathBuf {
std::env::var_os("OUT_DIR")
.expect("OUT_DIR env var is not set")
.into()
}
pub fn profile() -> Profile {
let raw = std::env::var("PROFILE").expect("PROFILE env var is not set");
match raw.as_str() {
"debug" => Profile::Debug,
"release" => Profile::Release,
other => panic!("PROFILE {other:?} is not a valid profile"),
}
}
pub fn rerun_if_changed<P: AsRef<Path>>(path: P) {
println!("cargo:rerun-if-changed={}", path.as_ref().display());
}
pub fn rerun_if_env_changed<N: AsRef<str>>(name: N) {
println!("cargo:rerun-if-env-changed={}", name.as_ref());
}
pub fn target_tmpdir() -> PathBuf {
std::env::var_os("CARGO_TARGET_TMPDIR")
.expect("CARGO_TARGET_TMPDIR env var is not set")
.into()
}
pub fn is_primary_package() -> bool {
std::env::var("CARGO_PRIMARY_PACKAGE").is_ok()
}
pub fn windows() -> bool {
std::env::var("CARGO_CFG_WINDOWS").is_ok()
}
pub fn unix() -> bool {
std::env::var("CARGO_CFG_UNIX").is_ok()
}
pub fn warning<S: AsRef<str>>(msg: S) {
println!("cargo:warning={}", msg.as_ref());
}
pub fn error<S: AsRef<str>>(msg: S) {
println!("cargo:error={}", msg.as_ref());
}
pub fn canon_feature_name<T: AsRef<str>>(name: T) -> String {
name.as_ref().to_ascii_uppercase().replace('-', "_")
}
pub fn realpath<P: AsRef<Path>>(path: P) -> PathBuf {
let path = path.as_ref();
match path.canonicalize() {
Ok(v) => {
let s = v.to_string_lossy();
match s.strip_prefix(r"\\?\") {
Some(v) => v.into(),
_ => s.into_owned().into(),
}
}
_ => path.to_owned(),
}
}
pub fn watch_file_changes<R, P>(root: R, patterns: P) -> io::Result<()>
where
R: AsRef<Path>,
P: IntoIterator,
P::Item: AsRef<str>,
{
let re = RegexSet::new(patterns).map_err(io::Error::other)?;
for entry in WalkDir::new(root)
.follow_links(true)
.into_iter()
.filter_entry(|e| {
!e.file_name()
.to_str()
.map(|s| s.starts_with('.') || s == "target")
.unwrap_or(false)
})
{
if let Ok(entry) = entry.as_ref() {
if entry.file_type().is_file()
&& re.is_match(entry.file_name().to_string_lossy().as_ref())
{
rerun_if_changed(entry.path());
}
}
}
Ok(())
}
pub fn touch<P>(files: P) -> io::Result<()>
where
P: IntoIterator,
P::Item: AsRef<Path>,
{
for file in files.into_iter() {
let f = fs::OpenOptions::new()
.create(true)
.truncate(false)
.write(true)
.open(file)?;
filetime::set_file_handle_times(&f, None, Some(FileTime::now()))?;
}
Ok(())
}