[![Yoe Distro CI](https://github.com/kraj/meta-clang/workflows/Yoe%20Distro%20CI/badge.svg?branch=master)](https://github.com/kraj/meta-clang/actions/workflows/yoe.yml?query=workflow%3AYoe+branch%3Amaster)

# meta-clang (C/C++ frontend and LLVM compiler backend)

This layer provides [clang/llvm](http://clang.llvm.org/) as alternative to system
C/C++ compiler for OpenEmbedded/Yocto Project based distributions. This can cohabit
with GNU compiler and can be used for specific recipes or full system compiler.

# Getting Started

```shell
git clone git://github.com/openembedded/openembedded-core.git
cd openembedded-core
git clone git://github.com/openembedded/bitbake.git
git clone git://github.com/kraj/meta-clang.git

$ . ./oe-init-build-env
```
If using poky ( Yocto project reference Distribution )

```shell
git clone https://git.yoctoproject.org/git/poky
cd poky
git clone git://github.com/kraj/meta-clang.git

$ . ./oe-init-build-env
```

Add meta-clang overlay
```
bitbake-layers add-layer ../meta-clang
```

Check `conf/bblayers.conf` to see that meta-clang is added to layer mix e.g.

# Default Compiler

Note that by default gcc will remain the system compiler, however if you wish
clang to be the default compiler then set

```shell
TOOLCHAIN ?= "clang"
```

in `local.conf`, this would now switch default cross-compiler to be clang 
you can select clang per recipe too by writing bbappends for them containing

```shell
TOOLCHAIN = "clang"
```
also look at `conf/nonclangable.conf` for list of recipes which do not yet fully
build with clang.

# Default Compiler Runtime

Default is to use GNU runtime `RUNTIME = "gnu"` which consists of libgcc, libstdc++ to provide C/C++
runtime support. However it's possible to use LLVM runtime to replace it where
compile-rt, llvm libunwind, and libc++ are used to provide C/C++ runtime, while
GNU runtime works with both GCC and Clang, LLVM runtime is only tested with Clang
compiler, switching to use LLVM runtime is done via a config metadata knob

```shell
RUNTIME = "llvm"
```

RUNTIME variable influences individual runtime elements and can be set explicitly as well
e.g. `LIBCPLUSPLUS` `COMPILER_RT` and `UNWINDLIB`.

Please note that this will still use crt files from GNU compiler always, while llvm now
do provide crt files, they have not been yet integrated into the toolchain.

# Default C++ Standard Library Switch

Using RUNTIME variable will select which C++ runtime is used, however it can be overridden
if needed to by modifying `LIBCPLUSPLUS` variable, usually defaults used by `RUNTIME` are
best fit. e.g. below we select LLVM C++ as default C++ runtime.

```shell
LIBCPLUSPLUS = "-stdlib=libc++"
```

in `local.conf`.
You can select libstdc++ per package too by writing bbappends for them containing

```shell
LIBCPLUSPLUS:toolchain-clang:pn-<recipe> = "-stdlibc=libc++"
```
Defaults are chosen to be GNU for maximum compatibility with existing GNU systems. It's always
good to use single runtime on a system, mixing runtimes can cause complications during
compilation as well as runtime. However, it's up to distribution policies to decide which runtime
to use.

# Adding clang in generated SDK toolchain

Clang based cross compiler is not included into the generated SDK using `bitbake meta-toolchain` or
`bitbake -cpopulate_sdk <image>` if clang is expected to be part of SDK, add `CLANGSDK = "1"`
in `local.conf`

```shell
CLANGSDK = "1"
```

# Kernel build with clang
Newer kernels and Android kernels support clang compilation, and even support LTO, The following takes [rockchip](https://github.com/JeffyCN/meta-rockchip)'s kernel as an example to configure clang compilation. x86, arm and arm64 kernel supported full LLVM toolchain, other arch only support clang. more info https://docs.kernel.org/kbuild/llvm.html

- linux-rockchip_%bbappend
```shell
TOOLCHAIN:forcevariable = "clang"

DEPENDS:append:toolchain-clang = " clang-cross-${TARGET_ARCH}"
KERNEL_CC:toolchain-clang = "${CCACHE}clang ${HOST_CC_KERNEL_ARCH} -fuse-ld=lld ${DEBUG_PREFIX_MAP} -fdebug-prefix-map=${STAGING_KERNEL_DIR}=${KERNEL_SRC_PATH}"
KERNEL_LD:toolchain-clang = "${CCACHE}ld.lld"
KERNEL_AR:toolchain-clang = "${CCACHE}llvm-ar"
```
if you want use LLVM integrated assembler for some older kernel, newer vesion is enabled default.
```shell
do_compile:prepend:toolchain-clang() {
	export LLVM_IAS=1
}

do_compile_kernelmodules:prepend:toolchain-clang() {
	export LLVM_IAS=1
}
```
if you want enable LTO, append follow content.
```
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI:append:toolchain-clang = "\
	file://lto.cfg \
"
```

`CONFIG_LTO_CLANG`is need for some android based kernel, mainline kernel will do auto detect.

- lto.cfg
```
CONFIG_LTO_CLANG=y
CONFIG_LTO=y
CONFIG_LTO_CLANG_THIN=y
```


# Building

Below we build for qemuarm machine as an example

```shell
$ MACHINE=qemuarm bitbake core-image-full-cmdline
```
# Running

```shell
$ runqemu nographic
```

# Limitations

Few components do not build with clang, if you have a component to add to that list
simply add it to `conf/nonclangable.inc` e.g.

```shell
TOOLCHAIN:pn-<recipe> = "gcc"
```

and OE will start using gcc to cross compile that recipe.

If a component does not build with libc++, you can add it to `conf/nonclangable.inc` e.g.

```shell
CXX:remove:pn-<recipe>:toolchain-clang = " -stdlib=libc++ "
```

# compiler-rt failing in do_configure with custom TARGET_VENDOR

If your DISTRO sets own value of TARGET_VENDOR, then it's need to be added in
CLANG_EXTRA_OE_VENDORS, it should be done automatically, but if compiler-rt fails
like bellow, then check the end of work-shared/llvm-project-source-12.0.0-r0/temp/log.do_patch
is should have line like:
NOTE: Adding support following TARGET_VENDOR values: foo in
  /OE/build/oe-core/tmp-glibc/work-shared/llvm-project-source-12.0.0-r0/git/llvm/lib/Support/Triple.cpp and
  /OE/build/oe-core/tmp-glibc/work-shared/llvm-project-source-12.0.0-r0/git/clang/lib/Driver/ToolChains/Gnu.cpp
and check these files if //CLANG_EXTRA_OE_VENDORS* strings were replaced correctly.
Read add_more_target_vendors function in recipes-devtools/clang/llvm-project-source.inc for more details.

http://errors.yoctoproject.org/Errors/Details/574365/
```shell
-- Found assembler: TOPDIR/tmp-glibc/work/core2-64-foo-linux/compiler-rt/12.0.0-r0/recipe-sysroot-native/usr/bin/x86_64-foo-linux/x86_64-foo-linux-clang
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: TOPDIR/tmp-glibc/work/core2-64-foo-linux/compiler-rt/12.0.0-r0/recipe-sysroot-native/usr/bin/x86_64-foo-linux/x86_64-foo-linux-clang
-- Check for working C compiler: TOPDIR/tmp-glibc/work/core2-64-foo-linux/compiler-rt/12.0.0-r0/recipe-sysroot-native/usr/bin/x86_64-foo-linux/x86_64-foo-linux-clang - broken
CMake Error at TOPDIR/tmp-glibc/work/core2-64-foo-linux/compiler-rt/12.0.0-r0/recipe-sysroot-native/usr/share/cmake-3.19/Modules/CMakeTestCCompiler.cmake:66 (message):
  The C compiler

    "TOPDIR/tmp-glibc/work/core2-64-foo-linux/compiler-rt/12.0.0-r0/recipe-sysroot-native/usr/bin/x86_64-foo-linux/x86_64-foo-linux-clang"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: TOPDIR/tmp-glibc/work/core2-64-foo-linux/compiler-rt/12.0.0-r0/build/CMakeFiles/CMakeTmp

    Run Build Command(s):ninja cmTC_928f4 && [1/2] Building C object CMakeFiles/cmTC_928f4.dir/testCCompiler.c.o
    [2/2] Linking C executable cmTC_928f4
```

# Dependencies

```shell
URI: git://github.com/openembedded/openembedded-core.git
branch: master
revision: HEAD

URI: git://github.com/openembedded/bitbake.git
branch: master
revision: HEAD
```

# Contributing

You are encouraged to follow Github Pull request workflow
to share changes and following commit message guidelines are recommended: [OE patch guidelines](https://www.openembedded.org/wiki/Commit_Patch_Message_Guidelines).

Layer Maintainer: [Khem Raj](<mailto:raj.khem@gmail.com>)
