@@ -1370,6 +1370,15 @@ impl Build {
13701370 cmd. push_opt_unless_duplicate ( format ! ( "-O{}" , opt_level) . into ( ) ) ;
13711371 }
13721372
1373+ if cmd. family == ToolFamily :: Clang && target. contains ( "android" ) {
1374+ // For compatibility with code that doesn't use pre-defined `__ANDROID__` macro.
1375+ // If compiler used via ndk-build or cmake (officially supported build methods)
1376+ // this macros is defined.
1377+ // See https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/cmake/android.toolchain.cmake#456
1378+ // https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/core/build-binary.mk#141
1379+ cmd. push_opt_unless_duplicate ( "-DANDROID" . into ( ) ) ;
1380+ }
1381+
13731382 if !target. contains ( "-ios" ) {
13741383 cmd. push_cc_arg ( "-ffunction-sections" . into ( ) ) ;
13751384 cmd. push_cc_arg ( "-fdata-sections" . into ( ) ) ;
@@ -1406,7 +1415,17 @@ impl Build {
14061415 // Target flags
14071416 match cmd. family {
14081417 ToolFamily :: Clang => {
1409- cmd. args . push ( format ! ( "--target={}" , target) . into ( ) ) ;
1418+ // clang from Android NDK target names are different from rustc.
1419+ // For example, armv7a-linux-androideabi16-clang passes
1420+ // --target=armv7a-linux-androideabi16 to clang.
1421+ // So if pass also `rustc` target, this break build, because of
1422+ // as result OS executes something like:
1423+ // clang --target=armv7a-linux-androideabi16 --target=armv7-linux-androideabi
1424+ // And some predefined macros will be not defined, because of
1425+ // clang uses only last --target=armv7-linux-androideabi
1426+ if !target. contains ( "android" ) || !new_clang_android_compiler ( & cmd. path ) {
1427+ cmd. args . push ( format ! ( "--target={}" , target) . into ( ) ) ;
1428+ }
14101429 }
14111430 ToolFamily :: Msvc { clang_cl } => {
14121431 // This is an undocumented flag from MSVC but helps with making
@@ -1974,29 +1993,7 @@ impl Build {
19741993 format ! ( "{}.exe" , gnu)
19751994 }
19761995 } else if target. contains ( "android" ) {
1977- let target = target
1978- . replace ( "armv7neon" , "arm" )
1979- . replace ( "armv7" , "arm" )
1980- . replace ( "thumbv7neon" , "arm" )
1981- . replace ( "thumbv7" , "arm" ) ;
1982- let gnu_compiler = format ! ( "{}-{}" , target, gnu) ;
1983- let clang_compiler = format ! ( "{}-{}" , target, clang) ;
1984- // On Windows, the Android clang compiler is provided as a `.cmd` file instead
1985- // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the
1986- // `.cmd` is explicitly appended to the command name, so we do that here.
1987- let clang_compiler_cmd = format ! ( "{}-{}.cmd" , target, clang) ;
1988-
1989- // Check if gnu compiler is present
1990- // if not, use clang
1991- if Command :: new ( & gnu_compiler) . output ( ) . is_ok ( ) {
1992- gnu_compiler
1993- } else if host. contains ( "windows" )
1994- && Command :: new ( & clang_compiler_cmd) . output ( ) . is_ok ( )
1995- {
1996- clang_compiler_cmd
1997- } else {
1998- clang_compiler
1999- }
1996+ autodetect_android_compiler ( & target, & host, gnu, clang)
20001997 } else if target. contains ( "cloudabi" ) {
20011998 format ! ( "{}-{}" , target, traditional)
20021999 } else if target == "wasm32-wasi"
@@ -2722,3 +2719,67 @@ fn command_add_output_file(
27222719 cmd. arg ( "-o" ) . arg ( & dst) ;
27232720 }
27242721}
2722+
2723+ // Use by default minimum available API level
2724+ // See note about naming here
2725+ // https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md#Clang
2726+ static NEW_STANDALONE_ANDROID_COMPILERS : [ & str ; 4 ] = [
2727+ "aarch64-linux-android21-clang" ,
2728+ "armv7a-linux-androideabi16-clang" ,
2729+ "i686-linux-android16-clang" ,
2730+ "x86_64-linux-android21-clang" ,
2731+ ] ;
2732+
2733+ fn new_clang_android_compiler ( clang_path : & Path ) -> bool {
2734+ NEW_STANDALONE_ANDROID_COMPILERS . iter ( ) . any ( |x| {
2735+ let x: & OsStr = x. as_ref ( ) ;
2736+ x == clang_path. as_os_str ( )
2737+ } )
2738+ }
2739+
2740+ fn autodetect_android_compiler ( target : & str , host : & str , gnu : & str , clang : & str ) -> String {
2741+ let new_clang_key = match target {
2742+ "aarch64-linux-android" => Some ( "aarch64" ) ,
2743+ "armv7-linux-androideabi" => Some ( "armv7a" ) ,
2744+ "i686-linux-android" => Some ( "i686" ) ,
2745+ "x86_64-linux-android" => Some ( "x86_64" ) ,
2746+ _ => None ,
2747+ } ;
2748+
2749+ let new_clang = new_clang_key
2750+ . map ( |key| {
2751+ NEW_STANDALONE_ANDROID_COMPILERS
2752+ . iter ( )
2753+ . find ( |x| x. starts_with ( key) )
2754+ } )
2755+ . unwrap_or ( None ) ;
2756+
2757+ if let Some ( new_clang) = new_clang {
2758+ if Command :: new ( new_clang) . output ( ) . is_ok ( ) {
2759+ return ( * new_clang) . into ( ) ;
2760+ }
2761+ }
2762+
2763+ let target = target
2764+ . replace ( "armv7neon" , "arm" )
2765+ . replace ( "armv7" , "arm" )
2766+ . replace ( "thumbv7neon" , "arm" )
2767+ . replace ( "thumbv7" , "arm" ) ;
2768+ let gnu_compiler = format ! ( "{}-{}" , target, gnu) ;
2769+ let clang_compiler = format ! ( "{}-{}" , target, clang) ;
2770+
2771+ // On Windows, the Android clang compiler is provided as a `.cmd` file instead
2772+ // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the
2773+ // `.cmd` is explicitly appended to the command name, so we do that here.
2774+ let clang_compiler_cmd = format ! ( "{}-{}.cmd" , target, clang) ;
2775+
2776+ // Check if gnu compiler is present
2777+ // if not, use clang
2778+ if Command :: new ( & gnu_compiler) . output ( ) . is_ok ( ) {
2779+ gnu_compiler
2780+ } else if host. contains ( "windows" ) && Command :: new ( & clang_compiler_cmd) . output ( ) . is_ok ( ) {
2781+ clang_compiler_cmd
2782+ } else {
2783+ clang_compiler
2784+ }
2785+ }
0 commit comments