-
Notifications
You must be signed in to change notification settings - Fork 289
Expand file tree
/
Copy pathbuild.rs
More file actions
154 lines (134 loc) · 5.45 KB
/
Copy pathbuild.rs
File metadata and controls
154 lines (134 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::PathBuf;
#[cfg(target_os = "macos")]
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
#[cfg(target_os = "linux")]
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
#[cfg(windows)]
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
fn link_path() -> PathBuf {
use std::io::prelude::*;
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
File::open(lastrun)
.and_then(|f| {
let mut binja_path = String::new();
let mut reader = BufReader::new(f);
reader.read_line(&mut binja_path)?;
Ok(PathBuf::from(binja_path.trim()))
})
.unwrap_or_else(|_| {
#[cfg(target_os = "macos")]
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
#[cfg(target_os = "linux")]
return home.join("binaryninja");
#[cfg(windows)]
return PathBuf::from(env::var("PROGRAMFILES").unwrap())
.join("Vector35\\BinaryNinja\\");
})
}
fn api_base_path() -> PathBuf {
env::var_os("BINARYNINJA_API_DIR")
.map(PathBuf::from)
.unwrap_or_else(|| {
let manifest_dir =
std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
std::path::PathBuf::from(manifest_dir)
.join("../../")
.canonicalize()
.unwrap()
})
}
// Generate and compile stub shared library and return the path to the folder containing the built stub library
fn generate_stubs() -> PathBuf {
let stubs_path = api_base_path().join("stubs");
// TODO: does visual studio add the config name as a subdirectory?
cmake::Config::new(stubs_path)
.generator("Ninja")
.build()
.join("build")
}
fn main() {
println!("cargo:rerun-if-env-changed=BINARYNINJADIR");
println!("cargo:rerun-if-env-changed=BINARYNINJA_API_DIR");
let api_base_path = api_base_path();
println!(
"cargo:rerun-if-changed={}",
api_base_path.join("binaryninjacore.h").display()
);
//Cargo's output directory
let out_dir = env::var("OUT_DIR").unwrap();
let link_path = match env::var("CARGO_FEATURE_CORE") {
Ok(_) => env::var("BINARYNINJADIR")
.map(PathBuf::from)
.unwrap_or_else(|_| link_path()),
Err(_) => generate_stubs(),
};
// Linux builds of binaryninja ship with libbinaryninjacore.so.1 in the
// application folder and no symlink. The linker will attempt to link with
// libbinaryninjacore.so. Since this is likely going to fail, we detect this
// ahead of time and create an appropriately named symlink inside of OUT_DIR
// and add it to the library search path.
#[cfg(target_os = "linux")]
{
let symlink_source = PathBuf::from(&out_dir).join("libbinaryninjacore.so");
let symlink_target = link_path.join("libbinaryninjacore.so.1");
// Make a symlink "libbinaryninjacore.so" pointing to "libbinaryninjacore.so.1"
if symlink_target.exists() && symlink_source.symlink_metadata().is_err() {
use std::os::unix::fs;
fs::symlink(symlink_target, symlink_source).expect("failed to create required symlink");
}
println!("cargo:rustc-link-search={}", out_dir);
}
// Emit the path to binaryninjacore consumers of this crate should pass to the linker.
println!("cargo:path={}", link_path.to_str().unwrap());
let current_line = "#define BN_CURRENT_UI_ABI_VERSION ";
let minimum_line = "#define BN_MINIMUM_UI_ABI_VERSION ";
let mut current_version = "0".to_string();
let mut minimum_version = "0".to_string();
let file = File::open(api_base_path.join("ui/uitypes.h")).expect("Couldn't open uitypes.h");
for line in BufReader::new(file).lines() {
let line = line.unwrap();
if let Some(version) = line.strip_prefix(current_line) {
version.clone_into(&mut current_version);
} else if let Some(version) = line.strip_prefix(minimum_line) {
version.clone_into(&mut minimum_version);
}
}
bindgen::builder()
.header(
api_base_path
.join("binaryninjacore.h")
.to_string_lossy()
.into_owned(),
)
.clang_arg("-std=c++20")
.clang_arg("-x")
.clang_arg("c++")
.size_t_is_usize(true)
.generate_comments(false)
.derive_default(true)
.generate_comments(true)
.clang_arg("-fparse-all-comments")
.allowlist_function("BN.*")
.allowlist_var("BN_CURRENT_CORE_ABI_VERSION")
.allowlist_var("BN_MINIMUM_CORE_ABI_VERSION")
.allowlist_var("MAX_RELOCATION_SIZE")
.raw_line(format!(
"pub const BN_CURRENT_UI_ABI_VERSION: u32 = {};",
current_version
))
.raw_line(format!(
"pub const BN_MINIMUM_UI_ABI_VERSION: u32 = {};",
minimum_version
))
.rustified_enum("BN.*")
.generate()
.expect("Unable to generate bindings")
.write_to_file(PathBuf::from(out_dir).join("bindings.rs"))
.expect("Couldn't write bindings!");
}