Clang:组装完整的工具链
组装完整的工具链
- 介绍
- 工具
- Clang前端
- 其他语言的语言前端
- 汇编器
- 链接器
- 运行时库
- 编译器运行时
- Atomics库
- Unwind库
- Sanitizer运行时
- C标准库
- C++ ABI 库
- C++ 标准库
Introduction
Clang只是C系列编程语言完整工具链中的一个组件。为了组装完整的工具链,需要额外的工具和运行时库。Clang主要是为了跟目标平台的现有工具和库进行互操作,LLVM项目为其中许多组件提供了替代方案。
本文档描述了完整工具链中的必需组件和可选组件、在哪里可以找到它们,以及每个选项的支持版本和限制。
Warning
本文档当前描述GCC兼容Clang驱动程序的类 POSIX 操作系统上的 Clang 配置。当使用与 MSVC 兼容的clang-cl驱动程序面向 Windows 时,某些细节会有所不同。
Tools
完整的C系列编程语言编译通常涉及以下工具,其中一些在某些编译中被省略:
- 预处理器(Preprocessor):执行 C 预处理器的操作:扩展
#includes
和#defines
。该-E
标志指示 Clang 在此步骤后停止。 - 解析(Parsing):它解析和分析源码并构建source-level中间表示(“AST”),根据输入生成 预编译头(PCH)、preamble或预编译模块文件(PCM)。
-precompile
标志指示 Clang 在此步骤后停止。当输入是头文件时,这是默认设置。 - IR 生成(IR generation):将source-level中间表示转换为特定的中间表示 (IR);对于 Clang,就是LLVM IR。该
-emit-llvm
标志指示 Clang 在此步骤后停止。如果与-S
参数结合,Clang 将生成文本 LLVM IR;否则,它将产生 LLVM IR bitcode。 - 编译器后端(Compiler backend):将中间表示转换为特定目标的汇编代码。该
-S
标志指示 Clang 在此步骤后停止。 - 汇编程序(Assembler):将特定目标的汇编代码转换为特定目标的机器代码目标文件。该
-c
标志指示 Clang 在此步骤后停止。 - 链接器(Linker):将一个或多个由编译器或汇编器生成的目标文件外加库链接为一个可执行文件(共享对象或可执行文件)。
Clang 提供了除链接器之外的所有部分。当多个步骤由同一个工具执行时,通常将这些步骤融合在一起以避免创建中间文件。
当将上述步骤之一的输出作为输入时,将跳过前面的步骤(例如,.s
文件输入指示组装和链接)。
可以使用-###
标志调用 Clang 驱动程序(此参数在大多数 shell 下需要转义)以查看它将为上述步骤运行哪些命令,而无需运行它们。-v(verbose)
除了运行命令之外,还将打印命令。
Clang前端
Clang 前端 (clang -cc1
) 用于编译 C 系列语言。
其他语言的语言前端
可以为 Clang 提供用非 C 系列语言编写的输入。在这种情况下,将使用外部工具来编译输入。目前支持的语言有:
- Ada (
-x ada, .ad[bs]
) - Fortran (
-x f95, .f, .f9[05], .for, .fpp
, 大小写不敏感) - Java (
-x java
)
在每种情况下,都将调用 GCC 来编译输入。
Assembler
Clang 可以使用 LLVM 的集成汇编器或外部系统特定工具(例如,GNU 操作系统上的 GNU 汇编器)从汇编中生成机器代码。默认情况下,Clang 在所有受支持的目标上使用 LLVM 的集成汇编器。如果您想改用系统汇编程序,请使用该 -fno-integrated-as选项。
Linker
可以将 Clang 配置为使用几个不同的链接器之一:
- GNU ld
- 古金
- LLVM 的lld
- MSVC 的 link.exe
lld 原生支持链接时优化,并在使用 gold 时通过链接器插件支持。
默认链接器因目标而异,并且可以通过 标志覆盖。-fuse-ld=<linker name>
运行时库
需要许多不同的运行时库来为 C 系列程序提供不同层次的支持。Clang 将隐式链接每个运行时库的适当实现,根据目标默认值选择或由–rtlib=and–stdlib= 标志显式选择。
隐式链接库的集合取决于语言模式。因此,您应该clang++在链接 C++ 程序时使用,以确保提供 C++ 运行时。
笔记
对于以下未描述的这些组件,可能存在其他实现方式。请让我们知道这些其他实现如何与 Clang 配合使用,以便可以将它们添加到此列表中!
编译器运行时
编译器运行时库提供了由编译器隐式调用的函数的定义,以支持底层硬件本身不支持的操作(例如,128 位整数乘法),并且操作的内联扩展被认为是不合适的。
默认运行时库是特定于目标的。对于 GCC 是主要编译器的目标,Clang 当前默认使用 libgcc_s。在大多数其他目标上,默认使用 compiler-rt。
编译器-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 使用带有–rtlib=libgcc标志的 libgcc_s。并非每个平台都支持此功能。
原子库
如果您的程序使用原子操作并且编译器无法将它们全部直接降低为机器指令(因为没有已知合适的机器指令或操作数不知道适当对齐),则调用运行时库__atomic_*会生成函数。此类程序需要包含这些原子函数的运行时库。
编译器-rt (LLVM)
compiler-rt 包含一个原子库的实现。
libatomic (GNU)
libgcc_s 不提供原子库的实现。相反, 在使用 libgcc_s 时,可以使用GCC 的 libatomic 库来提供这些。
笔记
使用 libgcc_s 时,Clang 当前不会自动链接到 libatomic。-latomic在使用非本地原子操作时,您可能需要手动添加以支持此配置(如果您看到引用__atomic_*函数的链接错误)。
展开库
unwind 库提供了一系列函数来实现 Itanium C++ ABI ( Level I )Unwind*的语言中立的堆栈展开部分。它是 C++ ABI 库的依赖项,有时是其他运行时的依赖项。
libunwind (LLVM)
LLVM 的 unwinder 库是 llvm-project git 存储库的一部分。要构建它,请传递-DLLVM_ENABLE_RUNTIMES=libunwind给 cmake 调用。
如果使用 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)。
消毒剂运行时
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 文档中的支持功能和 异常处理支持的 Level 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++ 的副本。
笔记
当静态链接 libstdc++ 时,Clang 当前不会自动链接到 libsupc++。-lsupc++在使用-static或时,您可能需要手动添加以支持此配置-static-libstdc++。
libcxxrt (PathScale)
这是 Itanium C++ ABI 规范的另一个实现。请参阅libcxxrt。
C++ 标准库
Clang 支持使用 LLVM 的 libc++ 或 GCC 的C++ 标准库的 libstdc++ 实现。
libc++ (LLVM)
libc++是 LLVM 对 C++ 标准库的实现,旨在成为从 C++11 开始的 C++ 标准的完整实现。
您可以指示 Clang 使用带有-stdlib=libc++标志的 libc++。
libstdc ++ (GNU)
libstdc++是 GCC 对 C++ 标准库的实现。Clang 支持 libstdc++ 4.8.3(2014-05-22 发布)及更高版本。从历史上看,Clang 为在 libstdc++ 中发现的问题实施了变通方法,并且随着固定的 libstdc++ 变得足够老,这些问题被删除。
您可以指示 Clang 使用带有-stdlib=libstdc++标志的 libstdc++。
参考
- 点赞
- 收藏
- 关注作者
评论(0)