Skip to content

Commit 95f819e

Browse files
ElykDeerverylazyguy
authored andcommitted
Resolves Vector35#2521; Rust API Linking Errors
1 parent 6d2b50a commit 95f819e

File tree

11 files changed

+551
-136
lines changed

11 files changed

+551
-136
lines changed

rust/README.md

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
> :warning: **These bindings are in a very early beta, only have partial support for the core APIs and are still actively under development. Compatibility _will_ break and conventions _will_ change! They are being used for core Binary Ninja features however, so we expect much of what is already there to be reliable enough to build on, just don't be surprised if your plugins/scripts need to hit a moving target.**
66
7-
> :warning: This project requires Rust Nightly to build with those fancy linker arguments
7+
> :warning: This project requires **Rust Nightly** to build with those fancy linker arguments
88
99

1010
## Dependencies
@@ -16,58 +16,7 @@ Rust **Nightly**
1616

1717
## How to use
1818

19-
### To write a plugin:
20-
21-
`Cargo.toml`:
22-
```
23-
[lib]
24-
crate-type = ["cdylib"]
25-
26-
[dependencies]
27-
binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
28-
```
29-
30-
`src/main.rs`:
31-
See the `./examples/`. Plugin registration commands are in `binaryninja::command::*`
32-
33-
34-
### To write a headless script:
35-
36-
`Cargo.toml`:
37-
```
38-
[dependencies]
39-
binaryninja = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
40-
```
41-
42-
`src/main.rs`:
43-
```
44-
use binaryninja::version;
45-
use binaryninja::architecture::Architecture;
46-
use binaryninja::binaryview::{BinaryViewBase, BinaryViewExt};
47-
48-
fn main() {
49-
println!("BinaryNinja Version: `{}`", version());
50-
51-
println!("Loading plugins..."); // This loads all the core architecture, platform, etc plugins
52-
binaryninja::headless::init();
53-
54-
println!("Loading binary...");
55-
let bv = binaryninja::open_view("/bin/cat").expect("Couldn't open `/bin/cat`");
56-
57-
println!("Filename: `{}`", bv.metadata().filename());
58-
println!("File size: `{:#x}`", bv.len());
59-
println!("Function count: {}", bv.functions().len());
60-
61-
for func in &bv.functions() {
62-
println!(" `{}`:", func.symbol().full_name());
63-
}
64-
65-
// Important! You need to call shutdown or your script will hang forever
66-
binaryninja::headless::shutdown();
67-
}
68-
```
69-
70-
All headless scripts should call both `binaryninja::headless::init()` and `binaryninja::headless::shutdown()`.
19+
See [`examples/template`](examples/template).
7120

7221
---
7322

rust/binaryninjacore-sys/build.rs

Lines changed: 19 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,86 +6,12 @@ use std::io::BufRead;
66
use std::io::BufReader;
77
use std::path::PathBuf;
88

9-
#[cfg(target_os = "macos")]
10-
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
11-
12-
#[cfg(target_os = "linux")]
13-
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
14-
15-
#[cfg(windows)]
16-
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
17-
18-
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
19-
fn link_path() -> PathBuf {
20-
use std::io::prelude::*;
21-
22-
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
23-
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
24-
25-
File::open(lastrun)
26-
.and_then(|f| {
27-
let mut binja_path = String::new();
28-
let mut reader = BufReader::new(f);
29-
30-
reader.read_line(&mut binja_path)?;
31-
Ok(PathBuf::from(binja_path.trim()))
32-
})
33-
.unwrap_or_else(|_| {
34-
#[cfg(target_os = "macos")]
35-
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
36-
37-
#[cfg(target_os = "linux")]
38-
return home.join("binaryninja");
39-
40-
#[cfg(windows)]
41-
return PathBuf::from(env::var("PROGRAMFILES").unwrap())
42-
.join("Vector35\\BinaryNinja\\");
43-
})
44-
}
45-
469
fn main() {
4710
println!("cargo:rerun-if-changed=../../binaryninjacore.h");
4811

4912
//Cargo's output directory
5013
let out_dir = env::var("OUT_DIR").unwrap();
5114

52-
// Detect for custom Clang or LLVM installations (BN devs/build server)
53-
let llvm_dir = env::var("LIBCLANG_PATH");
54-
let llvm_version = env::var("LLVM_VERSION");
55-
let llvm_install_dir = env::var("LLVM_INSTALL_DIR");
56-
57-
// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
58-
let install_path = env::var("BINARYNINJADIR")
59-
.map(PathBuf::from)
60-
.unwrap_or_else(|_| link_path());
61-
62-
#[cfg(target_os = "linux")]
63-
println!(
64-
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
65-
install_path.to_str().unwrap(),
66-
install_path.to_str().unwrap(),
67-
);
68-
69-
#[cfg(not(target_os = "linux"))]
70-
println!(
71-
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
72-
install_path.to_str().unwrap(),
73-
install_path.to_str().unwrap(),
74-
);
75-
76-
// TODO : Clean this up even more
77-
#[warn(unused_assignments)]
78-
let is_mac = {
79-
#[cfg(target_os = "macos")]
80-
{
81-
true
82-
}
83-
#[cfg(not(target_os = "macos"))]
84-
{
85-
false
86-
}
87-
};
88-
8915
let current_line = "#define BN_CURRENT_UI_ABI_VERSION ";
9016
let minimum_line = "#define BN_MINIMUM_UI_ABI_VERSION ";
9117
let mut current_version = "0".to_string();
@@ -100,8 +26,6 @@ fn main() {
10026
}
10127
}
10228

103-
// Difference between global LLVM/Clang install and custom LLVM/Clang install...
104-
// First option is for the build server, second option is being nice to our dev who have `LLVM_INSTALL_DIR` set, third is for people with "normal" setups (and Macs)
10529
let mut bindings = bindgen::builder()
10630
.header("../../binaryninjacore.h")
10731
.clang_arg("-std=c++17")
@@ -121,13 +45,25 @@ fn main() {
12145
minimum_version
12246
))
12347
.rustified_enum("BN.*");
124-
if let (false, Ok(llvm_dir), Ok(llvm_version)) = (is_mac, llvm_dir, llvm_version) {
125-
let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
126-
bindings = bindings.clang_arg(llvm_include_path);
127-
} else if let (false, Ok(llvm_install_dir)) = (is_mac, llvm_install_dir) {
128-
let llvm_include_path = format!("-I{}/12.0.0/lib/clang/12.0.0/include", llvm_install_dir);
129-
env::set_var("LIBCLANG_PATH", format!("{}/12.0.0/lib", llvm_install_dir));
130-
bindings = bindings.clang_arg(llvm_include_path);
48+
49+
// Difference between global LLVM/Clang install and custom LLVM/Clang install...
50+
// First option is for the build server, second option is being nice to our dev who have `LLVM_INSTALL_DIR` set, default is for people with "normal" setups (and Macs)
51+
#[cfg(not(target_os = "macos"))]
52+
{
53+
// Detect for custom Clang or LLVM installations (BN devs/build server)
54+
let llvm_dir = env::var("LIBCLANG_PATH");
55+
let llvm_version = env::var("LLVM_VERSION");
56+
let llvm_install_dir = env::var("LLVM_INSTALL_DIR");
57+
58+
if let (Ok(llvm_dir), Ok(llvm_version)) = (llvm_dir, llvm_version) {
59+
let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
60+
bindings = bindings.clang_arg(llvm_include_path);
61+
} else if let Ok(llvm_install_dir) = llvm_install_dir {
62+
let llvm_include_path =
63+
format!("-I{}/12.0.0/lib/clang/12.0.0/include", llvm_install_dir);
64+
env::set_var("LIBCLANG_PATH", format!("{}/12.0.0/lib", llvm_install_dir));
65+
bindings = bindings.clang_arg(llvm_include_path);
66+
}
13167
}
13268

13369
bindings
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
2+
3+
project(test_headless)
4+
5+
file(GLOB PLUGIN_SOURCES
6+
${PROJECT_SOURCE_DIR}/Cargo.toml
7+
${PROJECT_SOURCE_DIR}/src/*.rs)
8+
9+
file(GLOB API_SOURCES
10+
${PROJECT_SOURCE_DIR}/../../../binaryninjacore.h
11+
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/build.rs
12+
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/Cargo.toml
13+
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/src/*
14+
${PROJECT_SOURCE_DIR}/../../Cargo.toml
15+
${PROJECT_SOURCE_DIR}/../../src/*.rs)
16+
17+
if(CMAKE_BUILD_TYPE MATCHES Debug)
18+
set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/debug)
19+
set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target)
20+
else()
21+
set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/release)
22+
set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target --release)
23+
endif()
24+
25+
set(OUTPUT_FILE basic_script${CMAKE_EXECUTABLE_SUFFIX})
26+
set(OUTPUT_PATH ${CMAKE_BINARY_DIR}/out/bin/${OUTPUT_FILE})
27+
28+
add_custom_target(test_headless ALL DEPENDS ${OUTPUT_PATH})
29+
add_dependencies(test_headless binaryninjaapi)
30+
31+
find_program(RUSTUP_PATH rustup REQUIRED HINTS ~/.cargo/bin)
32+
set(INSTALL_UPDATE_NIGHTLY ${RUSTUP_PATH} install nightly)
33+
34+
if(APPLE)
35+
if(UNIVERSAL)
36+
if(CMAKE_BUILD_TYPE MATCHES Debug)
37+
set(AARCH64_LIB_PATH ${PROJECT_BINARY_DIR}/target/aarch64-apple-darwin/debug/${OUTPUT_FILE})
38+
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/debug/${OUTPUT_FILE})
39+
else()
40+
set(AARCH64_LIB_PATH ${PROJECT_BINARY_DIR}/target/aarch64-apple-darwin/release/${OUTPUT_FILE})
41+
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/release/${OUTPUT_FILE})
42+
endif()
43+
44+
add_custom_command(
45+
OUTPUT ${OUTPUT_PATH}
46+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
47+
COMMAND ${CMAKE_COMMAND} -E env
48+
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
49+
${RUSTUP_PATH} run nightly cargo build --target=aarch64-apple-darwin ${CARGO_OPTS}
50+
COMMAND ${CMAKE_COMMAND} -E env
51+
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
52+
${RUSTUP_PATH} run nightly cargo build --target=x86_64-apple-darwin ${CARGO_OPTS}
53+
COMMAND cp ${AARCH64_LIB_PATH} ${OUTPUT_PATH}-aarch
54+
COMMAND cp ${X86_64_LIB_PATH} ${OUTPUT_PATH}
55+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
56+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
57+
else()
58+
if(CMAKE_BUILD_TYPE MATCHES Debug)
59+
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/debug/${OUTPUT_FILE})
60+
else()
61+
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/release/${OUTPUT_FILE})
62+
endif()
63+
64+
add_custom_command(
65+
OUTPUT ${OUTPUT_PATH}
66+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
67+
COMMAND ${CMAKE_COMMAND} -E env
68+
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
69+
${RUSTUP_PATH} run nightly cargo build --target=x86_64-apple-darwin ${CARGO_OPTS}
70+
COMMAND cp ${X86_64_LIB_PATH} ${OUTPUT_PATH}
71+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
72+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
73+
endif()
74+
elseif(WIN32)
75+
add_custom_command(
76+
OUTPUT ${OUTPUT_PATH}
77+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
78+
COMMAND ${CMAKE_COMMAND} -E env
79+
LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
80+
${RUSTUP_PATH} run nightly cargo build ${CARGO_OPTS}
81+
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
82+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
83+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
84+
else()
85+
add_custom_command(
86+
OUTPUT ${OUTPUT_PATH}
87+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
88+
COMMAND ${CMAKE_COMMAND} -E env
89+
LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
90+
${RUSTUP_PATH} run nightly cargo build ${CARGO_OPTS}
91+
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
92+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
93+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
94+
endif()

rust/examples/basic_script/build.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::env;
2+
use std::fs::File;
3+
use std::io::BufReader;
4+
use std::path::PathBuf;
5+
6+
#[cfg(target_os = "macos")]
7+
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
8+
9+
#[cfg(target_os = "linux")]
10+
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
11+
12+
#[cfg(windows)]
13+
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
14+
15+
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
16+
fn link_path() -> PathBuf {
17+
use std::io::prelude::*;
18+
19+
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
20+
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
21+
22+
File::open(lastrun)
23+
.and_then(|f| {
24+
let mut binja_path = String::new();
25+
let mut reader = BufReader::new(f);
26+
27+
reader.read_line(&mut binja_path)?;
28+
Ok(PathBuf::from(binja_path.trim()))
29+
})
30+
.unwrap_or_else(|_| {
31+
#[cfg(target_os = "macos")]
32+
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
33+
34+
#[cfg(target_os = "linux")]
35+
return home.join("binaryninja");
36+
37+
#[cfg(windows)]
38+
return PathBuf::from(env::var("PROGRAMFILES").unwrap()).join("Vector35\\BinaryNinja\\");
39+
})
40+
}
41+
42+
fn main() {
43+
// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
44+
let install_path = env::var("BINARYNINJADIR")
45+
.map(PathBuf::from)
46+
.unwrap_or_else(|_| link_path());
47+
48+
#[cfg(target_os = "linux")]
49+
println!(
50+
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
51+
install_path.to_str().unwrap(),
52+
install_path.to_str().unwrap(),
53+
);
54+
55+
#[cfg(target_os = "macos")]
56+
println!(
57+
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
58+
install_path.to_str().unwrap(),
59+
install_path.to_str().unwrap(),
60+
);
61+
62+
#[cfg(target_os = "windows")]
63+
{
64+
println!("cargo:rustc-link-lib=binaryninjacore");
65+
println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
66+
}
67+
}

0 commit comments

Comments
 (0)