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.
This commit is contained in:
Peter Collingbourne 2022-10-12 17:02:31 -07:00
parent 7db4a89d49
commit aad44b3b54
8 changed files with 62 additions and 75 deletions

View File

@ -30,7 +30,7 @@
# #
# If `change-id` does not match the version that is currently running, # If `change-id` does not match the version that is currently running,
# `x.py` will prompt you to update it and check the related PR for more details. # `x.py` will prompt you to update it and check the related PR for more details.
change-id = 115898 change-id = 116998
# ============================================================================= # =============================================================================
# Tweaking how LLVM is compiled # Tweaking how LLVM is compiled
@ -377,6 +377,9 @@ change-id = 115898
# this is not intended to be used during local development. # this is not intended to be used during local development.
#metrics = false #metrics = false
# Specify the location of the Android NDK. Used when targeting Android.
#android-ndk = "/path/to/android-ndk-r25b"
# ============================================================================= # =============================================================================
# General install configuration options # General install configuration options
# ============================================================================= # =============================================================================
@ -756,12 +759,6 @@ change-id = 115898
# it must link to `libgcc_eh.a` to get a working output, and this option have no effect. # it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
#llvm-libunwind = 'no' if Linux, 'in-tree' if Fuchsia #llvm-libunwind = 'no' if Linux, 'in-tree' if Fuchsia
# If this target is for Android, this option will be required to specify where
# the NDK for the target lives. This is used to find the C compiler to link and
# build native code.
# See `src/bootstrap/cc_detect.rs` for details.
#android-ndk = <none> (path)
# Build the sanitizer runtimes for this target. # Build the sanitizer runtimes for this target.
# This option will override the same option under [build] section. # This option will override the same option under [build] section.
#sanitizers = build.sanitizers (bool) #sanitizers = build.sanitizers (bool)

View File

@ -103,7 +103,7 @@ class GenerateAndParseConfig(unittest.TestCase):
"""Test that we can serialize and deserialize a config.toml file""" """Test that we can serialize and deserialize a config.toml file"""
def test_no_args(self): def test_no_args(self):
build = serialize_and_parse([]) build = serialize_and_parse([])
self.assertEqual(build.get_toml("change-id"), '115898') self.assertEqual(build.get_toml("change-id"), '116998')
self.assertEqual(build.get_toml("profile"), 'dist') self.assertEqual(build.get_toml("profile"), 'dist')
self.assertIsNone(build.get_toml("llvm.download-ci-llvm")) self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))

View File

@ -97,20 +97,7 @@ v("llvm-root", None, "set LLVM root")
v("llvm-config", None, "set path to llvm-config") v("llvm-config", None, "set path to llvm-config")
v("llvm-filecheck", None, "set path to LLVM's FileCheck utility") v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
v("python", "build.python", "set path to python") v("python", "build.python", "set path to python")
v("android-cross-path", "target.arm-linux-androideabi.android-ndk", v("android-ndk", "build.android-ndk", "set path to Android NDK")
"Android NDK standalone path (deprecated)")
v("i686-linux-android-ndk", "target.i686-linux-android.android-ndk",
"i686-linux-android NDK standalone path")
v("arm-linux-androideabi-ndk", "target.arm-linux-androideabi.android-ndk",
"arm-linux-androideabi NDK standalone path")
v("armv7-linux-androideabi-ndk", "target.armv7-linux-androideabi.android-ndk",
"armv7-linux-androideabi NDK standalone path")
v("thumbv7neon-linux-androideabi-ndk", "target.thumbv7neon-linux-androideabi.android-ndk",
"thumbv7neon-linux-androideabi NDK standalone path")
v("aarch64-linux-android-ndk", "target.aarch64-linux-android.android-ndk",
"aarch64-linux-android NDK standalone path")
v("x86_64-linux-android-ndk", "target.x86_64-linux-android.android-ndk",
"x86_64-linux-android NDK standalone path")
v("musl-root", "target.x86_64-unknown-linux-musl.musl-root", v("musl-root", "target.x86_64-unknown-linux-musl.musl-root",
"MUSL root installation directory (deprecated)") "MUSL root installation directory (deprecated)")
v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root", v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root",

