Skip to content

Commit 17226b3

Browse files
committed
Improve android-ndk property interface
PR #105716 added support for NDK r25b, and removed support for r15. Since the switch to r25b would have broken existing r15 users anyway, let's take the opportunity to make the interface more user friendly. Firstly move the android-ndk property to [build] instead of the targets. This is possible now that the NDK has obsoleted the concept of target-specific toolchains. Also make the property take the NDK root directory instead of the "toolchains/llvm/prebuilt/<host tag>" subdirectory.
1 parent 1a521db commit 17226b3

File tree

6 files changed

+59
-72
lines changed

6 files changed

+59
-72
lines changed

config.toml.example

+3-6
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ changelog-seen = 2
346346
# this is not intended to be used during local development.
347347
#metrics = false
348348

349+
# Specify the location of the Android NDK. Used when targeting Android.
350+
#android-ndk = "/path/to/android-ndk-r25b"
351+
349352
# =============================================================================
350353
# General install configuration options
351354
# =============================================================================
@@ -717,12 +720,6 @@ changelog-seen = 2
717720
# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
718721
#llvm-libunwind = 'no' if Linux, 'in-tree' if Fuchsia
719722

720-
# If this target is for Android, this option will be required to specify where
721-
# the NDK for the target lives. This is used to find the C compiler to link and
722-
# build native code.
723-
# See `src/bootstrap/cc_detect.rs` for details.
724-
#android-ndk = <none> (path)
725-
726723
# Build the sanitizer runtimes for this target.
727724
# This option will override the same option under [build] section.
728725
#sanitizers = build.sanitizers (bool)

src/bootstrap/cc_detect.rs

+48-33
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::path::{Path, PathBuf};
2626
use std::process::Command;
2727
use std::{env, iter};
2828

29-
use crate::config::{Target, TargetSelection};
29+
use crate::config::TargetSelection;
3030
use crate::util::output;
3131
use crate::{Build, CLang, GitRepo};
3232

