1- use std:: env;
21use std:: fs:: File ;
32use std:: io:: BufRead ;
43use std:: io:: BufReader ;
5- use std:: path:: PathBuf ;
4+ use std:: path:: { Path , PathBuf } ;
65
76#[ cfg( target_os = "macos" ) ]
87static LASTRUN_PATH : ( & str , & str ) = ( "HOME" , "Library/Application Support/Binary Ninja/lastrun" ) ;
@@ -13,11 +12,11 @@ static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
1312#[ cfg( windows) ]
1413static LASTRUN_PATH : ( & str , & str ) = ( "APPDATA" , "Binary Ninja\\ lastrun" ) ;
1514
16- // Check last run location for path to BinaryNinja; Otherwise check the default install locations
15+ /// Check the last run location for the path to binary ninja core, falling back to default install locations.
1716fn link_path ( ) -> PathBuf {
1817 use std:: io:: prelude:: * ;
1918
20- let home = PathBuf :: from ( env:: var ( LASTRUN_PATH . 0 ) . unwrap ( ) ) ;
19+ let home = PathBuf :: from ( std :: env:: var ( LASTRUN_PATH . 0 ) . unwrap ( ) ) ;
2120 let lastrun = PathBuf :: from ( & home) . join ( LASTRUN_PATH . 1 ) ;
2221
2322 File :: open ( lastrun)
@@ -41,33 +40,45 @@ fn link_path() -> PathBuf {
4140 } )
4241}
4342
44- // Generate and compile stub shared library and return the path to the folder containing the built stub library
43+ /// Generate and compile a stubbed out shared library and return the path to the folder containing
44+ /// the built stub library, this allows us to link without actually having the real core library.
4545fn generate_stubs ( ) -> PathBuf {
4646 let manifest_dir = std:: env:: var ( "CARGO_MANIFEST_DIR" ) . expect ( "CARGO_MANIFEST_DIR not set" ) ;
47-
48- let api_base_path = std:: path:: PathBuf :: from ( manifest_dir)
47+ let api_base_path = PathBuf :: from ( manifest_dir)
4948 . join ( "../../" )
5049 . canonicalize ( )
5150 . unwrap ( ) ;
52-
5351 let stubs_path = api_base_path. join ( "stubs" ) ;
54-
5552 // TODO: does visual studio add the config name as a subdirectory?
5653 cmake:: Config :: new ( stubs_path)
5754 . generator ( "Ninja" )
5855 . build ( )
5956 . join ( "build" )
6057}
6158
59+ /// Find a header file for parsing, checking the vendored directory, falling back to the default location.
60+ ///
61+ /// The `vendor` directory is used when publishing the crate, as the headers must be contained within
62+ /// the packaged crate, for more information see https://doc.rust-lang.org/cargo/reference/publishing.html#packaging-a-crate
63+ fn find_header ( name : & str , fallback_path : & str ) -> PathBuf {
64+ let manifest_dir = std:: env:: var ( "CARGO_MANIFEST_DIR" ) . expect ( "CARGO_MANIFEST_DIR not set" ) ;
65+ let vendored = Path :: new ( & manifest_dir) . join ( "vendor" ) . join ( name) ;
66+ if vendored. exists ( ) {
67+ vendored
68+ } else {
69+ PathBuf :: from ( fallback_path)
70+ }
71+ }
72+
6273fn main ( ) {
6374 println ! ( "cargo:rerun-if-env-changed=BINARYNINJADIR" ) ;
6475 println ! ( "cargo:rerun-if-changed=../../binaryninjacore.h" ) ;
6576
6677 //Cargo's output directory
67- let out_dir = env:: var ( "OUT_DIR" ) . unwrap ( ) ;
78+ let out_dir = std :: env:: var ( "OUT_DIR" ) . unwrap ( ) ;
6879
69- let link_path = match env:: var ( "CARGO_FEATURE_CORE" ) {
70- Ok ( _) => env:: var ( "BINARYNINJADIR" )
80+ let link_path = match std :: env:: var ( "CARGO_FEATURE_CORE" ) {
81+ Ok ( _) => std :: env:: var ( "BINARYNINJADIR" )
7182 . map ( PathBuf :: from)
7283 . unwrap_or_else ( |_| link_path ( ) ) ,
7384 Err ( _) => generate_stubs ( ) ,
@@ -93,11 +104,19 @@ fn main() {
93104 // Emit the path to binaryninjacore consumers of this crate should pass to the linker.
94105 println ! ( "cargo:path={}" , link_path. to_str( ) . unwrap( ) ) ;
95106
107+ // We need to vendor the headers when publishing the crate, otherwise the headers will be missing
108+ // from the packaged crate, and building will fail.
109+ let header_path = find_header ( "binaryninjacore.h" , "../../binaryninjacore.h" ) ;
110+ let ui_header_path = find_header ( "uitypes.h" , "../../ui/uitypes.h" ) ;
111+
96112 let current_line = "#define BN_CURRENT_UI_ABI_VERSION " ;
97113 let minimum_line = "#define BN_MINIMUM_UI_ABI_VERSION " ;
98114 let mut current_version = "0" . to_string ( ) ;
99115 let mut minimum_version = "0" . to_string ( ) ;
100- let file = File :: open ( "../../ui/uitypes.h" ) . expect ( "Couldn't open uitypes.h" ) ;
116+ let file = File :: open ( & ui_header_path) . expect ( & format ! (
117+ "Couldn't open '{}'" ,
118+ ui_header_path. to_string_lossy( )
119+ ) ) ;
101120 for line in BufReader :: new ( file) . lines ( ) {
102121 let line = line. unwrap ( ) ;
103122 if let Some ( version) = line. strip_prefix ( current_line) {
@@ -108,7 +127,7 @@ fn main() {
108127 }
109128
110129 bindgen:: builder ( )
111- . header ( "../../binaryninjacore.h" )
130+ . header ( header_path . to_string_lossy ( ) )
112131 . clang_arg ( "-std=c++20" )
113132 . clang_arg ( "-x" )
114133 . clang_arg ( "c++" )
0 commit comments