use std::env;
use std::process;
fn main() {
let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
let cretonne_targets = env::var("CRETONNE_TARGETS").ok();
let cretonne_targets = cretonne_targets.as_ref().map(|s| s.as_ref());
match isa_targets(cretonne_targets, &target_triple) {
Ok(isa_targets) => {
for isa in &isa_targets {
println!("cargo:rustc-cfg=build_{}", isa.name());
}
}
Err(err) => {
eprintln!("Error: {}", err);
process::exit(1);
}
}
println!("Build script generating files in {}", out_dir);
let cur_dir = env::current_dir().expect("Can't access current working directory");
let crate_dir = cur_dir.as_path();
println!(
"cargo:rerun-if-changed={}",
crate_dir.join("build.rs").to_string_lossy()
);
let meta_dir = crate_dir.join("meta");
let build_script = meta_dir.join("build.py");
let status = process::Command::new("python")
.current_dir(crate_dir)
.arg("-B")
.arg(build_script)
.arg("--out-dir")
.arg(out_dir)
.status()
.expect("Failed to launch second-level build script");
if !status.success() {
process::exit(status.code().unwrap());
}
}
#[derive(Copy, Clone)]
enum Isa {
Riscv,
X86,
Arm32,
Arm64,
}
impl Isa {
fn new(name: &str) -> Option<Self> {
Isa::all()
.iter()
.cloned()
.filter(|isa| isa.name() == name)
.next()
}
fn from_arch(arch: &str) -> Option<Isa> {
Isa::all()
.iter()
.cloned()
.filter(|isa| isa.is_arch_applicable(arch))
.next()
}
fn all() -> [Isa; 4] {
[Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
}
fn name(&self) -> &'static str {
match *self {
Isa::Riscv => "riscv",
Isa::X86 => "x86",
Isa::Arm32 => "arm32",
Isa::Arm64 => "arm64",
}
}
fn is_arch_applicable(&self, arch: &str) -> bool {
match *self {
Isa::Riscv => arch == "riscv",
Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch),
Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"),
Isa::Arm64 => arch == "aarch64",
}
}
}
fn isa_targets(cretonne_targets: Option<&str>, target_triple: &str) -> Result<Vec<Isa>, String> {
match cretonne_targets {
Some("native") => {
Isa::from_arch(target_triple.split('-').next().unwrap())
.map(|isa| vec![isa])
.ok_or_else(|| {
format!(
"no supported isa found for target triple `{}`",
target_triple
)
})
}
Some(targets) => {
let unknown_isa_targets = targets
.split(',')
.filter(|target| Isa::new(target).is_none())
.collect::<Vec<_>>();
let isa_targets = targets.split(',').flat_map(Isa::new).collect::<Vec<_>>();
match (unknown_isa_targets.is_empty(), isa_targets.is_empty()) {
(true, true) => Ok(Isa::all().to_vec()),
(true, _) => Ok(isa_targets),
(_, _) => Err(format!(
"unknown isa targets: `{}`",
unknown_isa_targets.join(", ")
)),
}
}
None => Ok(Isa::all().to_vec()),
}
}