英语

使用 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= 设置相同的值。 当运行最终将运行 make 的脚本时,还应将 LLVM= 设置为环境变量。

交叉编译

单个 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 一起使用以改进后续构建,(虽然为了避免 100% 缓存未命中,应将 KBUILD_BUILD_TIMESTAMP 设置为构建之间的确定性值,有关更多信息,请参见 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 或通过发行版的软件包管理器获取它。