From bf5edd5c7121af9a1df5ee97989c55907342f610 Mon Sep 17 00:00:00 2001 From: Aleksey Kuznetsov Date: Sat, 29 Jul 2017 16:21:41 +0500 Subject: [PATCH] Implement conditional compilation configuration in build.rs --- lib/cretonne/build.rs | 104 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/lib/cretonne/build.rs b/lib/cretonne/build.rs index 4766a032e0..2653bf54a0 100644 --- a/lib/cretonne/build.rs +++ b/lib/cretonne/build.rs @@ -8,6 +8,13 @@ // OUT_DIR // Directory where generated files should be placed. // +// TARGET +// Target triple provided by Cargo. +// +// CRETONNE_TARGETS (Optional) +// A setting for conditional compilation of isa targets. Possible values can be "native" or +// known isa targets separated by ','. +// // The build script expects to be run from the directory where this build.rs file lives. The // current directory is used to find the sources. @@ -17,6 +24,22 @@ 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()); + + // Configure isa targets cfg. + 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); @@ -45,3 +68,84 @@ fn main() { process::exit(status.code().unwrap()); } } + +/// Represents known ISA target. +#[derive(Copy, Clone)] +enum Isa { + Riscv, + Intel, + Arm32, + Arm64, +} + +impl Isa { + /// Creates isa target using name. + fn new(name: &str) -> Option { + Isa::all() + .iter() + .cloned() + .filter(|isa| isa.name() == name) + .next() + } + + /// Creates isa target from arch. + fn from_arch(arch: &str) -> Option { + Isa::all() + .iter() + .cloned() + .filter(|isa| isa.is_arch_applicable(arch)) + .next() + } + + /// Returns all supported isa targets. + fn all() -> [Isa; 4] { + [Isa::Riscv, Isa::Intel, Isa::Arm32, Isa::Arm64] + } + + /// Returns name of the isa target. + fn name(&self) -> &'static str { + match *self { + Isa::Riscv => "riscv", + Isa::Intel => "intel", + Isa::Arm32 => "arm32", + Isa::Arm64 => "arm64", + } + } + + /// Checks if arch is applicable for the isa target. + fn is_arch_applicable(&self, arch: &str) -> bool { + match *self { + Isa::Riscv => arch == "riscv", + Isa::Intel => ["x86_64", "i386", "i586", "i686"].contains(&arch), + Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"), + Isa::Arm64 => arch == "aarch64", + } + } +} + +/// Returns isa targets to configure conditional compilation. +fn isa_targets(cretonne_targets: Option<&str>, target_triple: &str) -> Result, 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::>(); + let isa_targets = targets.split(',').flat_map(Isa::new).collect::>(); + 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()), + } +}