View File

@ -21,7 +21,6 @@
use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
use crate::core::config::flags::{Color, Flags, Warnings}; use crate::core::config::flags::{Color, Flags, Warnings};
use crate::utils::cache::{Interned, INTERNER}; use crate::utils::cache::{Interned, INTERNER};
use crate::utils::cc_detect::{ndk_compiler, Language};
use crate::utils::channel::{self, GitInfo}; use crate::utils::channel::{self, GitInfo};
use crate::utils::helpers::{exe, output, t}; use crate::utils::helpers::{exe, output, t};
use build_helper::exit; use build_helper::exit;
@ -142,6 +141,7 @@ pub struct Config {
pub color: Color, pub color: Color,
pub patch_binaries_for_nix: Option<bool>, pub patch_binaries_for_nix: Option<bool>,
pub stage0_metadata: Stage0Metadata, pub stage0_metadata: Stage0Metadata,
pub android_ndk: Option<PathBuf>,
pub stdout_is_tty: bool, pub stdout_is_tty: bool,
pub stderr_is_tty: bool, pub stderr_is_tty: bool,
@ -521,7 +521,6 @@ pub struct Target {
pub ranlib: Option<PathBuf>, pub ranlib: Option<PathBuf>,
pub default_linker: Option<PathBuf>, pub default_linker: Option<PathBuf>,
pub linker: Option<PathBuf>, pub linker: Option<PathBuf>,
pub ndk: Option<PathBuf>,
pub sanitizers: Option<bool>, pub sanitizers: Option<bool>,
pub profiler: Option<StringOrBool>, pub profiler: Option<StringOrBool>,
pub rpath: Option<bool>, pub rpath: Option<bool>,
@ -799,6 +798,7 @@ struct Build {
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix", patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
// NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
metrics: Option<bool> = "metrics", metrics: Option<bool> = "metrics",
android_ndk: Option<PathBuf> = "android-ndk",
} }
} }
@ -1039,7 +1039,6 @@ struct TomlTarget {
llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches", llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
llvm_filecheck: Option<String> = "llvm-filecheck", llvm_filecheck: Option<String> = "llvm-filecheck",
llvm_libunwind: Option<String> = "llvm-libunwind", llvm_libunwind: Option<String> = "llvm-libunwind",
android_ndk: Option<String> = "android-ndk",
sanitizers: Option<bool> = "sanitizers", sanitizers: Option<bool> = "sanitizers",
profiler: Option<StringOrBool> = "profiler", profiler: Option<StringOrBool> = "profiler",
rpath: Option<bool> = "rpath", rpath: Option<bool> = "rpath",
@ -1320,6 +1319,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
config.python = build.python.map(PathBuf::from); config.python = build.python.map(PathBuf::from);
config.reuse = build.reuse.map(PathBuf::from); config.reuse = build.reuse.map(PathBuf::from);
config.submodules = build.submodules; config.submodules = build.submodules;
config.android_ndk = build.android_ndk;
set(&mut config.low_priority, build.low_priority); set(&mut config.low_priority, build.low_priority);
set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.compiler_docs, build.compiler_docs);
set(&mut config.library_docs_private_items, build.library_docs_private_items); set(&mut config.library_docs_private_items, build.library_docs_private_items);
@ -1600,18 +1600,11 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
.llvm_libunwind .llvm_libunwind
.as_ref() .as_ref()
.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
if let Some(ref s) = cfg.android_ndk {
target.ndk = Some(config.src.join(s));
}
if let Some(s) = cfg.no_std { if let Some(s) = cfg.no_std {
target.no_std = s; target.no_std = s;
} }
target.cc = cfg.cc.map(PathBuf::from).or_else(|| { target.cc = cfg.cc.map(PathBuf::from);
target.ndk.as_ref().map(|ndk| ndk_compiler(Language::C, &triple, ndk)) target.cxx = cfg.cxx.map(PathBuf::from);
});
target.cxx = cfg.cxx.map(PathBuf::from).or_else(|| {
target.ndk.as_ref().map(|ndk| ndk_compiler(Language::CPlusPlus, &triple, ndk))
});
target.ar = cfg.ar.map(PathBuf::from); target.ar = cfg.ar.map(PathBuf::from);
target.ranlib = cfg.ranlib.map(PathBuf::from); target.ranlib = cfg.ranlib.map(PathBuf::from);
target.linker = cfg.linker.map(PathBuf::from); target.linker = cfg.linker.map(PathBuf::from);