@@ -100,10 +100,11 @@ pub fn find(build: &mut Build) {
100100
for target in targets.into_iter() {
101101
let mut cfg = new_cc_build(build, target);
102102
let config = build.config.target_config.get(&target);
103-
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
103+
if let Some(cc) = config
104+
.and_then(|c| c.cc.clone())
105+
.or_else(|| default_compiler(&mut cfg, Language::C, target, build))
106+
{
104107
cfg.compiler(cc);
105-
} else {
106-
set_compiler(&mut cfg, Language::C, target, config, build);
107108
}
108109

109110
let compiler = cfg.get_compiler();
@@ -120,12 +121,12 @@ pub fn find(build: &mut Build) {
120121
// We'll need one anyways if the target triple is also a host triple
121122
let mut cfg = new_cc_build(build, target);
122123
cfg.cpp(true);
123-
let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
124+
let cxx_configured = if let Some(cxx) = config
125+
.and_then(|c| c.cxx.clone())
126+
.or_else(|| default_compiler(&mut cfg, Language::CPlusPlus, target, build))
127+
{
124128
cfg.compiler(cxx);
125129
true
126-
} else if build.hosts.contains(&target) || build.build == target {
127-
set_compiler(&mut cfg, Language::CPlusPlus, target, config, build);
128-
true
129130
} else {
130131
// Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars).
131132
cfg.try_get_compiler().is_ok()
@@ -155,68 +156,70 @@ pub fn find(build: &mut Build) {
155156
}
156157
}
157158

158-
fn set_compiler(
159+
fn default_compiler(
159160
cfg: &mut cc::Build,
160161
compiler: Language,
161162
target: TargetSelection,
162-
config: Option<&Target>,
163163
build: &Build,
164-
) {
164+
) -> Option<PathBuf> {
165165
match &*target.triple {
166166
// When compiling for android we may have the NDK configured in the
167167
// config.toml in which case we look there. Otherwise the default
168168
// compiler already takes into account the triple in question.
169-
t if t.contains("android") => {
170-
if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
171-
cfg.compiler(ndk_compiler(compiler, &*target.triple, ndk));
172-
}
173-
}
169+
t if t.contains("android") => build
170+
.config
171+
.android_ndk
172+
.as_ref()
173+
.map(|ndk| ndk_compiler(compiler, &*target.triple, ndk)),
174174

175175
// The default gcc version from OpenBSD may be too old, try using egcc,
176176
// which is a gcc version from ports, if this is the case.
177177
t if t.contains("openbsd") => {
178178
let c = cfg.get_compiler();
179179
let gnu_compiler = compiler.gcc();
180180
if !c.path().ends_with(gnu_compiler) {
181-
return;
181+
return None;
182182
}
183183

184184
let output = output(c.to_command().arg("--version"));
185-
let i = match output.find(" 4.") {
186-
Some(i) => i,
187-
None => return,
188-
};
185+
let i = output.find(" 4.")?;
189186
match output[i + 3..].chars().next().unwrap() {
190187
'0'..='6' => {}
191-
_ => return,
188+
_ => return None,
192189
}
193190
let alternative = format!("e{}", gnu_compiler);
194191
if Command::new(&alternative).output().is_ok() {
195-
cfg.compiler(alternative);
192+
Some(PathBuf::from(alternative))
193+
} else {
194+
None
196195
}
197196
}
198197

199-
"mips-unknown-linux-musl" => {
198+
"mips-unknown-linux-musl" if compiler == Language::C => {
200199
if cfg.get_compiler().path().to_str() == Some("gcc") {
201-
cfg.compiler("mips-linux-musl-gcc");
200+
Some(PathBuf::from("mips-linux-musl-gcc"))
201+
} else {
202+
None
202203
}
203204
}
204-
"mipsel-unknown-linux-musl" => {
205+
"mipsel-unknown-linux-musl" if compiler == Language::C => {
205206
if cfg.get_compiler().path().to_str() == Some("gcc") {
206-
cfg.compiler("mipsel-linux-musl-gcc");
207+
Some(PathBuf::from("mipsel-linux-musl-gcc"))
208+
} else {
209+
None
207210
}
208211
}
209212

210-
t if t.contains("musl") => {
213+
t if t.contains("musl") && compiler == Language::C => {
211214
if let Some(root) = build.musl_root(target) {
212215
let guess = root.join("bin/musl-gcc");
213-
if guess.exists() {
214-
cfg.compiler(guess);
215-
}
216+
if guess.exists() { Some(guess) } else { None }
217+
} else {
218+
None
216219
}
217220
}
218221

219-
_ => {}
222+
_ => None,
220223
}
221224
}
222225

@@ -237,10 +240,22 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path
237240
let api_level =
238241
if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" };
239242
let compiler = format!("{}{}-{}", triple_translated, api_level, compiler.clang());
240-
ndk.join("bin").join(compiler)
243+
let host_tag = if cfg!(target_os = "macos") {
244+
// The NDK uses universal binaries, so this is correct even on ARM.
245+
"darwin-x86_64"
246+
} else if cfg!(target_os = "windows") {
247+
"windows-x86_64"
248+
} else {
249+
// NDK r25b only has official releases for macOS, Windows and Linux.
250+
// Try the Linux directory everywhere else, on the assumption that the OS has an
251+
// emulation layer that can cope (e.g. BSDs).
252+
"linux-x86_64"
253+
};
254+
ndk.join("toolchains").join("llvm").join("prebuilt").join(host_tag).join("bin").join(compiler)
241255
}
242256

243257
/// The target programming language for a native compiler.
258+
#[derive(PartialEq)]
244259
pub(crate) enum Language {
245260
/// The compiler is targeting C.
246261
C,

src/bootstrap/config.rs

+5-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use std::str::FromStr;
1818

1919
use crate::builder::TaskPath;
2020
use crate::cache::{Interned, INTERNER};
21-
use crate::cc_detect::{ndk_compiler, Language};
2221
use crate::channel::{self, GitInfo};
2322
pub use crate::flags::Subcommand;
2423
use crate::flags::{Color, Flags};
@@ -86,6 +85,7 @@ pub struct Config {
8685
pub color: Color,
8786
pub patch_binaries_for_nix: bool,
8887
pub stage0_metadata: Stage0Metadata,
88+
pub android_ndk: Option<PathBuf>,
8989

9090
pub on_fail: Option<String>,
9191
pub stage: u32,
@@ -443,7 +443,6 @@ pub struct Target {
443443
pub ranlib: Option<PathBuf>,
444444
pub default_linker: Option<PathBuf>,
445445
pub linker: Option<PathBuf>,
446-
pub ndk: Option<PathBuf>,
447446
pub sanitizers: Option<bool>,
448447
pub profiler: Option<bool>,
449448
pub crt_static: Option<bool>,
@@ -645,6 +644,7 @@ define_config! {
645644
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
646645
// NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
647646
metrics: Option<bool> = "metrics",
647+
android_ndk: Option<PathBuf> = "android-ndk",
648648
}
649649
}
650650

@@ -785,7 +785,6 @@ define_config! {
785785
llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
786786
llvm_filecheck: Option<String> = "llvm-filecheck",
787787
llvm_libunwind: Option<String> = "llvm-libunwind",
788-
android_ndk: Option<String> = "android-ndk",
789788
sanitizers: Option<bool> = "sanitizers",
790789
profiler: Option<bool> = "profiler",
791790
crt_static: Option<bool> = "crt-static",
@@ -1023,6 +1022,7 @@ impl Config {
10231022
config.python = build.python.map(PathBuf::from);
10241023
config.reuse = build.reuse.map(PathBuf::from);
10251024
config.submodules = build.submodules;
1025+
config.android_ndk = build.android_ndk;
10261026
set(&mut config.low_priority, build.low_priority);
10271027
set(&mut config.compiler_docs, build.compiler_docs);
10281028
set(&mut config.library_docs_private_items, build.library_docs_private_items);
@@ -1252,18 +1252,11 @@ impl Config {
12521252
.llvm_libunwind
12531253
.as_ref()
12541254
.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
1255-
if let Some(ref s) = cfg.android_ndk {
1256-
target.ndk = Some(config.src.join(s));
1257-
}
12581255
if let Some(s) = cfg.no_std {
12591256
target.no_std = s;
12601257
}
1261-
target.cc = cfg.cc.map(PathBuf::from).or_else(|| {
1262-
target.ndk.as_ref().map(|ndk| ndk_compiler(Language::C, &triple, ndk))
1263-
});
1264-
target.cxx = cfg.cxx.map(PathBuf::from).or_else(|| {
1265-
target.ndk.as_ref().map(|ndk| ndk_compiler(Language::CPlusPlus, &triple, ndk))
1266-
});
1258+
target.cc = cfg.cc.map(PathBuf::from);
1259+
target.cxx = cfg.cxx.map(PathBuf::from);
12671260
target.ar = cfg.ar.map(PathBuf::from);
12681261
target.ranlib = cfg.ranlib.map(PathBuf::from);
12691262
target.linker = cfg.linker.map(PathBuf::from);

src/bootstrap/configure.py

+1-14
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,7 @@ def v(*args):
9797
v("llvm-config", None, "set path to llvm-config")
9898
v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
9999
v("python", "build.python", "set path to python")
100-
v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
101-
"Android NDK standalone path (deprecated)")
102-
v("i686-linux-android-ndk", "target.i686-linux-android.android-ndk",
103-
"i686-linux-android NDK standalone path")
104-
v("arm-linux-androideabi-ndk", "target.arm-linux-androideabi.android-ndk",
105-
"arm-linux-androideabi NDK standalone path")
106-
v("armv7-linux-androideabi-ndk", "target.armv7-linux-androideabi.android-ndk",
107-
"armv7-linux-androideabi NDK standalone path")
108-
v("thumbv7neon-linux-androideabi-ndk", "target.thumbv7neon-linux-androideabi.android-ndk",
109-
"thumbv7neon-linux-androideabi NDK standalone path")
110-
v("aarch64-linux-android-ndk", "target.aarch64-linux-android.android-ndk",
111-
"aarch64-linux-android NDK standalone path")
112-
v("x86_64-linux-android-ndk", "target.x86_64-linux-android.android-ndk",
113-
"x86_64-linux-android NDK standalone path")
100+
v("android-ndk", "build.android-ndk", "set path to Android NDK")
114101
v("musl-root", "target.x86_64-unknown-linux-musl.musl-root",
115102
"MUSL root installation directory (deprecated)")
116103
v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root",

src/ci/docker/host-x86_64/arm-android/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ ENV PATH=$PATH:/android/sdk/platform-tools
3030

3131
ENV TARGETS=arm-linux-androideabi
3232

33-
ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/
33+
ENV RUST_CONFIGURE_ARGS --android-ndk=/android/ndk/
3434

3535
ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
3636

src/ci/docker/host-x86_64/dist-android/Dockerfile

+1-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ ENV TARGETS=$TARGETS,x86_64-linux-android
1919
ENV RUST_CONFIGURE_ARGS \
2020
--enable-extended \
2121
--enable-profiler \
22-
--arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
23-
--armv7-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
24-
--thumbv7neon-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
25-
--i686-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
26-
--aarch64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
27-
--x86_64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
22+
--android-ndk=/android/ndk/ \
2823
--disable-docs
2924

3025
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS

0 commit comments

Comments
 (0)