fn main() {
use std::io::Write;
fn pthread_mutex_layout(
has_multitask: bool,
has_smp: bool,
has_lockdep: bool,
) -> (usize, &'static str) {
if !has_multitask {
return (1, "{0}");
}
if has_lockdep {
if has_smp {
return (10, "{-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}");
}
return (9, "{-1, 0, 0, 0, 0, 0, 0, 0, 0}");
}
if has_smp {
(6, "{0, 0, 8, 0, 0, 0}")
} else {
(5, "{0, 8, 0, 0, 0}")
}
}
fn gen_pthread_mutex(out_file: &str) -> std::io::Result<()> {
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_MULTITASK");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_SMP");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_LOCKDEP");
let has_multitask = std::env::var_os("CARGO_FEATURE_MULTITASK").is_some();
let has_smp = std::env::var_os("CARGO_FEATURE_SMP").is_some();
let has_lockdep = std::env::var_os("CARGO_FEATURE_LOCKDEP").is_some();
let (mutex_size, mutex_init) = pthread_mutex_layout(has_multitask, has_smp, has_lockdep);
let mut output = Vec::new();
writeln!(
output,
"// Generated by ax-posix-api/build.rs - DO NOT edit!"
)?;
writeln!(
output,
r#"
typedef struct {{
long __l[{mutex_size}];
}} pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER {{ .__l = {mutex_init} }}
"#
)?;
std::fs::write(out_file, output)?;
Ok(())
}
fn gen_c_to_rust_bindings(in_file: &str, out_file: &std::path::Path) {
println!("cargo:rerun-if-changed={in_file}");
let allow_types = [
"stat",
"size_t",
"ssize_t",
"off_t",
"mode_t",
"sock.*",
"fd_set",
"timeval",
"pthread_t",
"pthread_attr_t",
"pthread_mutex_t",
"pthread_mutexattr_t",
"epoll_event",
"iovec",
"clockid_t",
"rlimit",
"aibuf",
"pollfd",
"nfds_t",
];
let allow_vars = [
"CLOCK_.*",
"O_.*",
"AF_.*",
"SOCK_.*",
"IPPROTO_.*",
"FD_.*",
"F_.*",
"_SC_.*",
"EPOLL_CTL_.*",
"EPOLL.*",
"RLIMIT_.*",
"EAI_.*",
"MAXADDRS",
"SO_.*",
"SOL_.*",
"TCP_.*",
"POLL.*",
];
#[derive(Debug)]
struct MyCallbacks;
impl bindgen::callbacks::ParseCallbacks for MyCallbacks {
fn include_file(&self, fname: &str) {
if !fname.contains("ax_pthread_mutex.h") {
println!("cargo:rerun-if-changed={fname}");
}
}
}
let target = std::env::var("TARGET").unwrap();
let mut builder = bindgen::Builder::default()
.header(in_file)
.clang_arg("-I./../../ulib/axlibc/include")
.parse_callbacks(Box::new(MyCallbacks))
.derive_default(true)
.size_t_is_usize(false)
.use_core();
for feature in ["MULTITASK", "SMP", "LOCKDEP"] {
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_{feature}");
if std::env::var_os(format!("CARGO_FEATURE_{feature}")).is_some() {
builder = builder.clang_arg(format!("-DAX_CONFIG_{feature}"));
}
}
if let Some(llvm_target) = target.strip_suffix("-softfloat") {
builder = builder.clang_arg(format!("--target={llvm_target}"));
}
for ty in allow_types {
builder = builder.allowlist_type(ty);
}
for var in allow_vars {
builder = builder.allowlist_var(var);
}
builder
.generate()
.expect("Unable to generate C-to-Rust bindings")
.write_to_file(out_file)
.expect("Couldn't write bindings!");
}
let axlibc_include = std::path::Path::new("../../ulib/axlibc/include");
let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
let out_file = out_dir.join("ctypes_gen.rs");
if axlibc_include.exists() {
gen_pthread_mutex(axlibc_include.join("ax_pthread_mutex.h").to_str().unwrap()).unwrap();
gen_c_to_rust_bindings("ctypes.h", &out_file);
} else {
eprintln!(
"cargo:warning=axlibc include directory not found, skipping ctypes_gen.rs regeneration"
);
std::fs::copy("src/ctypes_gen.rs", &out_file)
.expect("pre-generated ctypes_gen.rs is not available");
}
}