From aad44b3b5420bdb0baa963cda669d7f2b1d9cf61 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 12 Oct 2022 17:02:31 -0700 Subject: [PATCH] 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/" subdirectory. --- config.example.toml | 11 +-- src/bootstrap/bootstrap_test.py | 2 +- src/bootstrap/configure.py | 15 +--- src/bootstrap/src/core/config/config.rs | 17 ++-- src/bootstrap/src/lib.rs | 2 +- src/bootstrap/src/utils/cc_detect.rs | 81 +++++++++++-------- .../docker/host-x86_64/arm-android/Dockerfile | 2 +- .../host-x86_64/dist-android/Dockerfile | 7 +- 8 files changed, 62 insertions(+), 75 deletions(-) diff --git a/config.example.toml b/config.example.toml index 4f44121410ecd..66fa91d4bad15 100644 --- a/config.example.toml +++ b/config.example.toml @@ -30,7 +30,7 @@ # # 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. -change-id = 115898 +change-id = 116998 # ============================================================================= # Tweaking how LLVM is compiled @@ -377,6 +377,9 @@ change-id = 115898 # this is not intended to be used during local development. #metrics = false +# Specify the location of the Android NDK. Used when targeting Android. +#android-ndk = "/path/to/android-ndk-r25b" + # ============================================================================= # 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. #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 = (path) - # Build the sanitizer runtimes for this target. # This option will override the same option under [build] section. #sanitizers = build.sanitizers (bool) diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py index fefd6b187394a..7f16cac78901c 100644 --- a/src/bootstrap/bootstrap_test.py +++ b/src/bootstrap/bootstrap_test.py @@ -103,7 +103,7 @@ class GenerateAndParseConfig(unittest.TestCase): """Test that we can serialize and deserialize a config.toml file""" def test_no_args(self): 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.assertIsNone(build.get_toml("llvm.download-ci-llvm")) diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index f469dbea6dbee..bfef3e672407d 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -97,20 +97,7 @@ def v(*args): v("llvm-config", None, "set path to llvm-config") v("llvm-filecheck", None, "set path to LLVM's FileCheck utility") v("python", "build.python", "set path to python") -v("android-cross-path", "target.arm-linux-androideabi.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("android-ndk", "build.android-ndk", "set path to Android NDK") v("musl-root", "target.x86_64-unknown-linux-musl.musl-root", "MUSL root installation directory (deprecated)") v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root", diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 7ca1bbad96843..5b5334b0a5572 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -21,7 +21,6 @@ use std::str::FromStr; use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::utils::cache::{Interned, INTERNER}; -use crate::utils::cc_detect::{ndk_compiler, Language}; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{exe, output, t}; use build_helper::exit; @@ -142,6 +141,7 @@ pub struct Config { pub color: Color, pub patch_binaries_for_nix: Option, pub stage0_metadata: Stage0Metadata, + pub android_ndk: Option, pub stdout_is_tty: bool, pub stderr_is_tty: bool, @@ -521,7 +521,6 @@ pub struct Target { pub ranlib: Option, pub default_linker: Option, pub linker: Option, - pub ndk: Option, pub sanitizers: Option, pub profiler: Option, pub rpath: Option, @@ -799,6 +798,7 @@ define_config! { patch_binaries_for_nix: Option = "patch-binaries-for-nix", // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally metrics: Option = "metrics", + android_ndk: Option = "android-ndk", } } @@ -1039,7 +1039,6 @@ define_config! { llvm_has_rust_patches: Option = "llvm-has-rust-patches", llvm_filecheck: Option = "llvm-filecheck", llvm_libunwind: Option = "llvm-libunwind", - android_ndk: Option = "android-ndk", sanitizers: Option = "sanitizers", profiler: Option = "profiler", rpath: Option = "rpath", @@ -1320,6 +1319,7 @@ impl Config { config.python = build.python.map(PathBuf::from); config.reuse = build.reuse.map(PathBuf::from); config.submodules = build.submodules; + config.android_ndk = build.android_ndk; set(&mut config.low_priority, build.low_priority); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.library_docs_private_items, build.library_docs_private_items); @@ -1600,18 +1600,11 @@ impl Config { .llvm_libunwind .as_ref() .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 { target.no_std = s; } - target.cc = cfg.cc.map(PathBuf::from).or_else(|| { - target.ndk.as_ref().map(|ndk| ndk_compiler(Language::C, &triple, ndk)) - }); - target.cxx = cfg.cxx.map(PathBuf::from).or_else(|| { - target.ndk.as_ref().map(|ndk| ndk_compiler(Language::CPlusPlus, &triple, ndk)) - }); + target.cc = cfg.cc.map(PathBuf::from); + target.cxx = cfg.cxx.map(PathBuf::from); target.ar = cfg.ar.map(PathBuf::from); target.ranlib = cfg.ranlib.map(PathBuf::from); target.linker = cfg.linker.map(PathBuf::from); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 97c743074af43..705c27bb92233 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -78,7 +78,7 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; /// /// 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. -pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898]; +pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898, 116998]; /// Extra --check-cfg to add when building /// (Mode restriction, config name, config values (if any)) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 3d3f93f7720ea..52b36ce75f343 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -26,7 +26,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::{env, iter}; -use crate::core::config::{Target, TargetSelection}; +use crate::core::config::TargetSelection; use crate::utils::helpers::output; use crate::{Build, CLang, GitRepo}; @@ -107,10 +107,11 @@ pub fn find(build: &Build) { pub fn find_target(build: &Build, target: TargetSelection) { let mut cfg = new_cc_build(build, 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); - } else { - set_compiler(&mut cfg, Language::C, target, config, build); } 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 let mut cfg = new_cc_build(build, target); 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); true - } else if build.hosts.contains(&target) || build.build == target { - set_compiler(&mut cfg, Language::CPlusPlus, target, config, build); - true } else { // Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars). 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, compiler: Language, target: TargetSelection, - config: Option<&Target>, build: &Build, -) { +) -> Option { match &*target.triple { // When compiling for android we may have the NDK configured in the // config.toml in which case we look there. Otherwise the default // compiler already takes into account the triple in question. - t if t.contains("android") => { - if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) { - cfg.compiler(ndk_compiler(compiler, &*target.triple, ndk)); - } - } + t if t.contains("android") => build + .config + .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, // 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 gnu_compiler = compiler.gcc(); if !c.path().ends_with(gnu_compiler) { - return; + return None; } let output = output(c.to_command().arg("--version")); - let i = match output.find(" 4.") { - Some(i) => i, - None => return, - }; + let i = output.find(" 4.")?; match output[i + 3..].chars().next().unwrap() { '0'..='6' => {} - _ => return, + _ => return None, } let alternative = format!("e{gnu_compiler}"); 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") { - 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") { - 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) { let guess = root.join("bin/musl-gcc"); - if guess.exists() { - cfg.compiler(guess); - } + if guess.exists() { Some(guess) } else { None } + } else { + None } } - _ => {} + _ => None, } } @@ -243,10 +246,22 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path let api_level = if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" }; 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. +#[derive(PartialEq)] pub(crate) enum Language { /// The compiler is targeting C. C, diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index db11700af2815..abca06fb9fb4c 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -30,7 +30,7 @@ ENV PATH=$PATH:/android/sdk/platform-tools 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 diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index b09b6edb01a6d..20b72b377cad2 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -19,12 +19,7 @@ ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-profiler \ - --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \ - --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/ \ + --android-ndk=/android/ndk/ \ --disable-docs ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS