Android NDK 工具链中的 LLVM 有什么用?

What's the use of LLVM in Android NDK Toolchains?

LLVM 在Android NDK 工具链中有什么用?


小回顾:

我正在 Ubuntu 上使用 Gradlew 构建我的原生项目,目标是 arm 和 x86_64 架构。似乎 LLVM 被用来调用 arm-linux-androideabi-4.9 和 [=32= 的 C/C++ 编译器]x86_64(?)

以下摘自armeabi-v7a/ndkBuild_build_output.log:

/home/mypc/Android/android-ndk-r17c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -MMD -MP -MF /home/mypc/git/android-project-1/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/objs-debug/module-5/stream_cpp.o.d -gcc-toolchain /home/mypc/Android/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -fpic -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument ...

..以下内容摘自x86_64/ndkBuild_build_output.log:

/home/mypc/Android/android-ndk-r17c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -MMD -MP -MF /home/mypc/git/android-project-1/build/intermediates/ndkBuild/debug/obj/local/x86_64/objs-debug/module-5/stream_cpp.o.d -gcc-toolchain /home/mypc/Android/android-ndk-r17c/toolchains/x86_64-4.9/prebuilt/linux-x86_64 -target x86_64-none-linux-android -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC -Wno-invalid-command-line-argument ...

让我们看看AndroidNDK的toolchains文件夹里面有什么:

myacc:~/.../android-ndk-r17c/toolchains$ tree -L 1
.
├── aarch64-linux-android-4.9
├── arm-linux-androideabi-4.9
├── llvm
├── mips64el-linux-android-4.9
├── mipsel-linux-android-4.9
├── NOTICE-MIPS
├── NOTICE-MIPS64
├── renderscript
├── x86-4.9
└── x86_64-4.9

这让我很困惑。我认为 llvm 是一种工具链,因为它放在这里,紧挨着其他工具链。同样,LLVM 在 Android NDK 工具链中的实际用途是什么?

感谢您的帮助:)

LLVM 是编译器(后端)。使用的编译器是 Clang,它位于 llvm 目录中。 (LLVM 是执行实际代码生成的 Clang 组件的名称,也称为后端。)

以前,NDK 使用 GCC 作为编译器。使用 GCC,每个目标架构(arm、aarch64、x86 等)都有一个单独的 GCC 副本,该副本是使用配置的单个目标构建的。另一方面,Clang/LLVM 可以使用一个编译器可执行文件来定位任何已配置的体系结构。因此,使用 Clang,您将节省一些磁盘空间,避免拥有许多单独的编译器可执行文件。这就是为什么只有一个 llvm 目录树的副本。

在 NDK r17 中,您可以同时使用 GCC 和 Clang 编译器;默认情况下使用 Clang,但 GCC 仍可用于尚未能够迁移到使用 Clang 的项目。在较新的 NDK 版本中,旧的 GCC 已被删除。

在较新的 NDK 版本中,即使删除了 GCC,像 aarch64-linux-android-4.9 这样的架构特定目录仍然保留,因为 GNU binutils(构建过程中使用的次要工具)仍在使用,并且每个架构也有一个副本(即使它们在技术上可能跨架构工作)。

至于为什么要为例如手臂还提到 x86_64;当您是 运行 Clang 或 GCC 时,您是 运行 运行 x86_64 的构建计算机的可执行文件,因此是路径的 prebuilt/linux-x86_64 部分。

LLVM 现在是一个 umbrela 项目,它包含多种模块化和可重用的编译器和工具链技术。您可以在 The LLVM Compiler Infrastructure.

查看更多详细信息

对于 Android NDK,llvm 自 r13b 起成为默认工具链,自 r18b 起删除了 gcc。

根据工具链目录 toolchains/llvm/prebuilt/darwin-x86_64,llvm 支持所有 ABI,即 x86、x86_64、arm、arm64。

当所有gcc相关工具,headers和libs完全移植到llvm时,可能在未来的NDK版本中toolchains目录下只有一个llvm目录。

可能有帮助的参考资料:Android NDK path variable for "strip" command in CMake build tool chain


更新

刚刚对不同的 NDK 修订版进行了快速测试,以检查用于交叉编译的 --gcc-toolchain--sysroot 的配置。

在 r16b

--target=armv7-none-linux-androideabi 
--gcc-toolchain=~/ndks/android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
--sysroot=~/ndks/android-ndk-r16b/sysroot 

在 r17c

--target=armv7-none-linux-androideabi
--gcc-toolchain=~/ndks/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
--sysroot=~/ndks/android-ndk-r17c/sysroot

在 r18b

--target=armv7-none-linux-androideabi19
--gcc-toolchain=~/ndks/android-ndk-r18b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
--sysroot=~/ndks/android-ndk-r18b/sysroot

在 r19b

--target=armv7-none-linux-androideabi19 
--gcc-toolchain=~/ndks/android-ndk-r19b/toolchains/llvm/prebuilt/darwin-x86_64 
--sysroot=~/ndks/android-ndk-r19b/toolchains/llvm/prebuilt/darwin-x86_64/sysroot 

如上所示,在 NDK r19b 之前,NDK 使用 clang 编译器,但 --gcc-toolchain--sysroot 被配置为构建工具的旧路径, headers 和库。

但是,自从 NDK r19b--gcc-toolchain--sysroot 被配置为新的工具链 llvm,即 toolchains/llvm/prebuilt/darwin-x86_64,将使用 "llvm version" 的工具(例如 ranlib、ar、strip 等)header 个文件和库。

此外,请注意 toolchains/llvm/prebuilt/darwin-x86_64 包含对所有 Android ABI 的支持,即 aarch64-linux-android for arm64-v8aarm-linux-androideabi 用于 armeabi-v7ai686-linux-android 用于 x86x86_64-linux-android 用于 x86_64

所以,如果你想纯粹使用 llvm 工具链,你可以试试 NDK r19b。