@@ -15,7 +15,8 @@ fn main() {
1515
1616 let build_config = "RelWithDebInfo" ;
1717
18- Command :: new ( "cmake" )
18+ let mut cmake_configure = Command :: new ( "cmake" ) ;
19+ cmake_configure
1920 . arg ( "-B" )
2021 . arg ( & build_dir)
2122 . arg ( "-S" )
@@ -38,7 +39,58 @@ fn main() {
3839 . arg ( "-DBUILD_SHARED_LIBS=OFF" )
3940 . arg ( "-DCMAKE_INSTALL_LIBDIR=lib" )
4041 . arg ( "-DENABLE_IPC=OFF" )
41- . arg ( format ! ( "-DCMAKE_INSTALL_PREFIX={}" , install_dir. display( ) ) )
42+ . arg ( format ! ( "-DCMAKE_INSTALL_PREFIX={}" , install_dir. display( ) ) ) ;
43+
44+ let target_os = env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ;
45+ let is_android = target_os == "android" ;
46+
47+ let ndk = if is_android {
48+ Some (
49+ env:: var ( "ANDROID_NDK_HOME" )
50+ . expect ( "Android target detected but ANDROID_NDK_HOME is not set" ) ,
51+ )
52+ } else {
53+ None
54+ } ;
55+
56+ if is_android {
57+ let ndk = ndk. as_deref ( ) . unwrap ( ) ;
58+ let toolchain_file = format ! ( "{ndk}/build/cmake/android.toolchain.cmake" ) ;
59+
60+ // Rust target triple -> NDK ABI name.
61+ let abi = match env:: var ( "TARGET" ) . unwrap ( ) {
62+ t if t. contains ( "aarch64" ) => "arm64-v8a" ,
63+ t if t. contains ( "armv7" ) => "armeabi-v7a" ,
64+ t if t. contains ( "x86_64" ) => "x86_64" ,
65+ target => panic ! ( "Unsupported Android ABI: {target}" ) ,
66+ } ;
67+
68+ // API level 24+ is required because Bitcoin Core uses getifaddrs
69+ // which was introduced in Android API 24 (Nougat).
70+ //
71+ // This can be overridden to a higher level by setting ANDROID_API_LEVEL.
72+ let api_level = match env:: var ( "ANDROID_API_LEVEL" ) {
73+ Ok ( level) => {
74+ let n: u32 = level. parse ( ) . expect ( "ANDROID_API_LEVEL must be a number" ) ;
75+ assert ! ( n >= 24 , "ANDROID_API_LEVEL must be 24+" ) ;
76+ level
77+ }
78+ _ => "24" . to_string ( ) ,
79+ } ;
80+
81+ cmake_configure
82+ . arg ( format ! ( "-DCMAKE_TOOLCHAIN_FILE={toolchain_file}" ) )
83+ . arg ( format ! ( "-DANDROID_ABI={abi}" ) )
84+ . arg ( format ! ( "-DANDROID_PLATFORM=android-{api_level}" ) )
85+ . arg ( "-DCMAKE_SYSTEM_NAME=Android" )
86+ . arg ( format ! ( "-DCMAKE_ANDROID_NDK={ndk}" ) )
87+ // The Android NDK toolchain sets CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
88+ // to ONLY, which prevents cmake from finding host packages via
89+ // CMAKE_PREFIX_PATH. Override it so Boost headers can be located.
90+ . arg ( "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH" ) ;
91+ }
92+
93+ cmake_configure
4294 . status ( )
4395 . expect ( "cmake should be installed and available in PATH" ) ;
4496
@@ -70,19 +122,49 @@ fn main() {
70122 } else {
71123 install_dir. join ( "lib" )
72124 } ;
125+
73126 println ! ( "cargo:rustc-link-search=native={}" , lib_dir. display( ) ) ;
74127
75128 println ! ( "cargo:rustc-link-lib=static=bitcoinkernel" ) ;
76129
77130 let compiler = cc:: Build :: new ( ) . get_compiler ( ) ;
78- let target_os = std:: env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ;
79131
80132 if target_os == "windows" {
81133 println ! ( "cargo:rustc-link-lib=bcrypt" ) ;
82134 println ! ( "cargo:rustc-link-lib=shell32" ) ;
83- }
135+ } else if is_android {
136+ // Without these, changing either variable between builds won't trigger a rebuild,
137+ // so we could silently end up with a stale binary built against the wrong NDK or API level.
138+ println ! ( "cargo:rerun-if-env-changed=ANDROID_NDK_HOME" ) ;
139+ println ! ( "cargo:rerun-if-env-changed=ANDROID_API_LEVEL" ) ;
140+ // Android NDK ships libc++_static.a and libc++abi.a in the
141+ // per-architecture sysroot directory (not the API-level subdirectory).
142+ let ndk = ndk. as_deref ( ) . unwrap ( ) ;
143+
144+ // Rust target triple -> NDK sysroot lib directory triple.
145+ // armv7 differs: Rust says `armv7-linux-androideabi`, NDK says `arm-linux-androideabi`.
146+ let ndk_triple = env:: var ( "TARGET" )
147+ . map ( |target| {
148+ if target. starts_with ( "armv7" ) {
149+ "arm-linux-androideabi" . into ( )
150+ } else {
151+ target
152+ }
153+ } )
154+ . unwrap ( ) ;
155+
156+ let host_tag = match std:: env:: consts:: OS {
157+ "macos" => "darwin-x86_64" ,
158+ "linux" => "linux-x86_64" ,
159+ os => panic ! ( "unsupported build host for Android cross-compilation: {os}" ) ,
160+ } ;
84161
85- if compiler. is_like_clang ( ) {
162+ let ndk_lib_dir =
163+ format ! ( "{ndk}/toolchains/llvm/prebuilt/{host_tag}/sysroot/usr/lib/{ndk_triple}" ) ;
164+ println ! ( "cargo:rustc-link-search=native={ndk_lib_dir}" ) ;
165+ println ! ( "cargo:rustc-link-lib=static=c++_static" ) ;
166+ println ! ( "cargo:rustc-link-lib=static=c++abi" ) ;
167+ } else if compiler. is_like_clang ( ) {
86168 if target_os == "macos" {
87169 println ! ( "cargo:rustc-link-lib=dylib=c++" ) ;
88170 } else {
0 commit comments