Linux Embedded

Le blog des technologies libres et embarquées

My first Linux kernel built with Clang compiler!

Following his internship at Smile in 2018 on LLVM/Clang integration into Buildroot [1], Valentin Korenblit still maintains these packages on his spare time (thanks to him!), up to the latest current version llvm/Clang 8.0.0.

At the same time the Linux kernel continues evolving to support Clang compiler thanks to Google engineers. See Phoronix article [2] and « Compiling the Linux kernel with LLVM tools » conference at FOSDEM 2019 [3].

Valentin stated in his internship report:

Clang was designed to offer GCC compatibility, so it accepts most of GCC’s command line arguments to specify the compiler options. However, GCC offers a lot of extensions to the standard language while Clang’s purpose is being standard-compliant. Because of this, Clang cannot be a replacement for GCC when compiling projects that depend on GCC extensions, as it happens with Linux kernel. In this case, Linux can’t be built because Clang does not accept the following kinds of constructs:

• Variable length arrays inside structures
• Nested Functions
• Explicit register variables

Furthermore, Linux kernel still depends on GNU assembler and linker.

http://www.linuxembedded.fr/2018/07/llvmclang-integration-into-buildroot/

In order to check by ourselves if it is now possible to compile a kernel with Clang using buildroot, we will compile the aarch64 configuration for Qemu (qemu_aarch64_virt_defconfig).
First, we will try with the GCC toolchain in order to verify that everything works fine. Then we will recompile the kernel with Clang.

$ make qemu_aarch64_virt_defconfig

In order to speedup the build, we use an prebuilt external toolchain (Arm AArch64 2019.03) instead of an internal toolchain. We could also use an aarch64 toolchain downloaded from toolchain-builder project (https://toolchains.bootlin.com) that provide several toolchains generated by Buildroot.

When the build is finished, we can test the system using Qemu as indicated in the file « board/qemu/aarch64-virt/readme.txt »

The system should boot correctly.
(If not, check your Qemu version and make sure it’s at least at the same version as the one present in the readme.txt).

Now that we tested that the kernel build correctly with GCC, we are going to try again with Clang. To do that, we first clean the kernel’s build directory

$ make linux-dirclean

Note: We keep the user space content previously built by the GCC toolchain.
Building user space programs using Clang is not supported yet by buildroot.

We then need to build the Clang compiler itself. This is done by the host-clang package

We cannot select host-clang in buildroot’s menuconfig, because host-clang can only be selected as a dependency of another package. We will simply trigger the host-clang build manually

$ make host-clang

In order to cross-compile the kernel, we have to modify the Linux’s package Makefile (linux/linux.mk) as suggested in the following patch.

Now it’s time to rebuild the kernel using Clang 🙂
Note: By default the qemu_aarch64_virt_defconfig uses a kernel 4.19.x, it’s recommended to use the latest kernel version (5.2.7).

$ make linux

The kernel build takes some time to complete, you can check the list of processes running on you build machine thanks to the htop command. You should notice some activity with clang-8 process.

When the build is finished (and successful), restart Qemu using the same command line as before.

The system should boot successfully and you can check the dmesg output to know the compiler used to build the kernel.

Conclusion:

This is our first test with a Linux kernel with Clang cross-compiler, for now it’s just a hack in Buildroot’s linux package.
Buildroot is not able to use Clang as a generic compiler for all user-space yet. Adding this feature requires discussion with the Buildroot community.

This support would also require to change some hard-coded references within the Buildroot’s package infrastructure. CMake and meson cross-compilation support, in particular, would need some work.

Buildroot probably needs a new toolchain-wrapper for Clang compiler to provide –sysroot path and other compiler options like it does for the GCC cross-toolchain.
Since the Clang compiler take a lot of time to build, it would be interesting to be able to reuse a prebuilt Clang compiler and import it in the toolchain-external package infrastructure. This would require that LLVM/Clang binaries be relocatable.
For now, only aarch64 kernel has been tested since it probably the most tested one with Clang [5]. It would be interesting to do further tests with other architectures like arm, x86, x86_64, mips, mips64, ppc, ppc64…

References:

[1] http://www.linuxembedded.fr/2018/07/llvmclang-integration-into-buildroot
[2] https://www.phoronix.com/scan.php?page=news_item&px=Google-2019-Clang-Kernel
[3] https://fosdem.org/2019/schedule/event/llvm_kernel/attachments/slides/3330/export/events/attachments/llvm_kernel/slides/3330/clang_linux_fosdem_19.pdf
[4] https://www.elinux.org/Buildroot:DeveloperDaysFOSDEM2018#LLVM.2FClang
[5] https://www.phoronix.com/scan.php?page=news_item&px=Clang-Kernel-2018