diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -182,6 +182,8 @@ EffectiveTriple = std::move(ET); } + std::optional getFallbackAndroidRuntimePath() const; + mutable std::optional cxxStdlibType; mutable std::optional runtimeLibType; mutable std::optional unwindLibType; diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -677,6 +677,46 @@ return Args.MakeArgString(getCompilerRT(Args, Component, Type)); } +// Android target triples contain a target version. If we don't have libraries +// for the exact target version, we should fall back to the next newest version +// or a versionless path, if any. +std::optional ToolChain::getFallbackAndroidRuntimePath() const { + llvm::Triple TripleWithoutLevel(getTriple()); + TripleWithoutLevel.setEnvironmentName("android"); // remove any version number + const std::string &TripleWithoutLevelStr = TripleWithoutLevel.str(); + unsigned TripleVersion = getTriple().getEnvironmentVersion().getMajor(); + unsigned BestVersion = 0; + + SmallString<128> LibDir(D.ResourceDir); + llvm::sys::path::append(LibDir, "lib"); + SmallString<32> TripleDir; + std::error_code EC; + for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(LibDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef DirName = llvm::sys::path::filename(LI->path()); + StringRef DirNameSuffix = DirName; + if (DirNameSuffix.consume_front(TripleWithoutLevelStr)) { + if (DirNameSuffix.empty() && TripleDir.empty()) { + TripleDir = DirName; + } else { + unsigned Version; + if (!DirNameSuffix.getAsInteger(10, Version) && Version > BestVersion && + Version < TripleVersion) { + BestVersion = Version; + TripleDir = DirName; + } + } + } + } + + if (!TripleDir.empty()) { + llvm::sys::path::append(LibDir, TripleDir); + return std::string(LibDir); + } + + return {}; +} + std::optional ToolChain::getRuntimePath() const { auto getPathForTriple = [this](const llvm::Triple &Triple) -> std::optional { @@ -712,15 +752,8 @@ return *Path; } - // Android targets may include an API level at the end. We still want to fall - // back on a path without the API level. - if (getTriple().isAndroid() && - getTriple().getEnvironmentName() != "android") { - llvm::Triple TripleWithoutLevel = getTriple(); - TripleWithoutLevel.setEnvironmentName("android"); - if (auto Path = getPathForTriple(TripleWithoutLevel)) - return *Path; - } + if (getTriple().isAndroid()) + return getFallbackAndroidRuntimePath(); return {}; } diff --git a/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android21/libclang_rt.builtins.a b/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android23/libclang_rt.builtins.a rename from clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android21/libclang_rt.builtins.a rename to clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android23/libclang_rt.builtins.a diff --git a/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android21/libclang_rt.builtins.a b/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android29/libclang_rt.builtins.a rename from clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android21/libclang_rt.builtins.a rename to clang/test/Driver/Inputs/resource_dir_with_per_target_subdir/lib/aarch64-unknown-linux-android29/libclang_rt.builtins.a diff --git a/clang/test/Driver/linux-per-target-runtime-dir.c b/clang/test/Driver/linux-per-target-runtime-dir.c --- a/clang/test/Driver/linux-per-target-runtime-dir.c +++ b/clang/test/Driver/linux-per-target-runtime-dir.c @@ -30,13 +30,29 @@ // RUN: --target=aarch64-unknown-linux-android21 \ // RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ // RUN: | FileCheck --check-prefix=CHECK-FILE-NAME-ANDROID21 %s -// CHECK-FILE-NAME-ANDROID21: lib{{/|\\}}aarch64-unknown-linux-android21{{/|\\}}libclang_rt.builtins.a +// CHECK-FILE-NAME-ANDROID21: lib{{/|\\}}aarch64-unknown-linux-android{{/|\\}}libclang_rt.builtins.a // RUN: %clang -rtlib=compiler-rt -print-file-name=libclang_rt.builtins.a 2>&1 \ // RUN: --target=aarch64-unknown-linux-android23 \ // RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ // RUN: | FileCheck --check-prefix=CHECK-FILE-NAME-ANDROID23 %s -// CHECK-FILE-NAME-ANDROID23: lib{{/|\\}}aarch64-unknown-linux-android{{/|\\}}libclang_rt.builtins.a +// CHECK-FILE-NAME-ANDROID23: lib{{/|\\}}aarch64-unknown-linux-android23{{/|\\}}libclang_rt.builtins.a + +// RUN: %clang -rtlib=compiler-rt -print-file-name=libclang_rt.builtins.a 2>&1 \ +// RUN: --target=aarch64-unknown-linux-android26 \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ +// RUN: | FileCheck --check-prefix=CHECK-FILE-NAME-ANDROID23 %s + +// RUN: %clang -rtlib=compiler-rt -print-file-name=libclang_rt.builtins.a 2>&1 \ +// RUN: --target=aarch64-unknown-linux-android29 \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ +// RUN: | FileCheck --check-prefix=CHECK-FILE-NAME-ANDROID29 %s +// CHECK-FILE-NAME-ANDROID29: lib{{/|\\}}aarch64-unknown-linux-android29{{/|\\}}libclang_rt.builtins.a + +// RUN: %clang -rtlib=compiler-rt -print-file-name=libclang_rt.builtins.a 2>&1 \ +// RUN: --target=aarch64-unknown-linux-android31 \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \ +// RUN: | FileCheck --check-prefix=CHECK-FILE-NAME-ANDROID29 %s // RUN: %clang -rtlib=compiler-rt -print-file-name=libclang_rt.builtins.a 2>&1 \ // RUN: --target=aarch64-unknown-linux-android \