use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use ::regex::*;
pub const BUILD_DIR: &str = "DRIO_BUILD_DIR";
#[cfg(target_os = "windows")]
pub const PLATFORM: &str = "WINDOWS";
#[cfg(target_os = "linux")]
pub const PLATFORM: &str = "LINUX";
#[cfg(target_os = "windows")]
pub const BUILD_TARGET: &str = "ALL_BUILD";
#[cfg(target_os = "linux")]
pub const BUILD_TARGET: &str = "all";
#[cfg(target_arch = "x86")]
pub const ARCHITECTURE: &str = "X86_32";
#[cfg(target_arch = "x86_64")]
pub const ARCHITECTURE: &str = "X86_64";
#[cfg(target_arch = "arm")]
pub const ARCHITECTURE: &str = "ARM_32";
#[cfg(target_arch = "aarch64")]
pub const ARCHITECTURE: &str = "ARM_64";
#[cfg(any(target_arch = "x86", target_arch = "arm"))]
pub const LIB_PATH: &str = "lib32";
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
pub const LIB_PATH: &str = "lib64";
fn version_ok(generated_rs: &Path) -> bool {
let mut fin = match File::open(generated_rs) {
Ok(f) => f,
Err(e) => {
eprintln!("Failed to open generated bindings : {}", e);
return false;
}
};
let mut contents = String::new();
if let Err(e) = fin.read_to_string(&mut contents) {
eprintln!("Failed to read generated bindings : {}", e);
return false;
}
let re = Regex::new(r"_USES_DR_VERSION_.+=\s*(\d+);").unwrap();
for cap in re.captures_iter(&contents) {
let version: usize = match cap[1].parse() {
Ok(v) => v,
Err(e) => {
eprintln!("Failed to parse version '{}' : {}", &cap[1], e);
return false;
}
};
let major = version / 100;
let minor = version % 100;
if major.to_string() != env!("CARGO_PKG_VERSION_MAJOR") {
panic!("Major version ({}) of {} does not match the current dynamorio-sys crate version ({})...", major, BUILD_DIR, env!("CARGO_PKG_VERSION_MAJOR"));
}
if minor.to_string() != env!("CARGO_PKG_VERSION_MINOR") {
panic!("Minor version ({}) of {} does not match the current dynamorio-sys crate version ({})...", minor, BUILD_DIR, env!("CARGO_PKG_VERSION_MINOR"));
}
}
true
}
fn main() {
let build_dir = match std::env::var(BUILD_DIR) {
Ok(build_dir) => {
println!("cargo:rerun-if-changed={}", build_dir);
PathBuf::from(build_dir)
}
_ => {
println!("cargo:rerun-if-changed=dynamorio");
#[cfg(target_os = "windows")]
let mut path = cmake::Config::new("dynamorio")
.define("BUILD_CLIENTS", "NO")
.define("BUILD_DOCS", "NO")
.define("BUILD_DRSTATS", "NO")
.define("BUILD_SAMPLES", "NO")
.define("BUILD_TESTS", "NO")
.define("BUILD_TOOLS", "NO")
.build_target(BUILD_TARGET)
.profile("RelWithDebInfo")
.build();
#[cfg(target_os = "linux")]
let mut path = cmake::Config::new("dynamorio")
.define("BUILD_CLIENTS", "NO")
.define("BUILD_DOCS", "NO")
.define("BUILD_SAMPLES", "NO")
.define("BUILD_TESTS", "NO")
.define("BUILD_TOOLS", "NO")
.define("CMAKE_ASM_COMPILER", "/usr/bin/as")
.define("CMAKE_ASM_FLAGS", "")
.build_target(BUILD_TARGET)
.profile("RelWithDebInfo")
.build();
path.push("build");
path
}
};
let mut extra_args = vec![];
let mut libs = vec!["dynamorio"];
extra_args.push(format!("-D{}", PLATFORM));
extra_args.push(format!("-D{}", ARCHITECTURE));
#[cfg(windows)]
{
let kits = windows_kits::WindowsKits::new().unwrap();
let include_path = kits
.get_version_dir(windows_kits::DirectoryType::Headers)
.unwrap();
for name in &["shared", "ucrt", "um"] {
extra_args.push(format!("-I{}", include_path.join(name).to_string_lossy()));
}
}
extra_args.push(format!("-I{}", build_dir.join("include").to_string_lossy()));
extra_args.push(format!(
"-I{}",
build_dir.join("ext/include").to_string_lossy()
));
println!(
"cargo:rustc-link-search={}",
build_dir.join(LIB_PATH).join("release").to_string_lossy()
);
println!(
"cargo:rustc-link-search={}",
build_dir
.join("ext")
.join(LIB_PATH)
.join("release")
.to_string_lossy()
);
if cfg!(feature = "bbdup") {
extra_args.push("-D __FEATURE_BBDUP".to_string());
libs.push("drbbdup");
}
if cfg!(feature = "containers") {
extra_args.push("-D __FEATURE_CONTAINERS".to_string());
libs.push("drcontainers");
}
if cfg!(feature = "covlib") {
extra_args.push("-D __FEATURE_COVLIB".to_string());
libs.push("drcovlib");
}
if cfg!(feature = "mgr") {
extra_args.push("-D __FEATURE_MGR".to_string());
libs.push("drmgr");
}
if cfg!(feature = "option") {
extra_args.push("-D __FEATURE_OPTION".to_string());
}
if cfg!(feature = "reg") {
extra_args.push("-D __FEATURE_REG".to_string());
libs.push("drreg");
}
if cfg!(feature = "syms") {
extra_args.push("-D __FEATURE_SYMS".to_string());
libs.push("drsyms");
}
if cfg!(feature = "util") {
extra_args.push("-D __FEATURE_UTIL".to_string());
libs.push("drutil");
}
if cfg!(feature = "wrap") {
extra_args.push("-D __FEATURE_WRAP".to_string());
libs.push("drwrap");
}
if cfg!(feature = "x") {
extra_args.push("-D __FEATURE_X".to_string());
libs.push("drx");
}
for lib in libs {
#[cfg(target_os = "linux")]
println!("cargo:rustc-link-lib={}", lib);
#[cfg(target_os = "windows")]
println!("cargo:rustc-link-lib={}", lib);
}
println!("cargo:rerun-if-changed=src/wrapper.h");
println!("{:?}", extra_args);
let bindings = bindgen::Builder::default()
.header("src/wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.use_core()
.size_t_is_usize(true)
.allowlist_function("__wrap_.*")
.allowlist_function("_?[dD][rR].*")
.allowlist_type("_?[dD][rR].*")
.allowlist_var("_?[dD][rR].*")
.allowlist_function("instr_.*")
.allowlist_function("instrlist_.*")
.allowlist_function("opnd_.*")
.allowlist_var("INVALID_FILE")
.allowlist_var("OP_.*")
.allowlist_var("OPSZ_.*")
.allowlist_var("SPILL_SLOT_.*")
.allowlist_var("_USES_DR_VERSION_")
.bitfield_enum("dr_emit_flags_t")
.bitfield_enum("dr_exit_flags_t")
.rustified_enum("dr_spill_slot_t")
.bitfield_enum("dr_mcontext_flags_t")
.rustified_enum("drsym_error_t")
.bitfield_enum("drsym_flags_t")
.clang_args(extra_args)
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let out_file = out_path.join("bindings.rs");
bindings
.write_to_file(&out_file)
.expect("Couldn't write bindings!");
if !version_ok(&out_file) {
std::fs::remove_file(&out_file).unwrap();
}
println!("cargo:rerun-if-changed=src/wrapper.c");
cc::Build::new()
.define(PLATFORM, None)
.define(ARCHITECTURE, None)
.include(build_dir.join("include"))
.include(build_dir.join("ext/include"))
.file("src/wrapper.c")
.compile("wrapper");
}