9

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


A little recap:

I was building my native project with Gradlew on Ubuntu, targeting arm and x86_64 architectures. Seems that LLVM were utilized to call C/C++ compiler of arm-linux-androideabi-4.9 as well as x86_64(?)

The following is extracted from 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 ...

..and the following is extracted from 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 ...

  • The "..." indicates that there's a long tail of this single-line command I've trimmed off.
  • Names of personal folders & project were changed.

Let's take a look what's inside Android NDK's toolchains folder:

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

It's quite confusing to me. I thought llvm is a kind of toolchain since it's placed here, next to other toolchains. Again, what's actually the use of LLVM in Android NDK Toolchains?

Thanks for the help :)

Nikolas
  • 141
  • 1
  • 2
  • 6

2 Answers2

17

LLVM is the compiler (backend). The compiler used is Clang, which resides within the llvm directory. (LLVM is the name of the component of Clang that does the actual code generation, aka backend.)

Previously, the NDK used GCC as compiler. With GCC, each target architecture (arm, aarch64, x86 etc) had a separate copy of GCC built with that individual target configured. Clang/LLVM on the other hand can target any configured architecture with one single compiler executable. So with Clang, you'll save a bit of diskspace, avoiding to have many separate compiler executables. That's why there's only one copy of the llvm directory tree.

In NDK r17, you have both GCC and Clang compilers available; Clang is used by default but GCC is still available for projects that haven't been able to migrate to using Clang yet. In newer NDK versions, the old GCC is removed.

In the newer NDK versions, even if GCC is removed, the architecture specific directories like aarch64-linux-android-4.9 are still kept around, as the GNU binutils (minor tools used by the build process) are still used, and those also come in one copy per architecture (even though they technically might work across architectures).

And as for why building for e.g. arm also mentions x86_64; when you are running Clang or GCC, you are running an executable for your build computer which runs x86_64, hence the prebuilt/linux-x86_64 part of the paths.

mstorsjo
  • 12,983
  • 2
  • 39
  • 62
  • Thanks for your clue, mstorsjo :) II've just found from [here](https://developer.android.com/ndk/downloads/revision_history.html) that GCC was removed since NDK Rev. 11 (March 2016). And from [here](https://stackoverflow.com/questions/23665181/gcc-toolchain-for-llvm) that "_the option -gcc-toolchain only tells the built Clang where to look for a C++ standard library and headers, it has nothing to do with the LLVM/Clang build process_" – Nikolas Feb 21 '19 at 01:49
  • But I'm still curious about how Clang define a project as "not able to migrate to using Clang yet"? Can it decide whether or not to use "C/C++ standard library and headers" inside arm-linux-androideabi-4.9/ or x86_64-4.9? (I'm wondering if we can remove all these legacy folders and my project can be built just fine) – Nikolas Feb 21 '19 at 01:56
  • 1
    NDK r11 only removed one older GCC version, but NDK r18 removed GCC altogether. No, you can't remove those folders, they still contain the binutils for each architecture, and NDK r17 as you are using still use them from those directories. In this case, `-gcc-toolchain` isn't used for finding any standard library or headers, but only for finding extra tools used during the build (the linker). In the latest NDK r19, those directories are still present but aren't used by a normal build. In later versions they might no longer be included. – mstorsjo Feb 21 '19 at 08:57
  • 1
    Clang doesn't define a project "not able to mgirate to using Clang yet". Historically, when building using the `ndk-build` system, the developer could set the variable `NDK_TOOLCHAIN_VERSION` to pick which version of GCC to use, when there were multiple ones to choose from. At some point Clang was added, and one could set `NDK_TOOLCHAIN_VERSION=clang` to pick that instead. After clang was made default, projects could still override `NDK_TOOLCHAIN_VERSION` if they preferred building with GCC, but that's no longer possible in the latest versions as GCC has been removed altogether. – mstorsjo Feb 21 '19 at 09:00
11

LLVM is an umbrela project now, and it contains multiple modular and reusable compiler and toolchain technologies. You can check more details at The LLVM Compiler Infrastructure.

For Android NDK, llvm became the default toolchain since r13b and gcc was removed since r18b.

According to toolchains directory toolchains/llvm/prebuilt/darwin-x86_64, llvm supports all the ABIs, i.e. x86, x86_64, arm, arm64.

Probably there will be only one llvm directory under toolchains directory in future NDK releases when all the gcc related tools, headers and libs are completely ported to llvm.

enter image description here

References that may help: Android NDK path variable for "strip" command in CMake build tool chain


Updates

Just did a quick test on different NDK revisions to check the configurations for --gcc-toolchain and --sysroot which are for cross compilation.

On 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 

On 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

On 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

On 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 

As seen above, before NDK r19b, NDK uses clang compiler but the --gcc-toolchain and --sysroot are configured as the older paths for build tools, headers and libs.

But, since NDK r19b, the --gcc-toolchain and --sysroot are configured as the new tool chains llvm, i.e. toolchains/llvm/prebuilt/darwin-x86_64, and the tools (e.g. ranlib, ar, strip, etc) header files and libraries of "llvm version" will be used.

Also, note that toolchains/llvm/prebuilt/darwin-x86_64 contains the support for all the Android ABIs, i.e. aarch64-linux-android for arm64-v8a, arm-linux-androideabi for armeabi-v7a, i686-linux-android for x86, x86_64-linux-android for x86_64.

So, you can try out the NDK r19b if you want to purely use llvm toolchains.

shizhen
  • 12,251
  • 9
  • 52
  • 88