View File

@ -78,7 +78,7 @@
/// ///
/// If you make any major changes (such as adding new values or changing default values), please /// If you make any major changes (such as adding new values or changing default values), please
/// ensure that the associated PR ID is added to the end of this list. /// ensure that the associated PR ID is added to the end of this list.
pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898]; pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898, 116998];
/// Extra --check-cfg to add when building /// Extra --check-cfg to add when building
/// (Mode restriction, config name, config values (if any)) /// (Mode restriction, config name, config values (if any))

View File

@ -26,7 +26,7 @@
use std::process::Command; use std::process::Command;
use std::{env, iter}; use std::{env, iter};
use crate::core::config::{Target, TargetSelection}; use crate::core::config::TargetSelection;
use crate::utils::helpers::output; use crate::utils::helpers::output;
use crate::{Build, CLang, GitRepo}; use crate::{Build, CLang, GitRepo};
@ -107,10 +107,11 @@ pub fn find(build: &Build) {
pub fn find_target(build: &Build, target: TargetSelection) { pub fn find_target(build: &Build, target: TargetSelection) {
let mut cfg = new_cc_build(build, target); let mut cfg = new_cc_build(build, target);
let config = build.config.target_config.get(&target); let config = build.config.target_config.get(&target);
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { if let Some(cc) = config
.and_then(|c| c.cc.clone())
.or_else(|| default_compiler(&mut cfg, Language::C, target, build))
{
cfg.compiler(cc); cfg.compiler(cc);
} else {
set_compiler(&mut cfg, Language::C, target, config, build);
} }
let compiler = cfg.get_compiler(); let compiler = cfg.get_compiler();
@ -127,12 +128,12 @@ pub fn find_target(build: &Build, target: TargetSelection) {
// We'll need one anyways if the target triple is also a host triple // We'll need one anyways if the target triple is also a host triple
let mut cfg = new_cc_build(build, target); let mut cfg = new_cc_build(build, target);
cfg.cpp(true); cfg.cpp(true);
let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { let cxx_configured = if let Some(cxx) = config
.and_then(|c| c.cxx.clone())
.or_else(|| default_compiler(&mut cfg, Language::CPlusPlus, target, build))
{
cfg.compiler(cxx); cfg.compiler(cxx);
true true
} else if build.hosts.contains(&target) || build.build == target {
set_compiler(&mut cfg, Language::CPlusPlus, target, config, build);
true
} else { } else {
// Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars). // Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars).
cfg.try_get_compiler().is_ok() cfg.try_get_compiler().is_ok()
@ -161,22 +162,21 @@ pub fn find_target(build: &Build, target: TargetSelection) {
} }
} }
fn set_compiler( fn default_compiler(
cfg: &mut cc::Build, cfg: &mut cc::Build,
compiler: Language, compiler: Language,
target: TargetSelection, target: TargetSelection,
config: Option<&Target>,
build: &Build, build: &Build,
) { ) -> Option<PathBuf> {
match &*target.triple { match &*target.triple {
// When compiling for android we may have the NDK configured in the // When compiling for android we may have the NDK configured in the
// config.toml in which case we look there. Otherwise the default // config.toml in which case we look there. Otherwise the default
// compiler already takes into account the triple in question. // compiler already takes into account the triple in question.
t if t.contains("android") => { t if t.contains("android") => build
if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) { .config
cfg.compiler(ndk_compiler(compiler, &*target.triple, ndk)); .android_ndk
} .as_ref()
} .map(|ndk| ndk_compiler(compiler, &*target.triple, ndk)),
// The default gcc version from OpenBSD may be too old, try using egcc, // The default gcc version from OpenBSD may be too old, try using egcc,
// which is a gcc version from ports, if this is the case. // which is a gcc version from ports, if this is the case.
@ -184,45 +184,48 @@ fn set_compiler(
let c = cfg.get_compiler(); let c = cfg.get_compiler();
let gnu_compiler = compiler.gcc(); let gnu_compiler = compiler.gcc();
if !c.path().ends_with(gnu_compiler) { if !c.path().ends_with(gnu_compiler) {
return; return None;
} }
let output = output(c.to_command().arg("--version")); let output = output(c.to_command().arg("--version"));
let i = match output.find(" 4.") { let i = output.find(" 4.")?;
Some(i) => i,
None => return,
};
match output[i + 3..].chars().next().unwrap() { match output[i + 3..].chars().next().unwrap() {
'0'..='6' => {} '0'..='6' => {}
_ => return, _ => return None,
} }
let alternative = format!("e{gnu_compiler}"); let alternative = format!("e{gnu_compiler}");
if Command::new(&alternative).output().is_ok() { if Command::new(&alternative).output().is_ok() {
cfg.compiler(alternative); Some(PathBuf::from(alternative))
} else {
None
} }
} }
"mips-unknown-linux-musl" => { "mips-unknown-linux-musl" if compiler == Language::C => {
if cfg.get_compiler().path().to_str() == Some("gcc") { if cfg.get_compiler().path().to_str() == Some("gcc") {
cfg.compiler("mips-linux-musl-gcc"); Some(PathBuf::from("mips-linux-musl-gcc"))
} else {
None
} }
} }
"mipsel-unknown-linux-musl" => { "mipsel-unknown-linux-musl" if compiler == Language::C => {
if cfg.get_compiler().path().to_str() == Some("gcc") { if cfg.get_compiler().path().to_str() == Some("gcc") {
cfg.compiler("mipsel-linux-musl-gcc"); Some(PathBuf::from("mipsel-linux-musl-gcc"))
} else {
None
} }
} }
t if t.contains("musl") => { t if t.contains("musl") && compiler == Language::C => {
if let Some(root) = build.musl_root(target) { if let Some(root) = build.musl_root(target) {
let guess = root.join("bin/musl-gcc"); let guess = root.join("bin/musl-gcc");
if guess.exists() { if guess.exists() { Some(guess) } else { None }
cfg.compiler(guess); } else {
} None
} }
} }
_ => {} _ => None,
} }
} }
@ -243,10 +246,22 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path
let api_level = let api_level =
if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" }; if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" };
let compiler = format!("{}{}-{}", triple_translated, api_level, compiler.clang()); let compiler = format!("{}{}-{}", triple_translated, api_level, compiler.clang());
ndk.join("bin").join(compiler) let host_tag = if cfg!(target_os = "macos") {
// The NDK uses universal binaries, so this is correct even on ARM.
"darwin-x86_64"
} else if cfg!(target_os = "windows") {
"windows-x86_64"
} else {
// NDK r25b only has official releases for macOS, Windows and Linux.
// Try the Linux directory everywhere else, on the assumption that the OS has an
// emulation layer that can cope (e.g. BSDs).
"linux-x86_64"
};
ndk.join("toolchains").join("llvm").join("prebuilt").join(host_tag).join("bin").join(compiler)
} }
/// The target programming language for a native compiler. /// The target programming language for a native compiler.
#[derive(PartialEq)]
pub(crate) enum Language { pub(crate) enum Language {
/// The compiler is targeting C. /// The compiler is targeting C.
C, C,

View File

@ -30,7 +30,7 @@ ENV PATH=$PATH:/android/sdk/platform-tools
ENV TARGETS=arm-linux-androideabi ENV TARGETS=arm-linux-androideabi
ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ ENV RUST_CONFIGURE_ARGS --android-ndk=/android/ndk/
ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS

View File

@ -19,12 +19,7 @@ ENV TARGETS=$TARGETS,x86_64-linux-android
ENV RUST_CONFIGURE_ARGS \ ENV RUST_CONFIGURE_ARGS \
--enable-extended \ --enable-extended \
--enable-profiler \ --enable-profiler \
--arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ --android-ndk=/android/ndk/ \
--armv7-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
--thumbv7neon-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
--i686-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
--aarch64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
--x86_64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
--disable-docs --disable-docs
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS