From ffe054aaa95b586ca4bdb1e1e5ccaddc5c22e997 Mon Sep 17 00:00:00 2001 From: Boris-Chengbiao Zhou <bobo1239@web.de> Date: Fri, 2 Aug 2019 15:42:21 +0200 Subject: [PATCH] Various improvements to the Rust bindings (#401) * Fix Rust bindings * Various small improvements for the Rust bindings * Remove unused dependencies * Use the cmake crate to compile keystone * Add Windows support to Rust bindings * Cleanup doc a bit * Fix symlink path * Link to C++ standard library * Build all keystone targets --- bindings/rust/Cargo.toml | 10 ++-- bindings/rust/Makefile | 9 ++- bindings/rust/README.md | 1 + bindings/rust/keystone-sys/Cargo.toml | 12 ++-- bindings/rust/keystone-sys/build.rs | 82 +++++++++++---------------- bindings/rust/keystone-sys/src/lib.rs | 11 ++-- bindings/rust/src/lib.rs | 12 ++-- 7 files changed, 60 insertions(+), 77 deletions(-) diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index b41e598..b612c6c 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "keystone" -version = "0.9.1" +version = "0.10.0" authors = [ "Remco Verhoef <remco.verhoef@dutchcoders.io>", "Tasuku SUENAGA a.k.a. gunyarakun <tasuku-s-github@titech.ac>" @@ -10,17 +10,17 @@ license = "GPL-2.0" readme = "README.md" repository = "https://github.com/keystone-engine/keystone" include = [ - "src/*", "tests/*", "Cargo.toml", "COPYING", "README.md", - "keystone-sys/*" + "src/*", "tests/*", "Cargo.toml", "COPYING", "README.md" ] [dependencies] -bitflags = "1.0" libc = "0.2" -keystone-sys = { path = "keystone-sys", version = "0.9.1" } +keystone-sys = { path = "keystone-sys", version = "0.10" } [features] default = [] use_system_keystone = ["keystone-sys/use_system_keystone"] build_keystone_cmake = ["keystone-sys/build_keystone_cmake"] + +[workspace] diff --git a/bindings/rust/Makefile b/bindings/rust/Makefile index 7a3f169..05a3a38 100644 --- a/bindings/rust/Makefile +++ b/bindings/rust/Makefile @@ -9,15 +9,18 @@ package: keystone-sys/keystone cd keystone-sys && cargo package -vv cargo package -vv +# For packaging we need to embed the keystone source in the crate keystone-sys/keystone: rsync -a ../.. keystone-sys/keystone --exclude bindings --filter ":- ../../.gitignore" clean: - rm -rf target/ keystone-sys/target/ keystone-sys/keystone/ + rm -rf keystone-sys/keystone/ + cargo clean check: - cargo test +# Make sure to only use one test thread as keystone isn't thread-safe + cargo test -- --test-threads=1 gen_const: - cd .. && python const_generator.py rust + cd .. && python2 const_generator.py rust cargo fmt diff --git a/bindings/rust/README.md b/bindings/rust/README.md index 32cb7a0..2a608ea 100644 --- a/bindings/rust/README.md +++ b/bindings/rust/README.md @@ -39,6 +39,7 @@ If you want to use keystone already installed in the system, specify `use_system ``` [dependencies.keystone] version = "0.10.0" +default-features = false features = ["use_system_keystone"] ``` diff --git a/bindings/rust/keystone-sys/Cargo.toml b/bindings/rust/keystone-sys/Cargo.toml index f791327..adff79f 100644 --- a/bindings/rust/keystone-sys/Cargo.toml +++ b/bindings/rust/keystone-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "keystone-sys" -version = "0.9.0" +version = "0.10.0" authors = [ "Remco Verhoef <remco.verhoef@dutchcoders.io>", "Tasuku SUENAGA a.k.a. gunyarakun <tasuku-s-github@titech.ac>" @@ -10,21 +10,17 @@ repository = "https://github.com/keystone-engine/keystone" documentation = "https://docs.rs/keystone/" license = "GPL-2.0" build = "build.rs" -exclude = [ - "keystone/build/**" -] [build-dependencies] -build-helper = "0.1" -os_type = "2.0" pkg-config = { optional = true, version = "0.3" } +cmake = { optional = true, version = "0.1" } [dependencies] bitflags = "1.0" libc = "0.2" [features] -default = [] +default = ["build_keystone_cmake"] use_system_keystone = ["pkg-config"] -build_keystone_cmake = [] +build_keystone_cmake = ["cmake"] diff --git a/bindings/rust/keystone-sys/build.rs b/bindings/rust/keystone-sys/build.rs index 2f698ab..599fc05 100644 --- a/bindings/rust/keystone-sys/build.rs +++ b/bindings/rust/keystone-sys/build.rs @@ -1,42 +1,45 @@ +#[cfg(feature = "build_keystone_cmake")] +extern crate cmake; #[cfg(feature = "use_system_keystone")] extern crate pkg_config; -use std::env; -use std::path::PathBuf; -use std::process::Command; +#[cfg(all(not(windows), feature = "build_keystone_cmake"))] +use std::os::unix::fs::symlink; +#[cfg(all(windows, feature = "build_keystone_cmake"))] +use std::os::windows::fs::symlink_dir as symlink; -fn build_with_cmake() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let cmake_dir = PathBuf::from("keystone"); - let build_dir = cmake_dir.join("build"); +#[cfg(feature = "build_keystone_cmake")] +use std::path::Path; - if !cmake_dir.exists() { - run(Command::new("ln").arg("-s").arg("../../..").arg("keystone")); +#[cfg(feature = "build_keystone_cmake")] +fn build_with_cmake() { + if !Path::new("keystone").exists() { + // This only happens when using the crate via a `git` reference as the + // published version already embeds keystone's source. + let pwd = std::env::current_dir().unwrap(); + let keystone_dir = pwd.ancestors().skip(3).next().unwrap(); + symlink(keystone_dir, "keystone").expect("failed to symlink keystone"); } - run(Command::new("mkdir") - .current_dir(&cmake_dir) - .arg("-p") - .arg("build")); - - run(Command::new("../make-share.sh").current_dir(&build_dir)); + let dest = cmake::Config::new("keystone") + .define("BUILD_LIBS_ONLY", "1") + .define("BUILD_SHARED_LIBS", "OFF") + .define("LLVM_TARGETS_TO_BUILD", "all") + // Prevent python from leaving behind `.pyc` files which break `cargo package` + .env("PYTHONDONTWRITEBYTECODE", "1") + .build(); - run(Command::new("cmake").current_dir(&build_dir).args(&[ - &format!("-DCMAKE_INSTALL_PREFIX={}", out_dir.display()), - "-DCMAKE_BUILD_TYPE=Release", - "-DBUILD_LIBS_ONLY=1", - "-DCMAKE_OSX_ARCHITECTURES=", - "-DBUILD_SHARED_LIBS=ON", - "-DLLVM_TARGET_ARCH=host", - "-G", - "Unix Makefiles", - "..", - ])); - - run(Command::new("make").current_dir(&build_dir).arg("install")); - - println!("cargo:rustc-link-search=native={}/lib", out_dir.display()); + println!("cargo:rustc-link-search=native={}/lib", dest.display()); println!("cargo:rustc-link-lib=keystone"); + + let target = std::env::var("TARGET").unwrap(); + if target.contains("apple") { + println!("cargo:rustc-link-lib=dylib=c++"); + } else if target.contains("linux") { + println!("cargo:rustc-link-lib=dylib=stdc++"); + } else if target.contains("windows") { + println!("cargo:rustc-link-lib=dylib=shell32"); + } } fn main() { @@ -44,24 +47,7 @@ fn main() { #[cfg(feature = "use_system_keystone")] pkg_config::find_library("keystone").expect("Could not find system keystone"); } else { + #[cfg(feature = "build_keystone_cmake")] build_with_cmake(); } } - -fn run(cmd: &mut Command) { - println!("run: {:?}", cmd); - let status = match cmd.status() { - Ok(s) => s, - Err(ref e) => fail(&format!("failed to execute command: {}", e)), - }; - if !status.success() { - fail(&format!( - "command did not execute successfully, got: {}", - status - )); - } -} - -fn fail(s: &str) -> ! { - panic!("\n{}\n\nbuild script failed, must exit now", s); -} diff --git a/bindings/rust/keystone-sys/src/lib.rs b/bindings/rust/keystone-sys/src/lib.rs index c063c48..fa8337f 100644 --- a/bindings/rust/keystone-sys/src/lib.rs +++ b/bindings/rust/keystone-sys/src/lib.rs @@ -9,17 +9,16 @@ extern crate libc; pub mod keystone_const; -use std::fmt; +use keystone_const::{Arch, Error, Mode, OptionType, OptionValue}; use std::ffi::CStr; +use std::fmt; use std::os::raw::c_char; -use keystone_const::{Arch, Error, Mode, OptionType, OptionValue}; #[allow(non_camel_case_types)] pub type ks_handle = libc::size_t; -#[link(name = "keystone")] extern "C" { - pub fn ks_version(major: *const u32, minor: *const u32) -> u32; + pub fn ks_version(major: *mut u32, minor: *mut u32) -> u32; pub fn ks_arch_supported(arch: Arch) -> bool; pub fn ks_open(arch: Arch, mode: Mode, engine: *mut ks_handle) -> Error; pub fn ks_asm( @@ -38,8 +37,8 @@ extern "C" { } impl Error { - pub fn msg(&self) -> String { - error_msg(*self) + pub fn msg(self) -> String { + error_msg(self) } } diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 5bcd5bf..2952880 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -1,6 +1,6 @@ -//! Keystone Assembler Engine (www.keystone-engine.org) */ -//! By Nguyen Anh Quynh <aquynh@gmail.com>, 2016 */ -//! Rust bindings by Remco Verhoef <remco@dutchcoders.io>, 2016 */ +//! Keystone Assembler Engine (www.keystone-engine.org) \ +//! By Nguyen Anh Quynh <aquynh@gmail.com>, 2016 \ +//! Rust bindings by Remco Verhoef <remco@dutchcoders.io>, 2016 //! //! ```rust //! extern crate keystone; @@ -16,12 +16,10 @@ //! } //! ``` -#![doc(html_root_url = "https://keystone/doc/here/v1")] - extern crate keystone_sys as ffi; extern crate libc; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use std::fmt; pub use ffi::keystone_const::*; @@ -66,7 +64,7 @@ pub fn arch_supported(arch: Arch) -> bool { pub fn error_msg(error: Error) -> String { unsafe { - CStr::from_ptr(ffi::ks_strerror(error.bits())) + CStr::from_ptr(ffi::ks_strerror(error)) .to_string_lossy() .into_owned() } -- GitLab