2024-11-11 15:19:36 +02:00
|
|
|
use std::{
|
2024-11-12 17:07:06 +02:00
|
|
|
env,
|
|
|
|
fs::{self, DirEntry},
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
process::Command,
|
2024-11-11 15:19:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const RENAMES: &[(&str, &str)] = &[
|
|
|
|
("CUsizeResult", "size_t"),
|
|
|
|
("CIsizeResult", "ssize_t"),
|
|
|
|
("CEofResult", "int"),
|
|
|
|
("CIntCountResult", "int"),
|
|
|
|
("CIntZeroResult", "int"),
|
|
|
|
("CFdResult", "int"),
|
|
|
|
("COffsetResult", "off_t"),
|
|
|
|
("CPidResult", "pid_t"),
|
|
|
|
];
|
|
|
|
|
|
|
|
fn include_dir(d: &DirEntry) -> bool {
|
|
|
|
d.metadata().map(|m| m.is_dir()).unwrap_or(false)
|
|
|
|
&& d.path()
|
|
|
|
.iter()
|
|
|
|
.nth(2)
|
|
|
|
.map_or(false, |c| c.to_str().map_or(false, |x| !x.starts_with("_")))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_header(config_path: impl AsRef<Path>, header_output: impl AsRef<Path>) {
|
|
|
|
let config_path = config_path.as_ref();
|
|
|
|
let header_output = header_output.as_ref();
|
|
|
|
let relative_path = config_path
|
|
|
|
.strip_prefix("src/headers")
|
|
|
|
.ok()
|
|
|
|
.and_then(|p| p.parent())
|
|
|
|
.and_then(|p| p.to_str())
|
|
|
|
.unwrap()
|
|
|
|
.replace("_", "/");
|
|
|
|
// TODO use outer workspace's target directory?
|
2024-11-12 17:07:06 +02:00
|
|
|
let header_path = header_output.join(&relative_path).with_extension("h");
|
2024-11-11 15:19:36 +02:00
|
|
|
let mod_path = config_path.with_file_name("mod.rs");
|
|
|
|
|
|
|
|
let mut config = cbindgen::Config::from_file(config_path).unwrap();
|
|
|
|
|
|
|
|
config
|
|
|
|
.export
|
|
|
|
.rename
|
|
|
|
.extend(RENAMES.into_iter().map(|&(x, y)| (x.into(), y.into())));
|
|
|
|
|
|
|
|
cbindgen::Builder::new()
|
|
|
|
.with_config(config)
|
|
|
|
.with_src(mod_path)
|
|
|
|
.generate()
|
|
|
|
.unwrap()
|
|
|
|
.write_to_file(header_path);
|
|
|
|
}
|
|
|
|
|
2024-11-12 17:07:06 +02:00
|
|
|
fn compile_crt0(arch: &str, output_dir: impl AsRef<Path>) {
|
|
|
|
let output_dir = output_dir.as_ref();
|
|
|
|
let mut command = Command::new("clang");
|
|
|
|
command
|
|
|
|
.arg(format!("--target={}-unknown-none", arch))
|
|
|
|
.arg("-nostdlib")
|
|
|
|
.arg("-nostdinc")
|
|
|
|
.arg("-c")
|
|
|
|
.arg("-o")
|
|
|
|
.arg(output_dir.join("crt0.o"))
|
|
|
|
.arg(format!("crt/{}/crt0.S", arch));
|
|
|
|
|
|
|
|
if !command.status().unwrap().success() {
|
|
|
|
panic!("Couldn't compile crt0.S");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-11 15:19:36 +02:00
|
|
|
fn main() {
|
|
|
|
let target = env::var("TARGET").expect("$TARGET is not set");
|
|
|
|
let profile = env::var("PROFILE").expect("$PROFILE is not set");
|
2024-11-12 17:07:06 +02:00
|
|
|
let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("$CARGO_CFG_TARGET_ARCH is not set");
|
2024-11-11 15:19:36 +02:00
|
|
|
|
2024-11-12 17:07:06 +02:00
|
|
|
let output_dir = PathBuf::from(format!("target/{target}/{profile}"));
|
|
|
|
let header_output = output_dir.join("include");
|
|
|
|
|
|
|
|
compile_crt0(&arch, output_dir);
|
2024-11-11 15:19:36 +02:00
|
|
|
|
|
|
|
fs::read_dir("src/headers")
|
|
|
|
.unwrap()
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(Result::ok)
|
|
|
|
.filter(|d| include_dir(d))
|
|
|
|
.map(|d| d.path().as_path().join("cbindgen.toml"))
|
|
|
|
.filter(|p| p.exists())
|
|
|
|
.for_each(|p| {
|
|
|
|
println!("cargo:rerun-if-changed={:?}", p.parent().unwrap());
|
|
|
|
println!("cargo:rerun-if-changed={:?}", p);
|
|
|
|
println!("cargo:rerun-if-changed={:?}", p.with_file_name("mod.rs"));
|
|
|
|
generate_header(&p, &header_output);
|
|
|
|
});
|
|
|
|
}
|