diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 8efb1887..195e9e0d 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -18,12 +18,7 @@ fn find_unicorn(unicorn_dir: &Path) -> Option { None } -fn out_dir() -> PathBuf { - let out_dir = env::var("OUT_DIR").unwrap(); - Path::new(&out_dir).to_path_buf() -} - -fn download_unicorn() -> PathBuf { +fn download_unicorn() -> Option { // https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-tar let pkg_version; if let Ok(unicorn_version) = env::var("UNICORN_VERSION") { @@ -31,7 +26,7 @@ fn download_unicorn() -> PathBuf { } else { pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); } - let out_dir = out_dir(); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let client = reqwest::blocking::Client::new(); let resp = client .get(format!( @@ -48,107 +43,85 @@ fn download_unicorn() -> PathBuf { let mut archive = Archive::new(tar); archive.unpack(&out_dir).unwrap(); - find_unicorn(&out_dir).unwrap() + match find_unicorn(&out_dir) { + Some(dir) => Some(String::from(out_dir.join(dir).to_str()?)), + None => None, + } } -#[allow(clippy::too_many_lines)] +#[allow(clippy::branches_sharing_code)] fn main() { let profile = env::var("PROFILE").unwrap(); - if let Some(unicorn_dir) = find_unicorn(&out_dir()) { - let rust_build_path = unicorn_dir.join("rust_build"); + let unicorn_dir = download_unicorn().unwrap(); + + println!("cargo:rerun-if-changed={}", &unicorn_dir); + + // We don't use TARGET since we can't cross-build. + if env::consts::OS == "windows" { + // Windows + let mut cmd = Command::new("cmake"); + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off") + .arg("-G") + .arg("Visual Studio 16 2019"); + + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + } else { + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + } + + cmd.output() + .expect("Fail to create build directory on Windows."); + + let mut platform = "x64"; + let mut conf = "Release"; + if std::mem::size_of::() == 4 { + platform = "Win32"; + } + if profile == "debug" { + conf = "Debug"; + } + + Command::new("msbuild") + .current_dir(format!("{}/rust_build", &unicorn_dir)) + .arg("unicorn.sln") + .arg("-m") + .arg("-p:Platform=".to_owned() + platform) + .arg("-p:Configuration=".to_owned() + conf) + .output() + .expect("Fail to build unicorn on Win32."); println!( - "cargo:rustc-link-search={}", - rust_build_path.to_str().unwrap() - ); - println!( - "cargo:rustc-link-search={}", - rust_build_path.join("Debug").to_str().unwrap() - ); - println!( - "cargo:rustc-link-search={}", - rust_build_path.join("Release").to_str().unwrap() + "cargo:rustc-link-search={}/rust_build/{}", + unicorn_dir, conf ); } else { - let unicorn_dir = if env::var("CI").is_ok() { - Path::new("..").join("..") - } else { - println!("cargo:warning=Unicorn not found. Downloading..."); - download_unicorn() - }; - - let rust_build_path = unicorn_dir.join("rust_build"); - + // Most Unix-like systems let mut cmd = Command::new("cmake"); + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off"); - // We don't use TARGET since we can't cross-build. - if env::consts::OS == "windows" { - // Windows - cmd.current_dir(&unicorn_dir) - .arg("-B") - .arg("rust_build") - .arg("-DUNICORN_BUILD_SHARED=off") - .arg("-G") - .arg("Visual Studio 16 2019"); - - if profile == "debug" { - cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); - } else { - cmd.arg("-DCMAKE_BUILD_TYPE=Release"); - } - - cmd.output() - .expect("Fail to create build directory on Windows."); - - let mut platform = "x64"; - let mut conf = "Release"; - if std::mem::size_of::() == 4 { - platform = "Win32"; - } - if profile == "debug" { - conf = "Debug"; - } - - Command::new("msbuild") - .current_dir(&rust_build_path) - .arg("unicorn.sln") - .arg("-m") - .arg("-p:Platform=".to_owned() + platform) - .arg("-p:Configuration=".to_owned() + conf) - .output() - .expect("Fail to build unicorn on Win32."); - println!( - "cargo:rustc-link-search={}", - rust_build_path.join(conf).to_str().unwrap() - ); + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); } else { - // Most Unix-like systems - let mut cmd = Command::new("cmake"); - cmd.current_dir(&unicorn_dir) - .arg("-B") - .arg("rust_build") - .arg("-DUNICORN_BUILD_SHARED=off"); - - if profile == "debug" { - cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); - } else { - cmd.arg("-DCMAKE_BUILD_TYPE=Release"); - } - - cmd.output() - .expect("Fail to create build directory on *nix."); - - Command::new("make") - .current_dir(&rust_build_path) - .arg("-j6") - .output() - .expect("Fail to build unicorn on *nix."); - - println!( - "cargo:rustc-link-search={}", - rust_build_path.to_str().unwrap() - ); + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); } + + cmd.output() + .expect("Fail to create build directory on *nix."); + + Command::new("make") + .current_dir(format!("{}/rust_build", &unicorn_dir)) + .arg("-j6") + .output() + .expect("Fail to build unicorn on *nix."); + + println!("cargo:rustc-link-search={}/rust_build", unicorn_dir); } // This is a workaround for Unicorn static link since libunicorn.a is also linked again lib*-softmmu.a. @@ -157,7 +130,7 @@ fn main() { // // Lazymio(@wtdcode): Why do I stick to static link? See: https://github.com/rust-lang/cargo/issues/5077 println!("cargo:rustc-link-lib=unicorn"); - for arch in &[ + for arch in [ "x86_64", "arm", "armeb", @@ -174,11 +147,10 @@ fn main() { "m68k", "ppc", "ppc64", - ] { + ] + .iter() + { println!("cargo:rustc-link-lib={}-softmmu", arch); } println!("cargo:rustc-link-lib=unicorn-common"); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=src"); } diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index 300e1220..2cf7faf9 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -80,12 +80,12 @@ extern "C" { pub struct UcHook<'a, D: 'a, F: 'a> { pub callback: F, - pub uc: Unicorn<'a, D>, + pub uc: Unicorn, } -pub trait IsUcHook<'a> {} +pub trait IsUcHook {} -impl<'a, D, F> IsUcHook<'a> for UcHook<'a, D, F> {} +impl<'a, D, F> IsUcHook for UcHook<'a, D, F> {} pub extern "C" fn code_hook_proxy( uc: uc_handle, diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 7b5c35c6..f96b795f 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -77,16 +77,15 @@ impl Drop for Context { } } -pub struct UnicornInner<'a, D> { +pub struct UnicornInner { pub uc: uc_handle, pub arch: Arch, /// to keep ownership over the hook for this uc instance's lifetime - pub hooks: Vec<(ffi::uc_hook, Box + 'a>)>, - pub data: D, + pub hooks: Vec<(ffi::uc_hook, Box)>, } /// Drop UC -impl<'a, D> Drop for UnicornInner<'a, D> { +impl Drop for UnicornInner { fn drop(&mut self) { if !self.uc.is_null() { unsafe { ffi::uc_close(self.uc) }; @@ -96,25 +95,25 @@ impl<'a, D> Drop for UnicornInner<'a, D> { } /// A Unicorn emulator instance. -pub struct Unicorn<'a, D: 'a> { - inner: Rc>>, +pub struct Unicorn { + inner: Rc>>, } -impl<'a> Unicorn<'a, ()> { +impl<'a> Unicorn<'a> { /// Create a new instance of the unicorn engine for the specified architecture /// and hardware mode. - pub fn new(arch: Arch, mode: Mode) -> Result, uc_error> { + pub fn new(arch: Arch, mode: Mode) -> Result, uc_error> { Self::new_with_data(arch, mode, ()) } } -impl<'a, D> Unicorn<'a, D> +impl<'a, D> Unicorn<'a> where D: 'a, { /// Create a new instance of the unicorn engine for the specified architecture /// and hardware mode. - pub fn new_with_data(arch: Arch, mode: Mode, data: D) -> Result, uc_error> { + pub fn new_with_data(arch: Arch, mode: Mode, data: D) -> Result, uc_error> { let mut handle = core::ptr::null_mut(); let err = unsafe { ffi::uc_open(arch, mode, &mut handle) }; if err == uc_error::OK {