英语

使用 Clang/LLVM 构建 Linux

本文档介绍如何使用 Clang 和 LLVM 工具构建 Linux 内核。

关于

Linux 内核传统上一直使用 GNU 工具链(如 GCC 和 binutils)进行编译。目前的工作已经允许使用 ClangLLVM 工具作为可行的替代品。诸如 AndroidChromeOSOpenMandrivaChimera Linux 等发行版都使用 Clang 构建的内核。谷歌和 Meta 的数据中心机群也运行着使用 Clang 构建的内核。

LLVM 是一个工具链组件集合,以 C++ 对象的形式实现。Clang 是 LLVM 的前端,它支持 C 和内核所需的 GNU C 扩展,并且发音为“klang”,而不是“see-lang”。

使用 LLVM 构建

通过以下方式调用 make

make LLVM=1

为宿主机目标编译。 对于交叉编译

make LLVM=1 ARCH=arm64

LLVM= 参数

LLVM 有 GNU binutils 工具的替代品。 它们可以单独启用。 支持的 make 变量的完整列表

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \
  OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf \
  HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld

LLVM=1 展开为以上内容。

如果你的 LLVM 工具在 PATH 中不可用,你可以使用带有尾部斜杠的 LLVM 变量来提供它们的位置

make LLVM=/path/to/llvm/

这将使用 /path/to/llvm/clang/path/to/llvm/ld.lld 等。 也可以使用以下命令

PATH=/path/to/llvm:$PATH make LLVM=1

如果你的 LLVM 工具具有版本后缀,并且你希望使用该显式版本而不是像 LLVM=1 这样的不带后缀的可执行文件进行测试,则可以使用 LLVM 变量传递后缀

make LLVM=-14

这将使用 clang-14ld.lld-14 等。

为了支持树外路径和版本后缀的组合,我们推荐

PATH=/path/to/llvm/:$PATH make LLVM=-14

LLVM=0 与完全省略 LLVM 不同,它的行为将类似于 LLVM=1。 如果你只想使用某些 LLVM 工具,请使用它们各自的 make 变量。

如果通过不同的命令进行配置和构建,则每次调用 make 时都应设置与 LLVM= 相同的值。LLVM= 还应在运行最终将运行 make 的脚本时设置为环境变量。

交叉编译

单个 Clang 编译器二进制文件(以及相应的 LLVM 工具)通常会包含所有支持的后端,这可以帮助简化交叉编译,尤其是在使用 LLVM=1 时。 如果你只使用 LLVM 工具,则 CROSS_COMPILE 或目标三元组前缀将变得不必要。 例子

make LLVM=1 ARCH=arm64

作为混合 LLVM 和 GNU 工具的一个示例,对于像 ARCH=s390 这样尚不支持 ld.lldllvm-objcopy 的目标,你可以通过以下方式调用 make

make LLVM=1 ARCH=s390 LD=s390x-linux-gnu-ld.bfd \
  OBJCOPY=s390x-linux-gnu-objcopy

此示例将调用 s390x-linux-gnu-ld.bfd 作为链接器和 s390x-linux-gnu-objcopy,因此请确保它们在你的 $PATH 中可访问。

当未设置 LLVM=1 时,CROSS_COMPILE 不用于为 Clang 编译器二进制文件(或相应的 LLVM 工具)添加前缀,就像 GNU 工具的情况一样。

LLVM_IAS= 参数

Clang 可以汇编汇编代码。 你可以传递 LLVM_IAS=0 来禁用此行为,并让 Clang 调用相应的非集成汇编器。 例子

make LLVM=1 LLVM_IAS=0

当交叉编译并且使用 LLVM_IAS=0 时,需要 CROSS_COMPILE,以便为编译器设置 --prefix= 以查找相应的非集成汇编器(通常,在定位另一个架构时不希望使用系统汇编器)。 例子

make LLVM=1 ARCH=arm LLVM_IAS=0 CROSS_COMPILE=arm-linux-gnueabi-

Ccache

ccache 可以与 clang 一起使用,以改进后续的构建,(虽然应该在构建之间将 KBUILD_BUILD_TIMESTAMP 设置为确定性值,以避免 100% 的缓存未命中,有关详细信息,请参阅 Reproducible_builds

KBUILD_BUILD_TIMESTAMP='' make LLVM=1 CC="ccache clang"

支持的架构

LLVM 并非定位 Linux 支持的所有架构,并且仅仅因为 LLVM 支持某个目标,并不意味着内核可以在没有任何问题的情况下构建或工作。 以下是当前使用 CC=clangLLVM=1 工作的架构的一般摘要。 支持级别与 MAINTAINERS 文件中的“S”值相对应。 如果某个架构不存在,则意味着 LLVM 不定位它,或者存在已知问题。 使用 LLVM 的最新稳定版本甚至是开发树通常会产生最佳结果。 通常期望架构的 defconfig 工作良好,某些配置可能存在尚未发现的问题。 欢迎随时在下面的问题跟踪器中提交错误报告!

架构

支持级别

make 命令

arm

支持

LLVM=1

arm64

支持

LLVM=1

hexagon

维护

LLVM=1

loongarch

维护

LLVM=1

mips

维护

LLVM=1

powerpc

维护

LLVM=1

riscv

支持

LLVM=1

s390

维护

LLVM=1 (LLVM >= 18.1.0), CC=clang (LLVM < 18.1.0)

sparc(仅限 sparc64)

维护

CC=clang LLVM_IAS=0 (LLVM >= 20)

um(用户模式)

维护

LLVM=1

x86

支持

LLVM=1

获取帮助

获取 LLVM

我们在 kernel.org 上提供了 LLVM 的预构建稳定版本。 这些已使用用于构建 Linux 内核的配置文件数据进行了优化,这应相对于 LLVM 的其他发行版缩短内核构建时间。

以下链接可能有助于从源代码构建 LLVM 或通过发行版的软件包管理器获取它。