组装完整的工具链¶
简介¶
Clang 只是 C 家族编程语言完整工具链中的一环。为了组装完整的工具链,需要额外的工具和运行时库。Clang 被设计为与目标平台上现有的工具和库互操作,LLVM 项目为许多这些组件提供了替代方案。
本文档描述了完整工具链中必需的和可选的组件,以及它们在哪里可以找到,以及每个选项的受支持版本和限制。
警告
本文档目前描述了在具有 GCC 兼容 clang
驱动程序的类 POSIX 操作系统上的 Clang 配置。当使用 MSVC 兼容的 clang-cl
驱动程序将目标设为 Windows 时,某些细节会有所不同。
工具¶
C 家族编程语言的完整编译通常涉及以下工具管道,其中一些工具在某些编译中被省略
预处理器:执行 C 预处理器的操作:扩展 #include 和 #define。
-E
标志指示 Clang 在此步骤后停止。解析:解析和语义分析源语言并构建源级中间表示(“AST”),生成 预编译头文件 (PCH),序言,或 预编译模块文件 (PCM),具体取决于输入。
-precompile
标志指示 Clang 在此步骤后停止。当输入是头文件时,这是默认行为。IR 生成:将源级中间表示转换为优化器特定的中间表示 (IR);对于 Clang,这是 LLVM IR。
-emit-llvm
标志指示 Clang 在此步骤后停止。如果与-S
结合使用,Clang 将生成文本 LLVM IR;否则,它将生成 LLVM IR 字节码。编译器后端:将中间表示转换为特定于目标的汇编代码。
-S
标志指示 Clang 在此步骤后停止。汇编器:将特定于目标的汇编代码转换为特定于目标的机器代码目标文件。
-c
标志指示 Clang 在此步骤后停止。链接器:将多个目标文件组合成一个映像(共享对象或可执行文件)。
Clang 提供了除链接器之外的所有这些部分。当多个步骤由同一个工具执行时,这些步骤通常会融合在一起,以避免创建中间文件。
当给定上述步骤之一的输出作为输入时,将跳过较早的步骤(例如,.s
文件输入将被汇编和链接)。
Clang 驱动程序可以与 -###
标志一起调用(此参数需要在大多数 shell 下转义),以查看它将为上述步骤运行哪些命令,而不实际运行它们。 -v
(详细)标志将打印命令,并运行它们。
Clang 前端¶
Clang 前端 (clang -cc1
) 用于编译 C 家族语言。前端的命令行界面被认为是实现细节,故意没有外部文档,并且可能会在不通知的情况下发生更改。
其他语言的语言前端¶
Clang 可以使用以非 C 家族语言编写的输入。在这种情况下,将使用外部工具来编译输入。当前支持的语言是
Ada (
-x ada
,.ad[bs]
)Fortran (
-x f95
,.f
,.f9[05]
,.for
,.fpp
,不区分大小写)Java (
-x java
)
在每种情况下,都会调用 GCC 来编译输入。
汇编器¶
Clang 可以使用 LLVM 的集成汇编器或外部特定于系统的工具(例如,GNU 操作系统上的 GNU 汇编器)从汇编代码生成机器代码。默认情况下,Clang 在所有支持它的目标上使用 LLVM 的集成汇编器。如果您希望改用系统汇编器,请使用 -fno-integrated-as
选项。
链接器¶
Clang 可以配置为使用以下几种不同的链接器
GNU ld
GNU gold
LLVM 的 lld
MSVC 的 link.exe
链接时优化由 lld 原生支持,并且在使用 gold 时通过 链接器插件 支持。
默认链接器因目标而异,可以通过 -fuse-ld=<linker name>
标志覆盖。
运行时库¶
需要许多不同的运行时库来为 C 家族程序提供不同级别的支持。Clang 将隐式链接每个运行时库的适当实现,该实现是根据目标默认值选择或通过 --rtlib=
和 --stdlib=
标志显式选择。
隐式链接的库集取决于语言模式。因此,在链接 C++ 程序时,应该使用 clang++
,以确保提供 C++ 运行时。
注意
这些组件可能存在下面没有描述的其他实现。请告知我们这些其他实现与 Clang 的配合程度,以便将其添加到此列表中!
编译器运行时¶
编译器运行时库提供了由编译器隐式调用的函数的定义,以支持底层硬件不支持的操作(例如,128 位整数乘法),以及操作的内联扩展被认为不适合的情况。
默认运行时库是特定于目标的。对于 GCC 是主要编译器的目标,Clang 目前默认使用 libgcc_s。在大多数其他目标上,默认使用 compiler-rt。
compiler-rt (LLVM)¶
LLVM 的编译器运行时库 提供了一套完整的运行时库函数,包含 Clang 将隐式调用的所有函数,位于 libclang_rt.builtins.<arch>.a
中。
您可以指示 Clang 使用 compiler-rt,方法是使用 --rtlib=compiler-rt
标志。这并非在所有平台上都支持。
如果使用 libc++ 和/或 libc++abi,您可能需要将它们配置为使用 compiler-rt 而不是 libgcc_s,方法是将 -DLIBCXX_USE_COMPILER_RT=YES
和/或 -DLIBCXXABI_USE_COMPILER_RT=YES
传递给 cmake
。否则,您最终可能会将两个运行时库链接到您的程序中(这通常是无害的,但浪费了资源)。
libgcc_s (GNU)¶
GCC 的运行时库 可以用作 compiler-rt 的替代品。但是,它缺少 LLVM 可能发出对它的引用的几个函数,尤其是在使用 Clang 的 __builtin_*_overflow
系列内联函数时。
您可以指示 Clang 使用 libgcc_s,方法是使用 --rtlib=libgcc
标志。这并非在所有平台上都支持。
原子库¶
如果您的程序使用了原子操作,并且编译器无法将所有操作直接降低到机器指令(因为要么没有已知的合适的机器指令,要么操作数已知不适合对齐),则将生成对运行时库 __atomic_*
函数的调用。这样的程序需要包含这些原子函数的运行时库。
compiler-rt (LLVM)¶
compiler-rt 包含原子库的实现。
libatomic (GNU)¶
libgcc_s 没有提供原子库的实现。相反,可以使用 GCC 的 libatomic 库 在使用 libgcc_s 时提供这些库。
注意
Clang 目前在使用 libgcc_s 时不会自动链接到 libatomic。您可能需要手动添加 -latomic
来支持在使用非本地原子操作时(如果您看到引用 __atomic_*
函数的链接错误)此配置。
展开库¶
展开库提供了一系列 _Unwind_*
函数,实现了 Itanium C++ ABI 的语言中立堆栈展开部分 (一级)。它是 C++ ABI 库的依赖项,有时也是其他运行时的依赖项。
libunwind (LLVM)¶
LLVM 的解旋器库是 llvm-project git 仓库的一部分。要构建它,请在 cmake 调用中传递 -DLLVM_ENABLE_RUNTIMES=libunwind
。
如果使用 libc++abi,您可能需要将其配置为使用 libunwind 而不是 libgcc_s,方法是将 -DLIBCXXABI_USE_LLVM_UNWINDER=YES
传递给 cmake
。如果 libc++abi 被配置为使用 libunwind 的某个版本,那么该库将被隐式链接到链接到 libc++abi 的二进制文件中。
libgcc_s (GNU)¶
libgcc_s 具有集成的解旋器,不需要提供外部解旋器库。
libunwind (nongnu.org)¶
这是 libunwind 规范的另一个实现。请参阅 libunwind (nongnu.org)。
libunwind (PathScale)¶
这是 libunwind 规范的另一个实现。请参阅 libunwind (pathscale)。
Sanitizer 运行时¶
Clang 的 sanitizers (-fsanitize=...
) 添加的检测会隐式地调用运行时库,以维护有关程序执行的辅助状态,并在检测到问题时发出诊断消息。
这些运行时库的唯一支持的实现由 LLVM 的 compiler-rt 提供,并且该库的相关部分 (libclang_rt.<sanitizer>.<arch>.a
) 在使用 -fsanitize=...
标志链接时将被隐式链接。
C 标准库¶
Clang 支持各种各样的 C 标准库 实现。
C++ ABI 库¶
C++ ABI 库提供了 Itanium C++ ABI 库部分的实现,涵盖了 Itanium C++ ABI 主要文档中的支持功能 和 异常处理支持的 II 级。当编译 C++ 代码时,Clang 会隐式地生成对该库中函数和对象的引用。
虽然可以使用 libstdc++ 链接 C++ 代码,并将使用 libc++ 的代码链接到同一个程序中(只要您不尝试跨越边界传递 C++ 标准库对象),但通常不可能在一个程序中拥有多个 C++ ABI 库。
Clang 使用的 C++ ABI 库版本将是所选 C++ 标准库链接到的版本。有几种实现可用
libc++abi (LLVM)¶
libc++abi 是 LLVM 对此规范的实现。
libsupc++ (GNU)¶
libsupc++ 是 GCC 对此规范的实现。但是,该库仅在静态链接 libstdc++ 时使用。libstdc++ 的动态库版本包含 libsupc++ 的副本。
注意
Clang 目前不会在静态链接 libstdc++ 时自动链接到 libsupc++。在使用 -static
或 -static-libstdc++
时,您可能需要手动添加 -lsupc++
来支持此配置。
libcxxrt (PathScale)¶
这是 Itanium C++ ABI 规范的另一个实现。请参阅 libcxxrt。
C++ 标准库¶
Clang 支持使用 LLVM 的 libc++ 或 GCC 的 libstdc++ 实现的 C++ 标准库。
libc++ (LLVM)¶
libc++ 是 LLVM 对 C++ 标准库的实现,旨在成为从 C++11 开始的 C++ 标准的完整实现。
您可以使用 -stdlib=libc++
标志指示 Clang 使用 libc++。
libstdc++ (GNU)¶
libstdc++ 是 GCC 对 C++ 标准库的实现。Clang 支持 libstdc++ 4.8.3(2014 年 5 月 22 日发布)及更高版本。历史上,Clang 为在 libstdc++ 中发现的问题实现了变通方法,随着 libstdc++ 的修复版本变得足够旧,这些变通方法将被删除。
您可以使用 -stdlib=libstdc++
标志指示 Clang 使用 libstdc++。