Skip to content

Commit af713db

Browse files
committed
Implement autodetection for default compiler from NDK
ref #459
1 parent d1a7b8e commit af713db

File tree

1 file changed

+85
-24
lines changed

1 file changed

+85
-24
lines changed

src/lib.rs

+85-24
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)