use std::env; use std::path::Path; use std::process::Command; fn main() { println!("cargo:rerun-if-changed=client"); let out_dir = env::var("OUT_DIR").unwrap(); let client_bin = build_client(&out_dir); setup_nyx(&out_dir); create_nyx_workdir(&out_dir, &client_bin); } #[track_caller] fn shell(cwd: impl AsRef, command_string: &str) { println!( "cargo:warning=Running ({}) {command_string}", cwd.as_ref().display() ); let cwd = cwd.as_ref(); let mut parts = command_string.split(" "); let command_name = parts.next().unwrap(); let mut command = Command::new(command_name); command.current_dir(cwd); command.stdout(std::process::Stdio::inherit()); command.stderr(std::process::Stdio::inherit()); command.args(parts); let mut process = command.spawn().unwrap(); let exit_status = process.wait().unwrap(); if !exit_status.success() { panic!( "Command failed with {exit_status}: {}> {command_string}", cwd.display() ); } } /// Builds the client and returns the path to its binary fn build_client(out_dir: &str) -> String { // Change the target dir to avoid a cargo target dir deadlock shell( "client", &format!("cargo build --release --target-dir {out_dir}/client_target"), ); format!("{out_dir}/client_target/release/client") } /// Downloads and compiles qemu-nyx and packer and compiles them for the current architecture /// This means that cross-compilation is not supported fn setup_nyx(out_dir: &str) { let packer_path = std::path::PathBuf::from(format!("{out_dir}/packer")); let qemu_path = std::path::PathBuf::from(format!("{out_dir}/QEMU-Nyx")); if !packer_path.exists() { shell(out_dir, "git clone https://github.com/nyx-fuzz/packer/"); } if !qemu_path.exists() { println!("cargo:warning=Cloning and building QEMU-Nyx. This may take a while..."); shell( out_dir, "git clone https://github.com/nyx-fuzz/QEMU-Nyx --depth 1", ); let is_debug_build = match env::var("DEBUG").unwrap().as_str() { "true" => true, "false" => false, other => panic!("Invalid value for DEBUG: {other}"), }; let qemu_compile_mode = if is_debug_build { "debug_static" } else { "lto" }; shell( qemu_path, &format!("bash compile_qemu_nyx.sh {qemu_compile_mode}"), ); } } fn create_nyx_workdir(out_dir: &str, client_bin: &str) { // Create the directory and move required binaries to it shell( out_dir, &format!( "python3 packer/packer/nyx_packer.py {client_bin} build afl processor_trace --fast_reload_mode --purge" ), ); // Create the nyx config shell( out_dir, "python3 packer/packer/nyx_config_gen.py build Kernel", ); // Pass the path to the build directory to src/main.rs println!("cargo:rustc-env=NYX_SHAREDIR={out_dir}/build") }