【问题标题】:What's the use of LLVM in Android NDK Toolchains?Android NDK 工具链中的 LLVM 有什么用?
【发布时间】:2023-03-03 23:47:01
【问题描述】:

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


简单回顾:

我在 Ubuntu 上使用 Gradlew 构建我的本地项目,目标是 arm 和 x86_64 架构。貌似LLVM被用来调用arm-linux-androideabi-4.9的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 ...

  • “...”表示我已经剪掉了这条单行命令的长尾。
  • 个人文件夹和项目的名称已更改。

让我们看看 Android NDK 的 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 工具链中的实际用途是什么?

感谢您的帮助:)

【问题讨论】:

    标签: android c++ linux android-ndk toolchain


    【解决方案1】:

    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(构建过程使用的次要工具),而且这些目录也进来了每个架构一个副本(即使它们在技术上可能跨架构工作)。

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

    【讨论】:

    • 感谢您的线索,mstorsjo :) 我刚刚从here 发现,自 NDK Rev. 11(2016 年 3 月)以来,GCC 已被删除。并且来自here,“选项 -gcc-toolchain 仅告诉构建的 Clang 在哪里寻找 C++ 标准库和头文件,它与 LLVM/Clang 构建过程无关” /跨度>
    • 但我仍然很好奇 Clang 是如何将项目定义为“还不能迁移到使用 Clang”的?它可以决定是否在 arm-linux-androideabi-4.9/ 或 x86_64-4.9 中使用“C/C++ 标准库和头文件”吗? (我想知道我们是否可以删除所有这些遗留文件夹并且我的项目可以正常构建)
    • NDK r11 仅删除了一个较旧的 GCC 版本,但 NDK r18 完全删除了 GCC。不,您不能删除这些文件夹,它们仍然包含每个架构的 binutils,并且您使用的 NDK r17 仍然从这些目录中使用它们。在这种情况下,-gcc-toolchain 不用于查找任何标准库或头文件,而仅用于查找构建期间使用的额外工具(链接器)。在最新的 NDK r19 中,这些目录仍然存在,但不被正常构建使用。在以后的版本中,它们可能不再包含在内。
    • Clang 没有定义“还不能使用 Clang”的项目。从历史上看,当使用ndk-build 系统构建时,开发人员可以设置变量NDK_TOOLCHAIN_VERSION 来选择要使用的GCC 版本,当有多个版本可供选择时。在某些时候添加了 Clang,并且可以设置 NDK_TOOLCHAIN_VERSION=clang 来代替它。将 clang 设为默认后,如果项目更喜欢使用 GCC 构建,他们仍然可以覆盖 NDK_TOOLCHAIN_VERSION,但在最新版本中不再可能,因为 GCC 已被完全删除。
    【解决方案2】:

    LLVM 现在是一个伞形项目,它包含多种模块化和可重用的编译器和工具链技术。您可以在The LLVM Compiler Infrastructure查看更多详细信息。

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

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

    在未来的 NDK 版本中,当所有 gcc 相关的工具、头文件和库都完全移植到 llvm 时,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 被配置为构建工具、头文件和库的旧路径。

    但是,从 NDK r19b 开始,--gcc-toolchain--sysroot 被配置为新的工具链 llvm,即 toolchains/llvm/prebuilt/darwin-x86_64,以及工具(例如ranlib、ar、strip 等)头文件和“llvm 版本”的库将被使用。

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

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

    【讨论】:

      猜你喜欢
      • 2018-09-14
      • 2021-06-12
      • 2016-05-09
      • 2018-09-17
      • 2012-02-25
      • 2014-07-03
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多