use std::{env, fs::copy, path::PathBuf};
use libafl_qemu_build::{build_with_bindings, maybe_generate_stub_bindings};
#[macro_export]
macro_rules! assert_unique_feature {
() => {};
($first:tt $(,$rest:tt)*) => {
$(
#[cfg(all(not(any(docsrs, feature = "clippy")), feature = $first, feature = $rest))]
compile_error!(concat!("features \"", $first, "\" and \"", $rest, "\" cannot be used together"));
)*
assert_unique_feature!($($rest),*);
}
}
#[macro_export]
macro_rules! assert_at_least_one_feature {
($($feature:literal),+) => {
#[cfg(not(any($(feature = $feature),+)))]
compile_error!(concat!("At least one of the following features must be enabled:", $(" ", $feature),+));
};
}
pub fn build() {
assert_unique_feature!("usermode", "systemmode");
assert_at_least_one_feature!("usermode", "systemmode");
let emulation_mode = if cfg!(feature = "usermode") {
"usermode"
} else if cfg!(feature = "systemmode") {
"systemmode"
} else {
unreachable!(
"The above macros, `assert_unique_feature` and `assert_at_least_one_feature`, should \
panic before this code is reached."
);
};
assert_unique_feature!(
"arm", "aarch64", "i386", "x86_64", "mips", "ppc", "hexagon", "riscv32", "riscv64"
);
assert_unique_feature!("be", "aarch64", "i386", "x86_64", "hexagon", "riscv32", "riscv64");
let cpu_target = if cfg!(feature = "x86_64") {
"x86_64".to_string()
} else if cfg!(feature = "arm") {
"arm".to_string()
} else if cfg!(feature = "aarch64") {
"aarch64".to_string()
} else if cfg!(feature = "i386") {
"i386".to_string()
} else if cfg!(feature = "mips") {
"mips".to_string()
} else if cfg!(feature = "ppc") {
"ppc".to_string()
} else if cfg!(feature = "riscv32") {
"riscv32".to_string()
} else if cfg!(feature = "riscv64") {
"riscv64".to_string()
} else if cfg!(feature = "hexagon") {
"hexagon".to_string()
} else {
env::var("CPU_TARGET").unwrap_or_else(|_| {
println!(
"cargo:warning=No architecture feature enabled or CPU_TARGET env specified for libafl_qemu, supported: arm, aarch64, hexagon, i386, mips, ppc, riscv32, riscv64, x86_64 - defaulting to x86_64"
);
"x86_64".to_string()
})
};
println!("cargo:rerun-if-env-changed=CPU_TARGET");
println!("cargo:rerun-if-env-changed=LIBAFL_QEMU_GEN_STUBS");
println!("cargo:rustc-cfg=cpu_target=\"{cpu_target}\"");
println!("cargo::rustc-check-cfg=cfg(cpu_target, values(\"x86_64\", \"arm\", \"aarch64\", \"i386\", \"mips\", \"ppc\", \"hexagon\", \"riscv32\", \"riscv64\"))");
let jobs = env::var("NUM_JOBS")
.ok()
.map(|x| str::parse::<u32>(&x).expect("The number of jobs is not a valid integer!"));
let out_dir = env::var("OUT_DIR").unwrap();
let out_dir = PathBuf::from(out_dir);
let bindings_file = out_dir.join("bindings.rs");
let src_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let src_dir = PathBuf::from(src_dir);
let stub_bindings_file = src_dir.join("src/bindings/x86_64_stub_bindings.rs");
if env::var("DOCS_RS").is_ok() || cfg!(feature = "clippy") {
copy(stub_bindings_file, bindings_file).expect("Failed to copy the bindings stub");
return;
}
build_with_bindings(
&cpu_target,
cfg!(feature = "be"),
emulation_mode == "usermode",
jobs,
&bindings_file,
);
println!("cargo:rerun-if-changed={}", stub_bindings_file.display());
maybe_generate_stub_bindings(
&cpu_target,
emulation_mode,
stub_bindings_file.as_path(),
bindings_file.as_path(),
);
}