裝配一個完整的工具鍊
-
-
- 1. 介紹
- 2. 工具
-
-
- 2.1 Clang 前端
- 2.2 其他語言的語言前端
- 2.3 彙編器
- 2.4 連結器
-
- 3. 運作時庫
-
-
- 3.1 編譯器運作時(Compiler runtime)
- 3.2 原子庫(Atomics library)
- 3.3 Unwind 庫
- 3.4 Sanitizer 運作時
- 3.5 C 标準庫
- 3.6 C++ ABI 庫
- 3.7 C++ 标準庫
-
-
本文為譯文,點選 此處檢視原文。
1. 介紹
Clang 隻是 C 家族程式設計語言完整工具鍊(tool chain)中的一個元件。為了裝配一個完整的工具鍊,需要額外的工具和運作時庫。Clang 被設計為與用于其目标平台的現有工具和庫進行互動操作,并且 LLVM 項目為許多這些元件提供了替代方案。
本文檔描述了完整工具鍊中所需的和可選的元件,在哪裡可以找到它們,以及每個選項支援的版本和限制。
警告
本文檔目前描述了使用 GCC-compatible 的
驅動程式在類 POSIX 作業系統上的 Clang 配置。當使用 MSVC-compatible 的
clang
驅動程式在目标系統Windows上時,有些細節是不同的。
clang-cl
2. 工具
C 家族程式設計語言的完整編譯通常涉及以下工具管道,其中一些在某些編譯中被省略:
-
:執行 C 預處理器的操作:展開預處理器(Preprocessor)
和#include
。#defines
标志訓示 Clang 在此步驟之後停止。-E
-
:根據輸入,解析和語義分析源語言,并建構一個源代碼級中間表示(“AST”),生成預編譯頭檔案(precompiled header,PCH)、序言(preamble)或預編譯子產品檔案(precompiled module file,PCM)。解析(Parsing)
标志訓示 Clang 在此步驟之後停止。當輸入是一個頭檔案時,這是預設值。-precompile
-
:将源代碼級中間表示轉換為一個特定于優化器(optimizer)的中間表示(IR);對于 Clang,這是LLVM IR。IR生成(IR generation)
标志訓示 Clang 在此步驟之後停止。如果與-emit-llvm
結合,Clang 将産生文本形式的 LLVM IR;否則,将産生 LLVM IR 位元組碼。-S
-
:這将中間表示轉換為特定于目标的彙編代碼。編譯器後端(Compiler backend)
标志訓示 Clang 在此步驟之後停止。-S
-
:将特定于目标的彙編代碼轉換為特定于目标的機器碼目标檔案。彙編器(Assembler)
标志訓示 Clang 在此步驟之後停止。-c
-
:它将多個目标檔案組合成一個映像(一個共享對象或一個可執行檔案)。連結器(Linker)
Clang提供了除連結器之外的所有這些部分。當同一工具執行多個步驟時,通常将這些步驟合并在一起,以避免建立中間檔案。
當給定上述步驟之一的輸出作為輸入時,将跳過前面的步驟(例如,輸入一個
.s
檔案将會進行彙編和連結)。
可以使用
-###
标記(在大多數 shell 中需要轉義這個參數)調用 Clang 驅動程式,以檢視将為上述步驟運作哪些指令,在不運作這些指令的情況下。除了運作指令外,
-v
(verbose)标志還将列印指令。
2.1 Clang 前端
Clang 前端(
clang -cc1
)用于編譯 C 家族語言。前端的指令行接口被認為是一個實作細節,故意沒有外部文檔,并且可以在不注意的情況下進行更改。
2.2 其他語言的語言前端
Clang可以提供用非 C 家族語言編寫的輸入。在這種情況下,将使用一個外部工具編譯輸入。目前支援的語言有:
- Ada (
、-x ada
).ad[bs]
- Fortran (
、-x f95
、.f
、.f9[05]
、.for
、不區分大小寫).fpp
- Java (
)-x java
在每種情況下,都會調用 GCC 來編譯輸入。
2.3 彙編器
Clang 既可以使用 LLVM 的內建彙編器,也可以使用外部特定于系統的工具(例如,GNU 作業系統上的 GNU 彙編器),以從彙編代碼生成機器碼。預設情況下,Clang 在支援 LLVM 的所有目标上使用 LLVM 的內建彙編器。如果想使用系統彙編器,請使用
-fno-integrated-as
選項。
2.4 連結器
Clang可以配置為使用幾個不同的連結器其中一個:
-
GNU ld
-
GNU gold
-
LLVM lld
-
MSVC link.exe
lld 原生支援連結時優化,使用 gold 時通過一個連結器插件以支援連結時優化。
預設連結器在不同的目标之間是不同的,可以通過
-fuse-ld=<linker name>
标志覆寫它。
3. 運作時庫
需要許多不同的運作時庫來為 C 家族程式提供不同的支援層。Clang 将隐式地連結每個運作時庫的一個适當實作,這些實作是根據目标預設值選擇的,或者由
--rtlib=
和
--stdlib=
标志顯式地選擇。
隐式連結庫的集合依賴于語言模式。是以,在連結 C++ 程式時應該使用
clang++
,以確定提供了 C++ 運作時。
注意
對于這些元件,可能存在下面沒有描述的其他實作。請讓我們知道這些其他實作與 Clang 的工作效果如何,以便将它們添加到這個清單中!
3.1 編譯器運作時(Compiler runtime)
編譯器運作時庫提供編譯器隐式調用的函數的定義,以支援底層硬體不支援的操作(例如,128位整數乘法),以及認為操作的内聯展開不合适的地方。
預設的運作時庫是特定于目标的。對于 GCC 是主要編譯器的目标,Clang 目前預設使用
libgcc_s
。在大多數其他目标上,預設情況下使用
compiler-rt
。
-
LLVM的編譯器運作時庫提供了一組完整的運作時庫函數,其中包含 Clang 将隐式調用的所有函數,在compiler-rt (LLVM)
libclang_rt.builtins.<arch>.a
中。
您可以訓示 Clang 使用帶有
标志的--rtlib=compiler-rt
compiler-rt
,并非所有平台都支援此功能。
如果使用
和/或libc++
,您可能需要将它們配置為使用libc++abi
而不是compiler-rt
,方法是将libgcc_s
和/或-DLIBCXX_USE_COMPILER_RT=YES
傳遞給-DLIBCXXABI_USE_COMPILER_RT=YES
。否則,您可能會将兩個運作時庫連結到您的程式中(這通常是無害的,但很浪費)。cmake
-
GCC的運作時庫可以用來代替libgcc_s (GNU)
。但是,它缺少幾個LLVM可能發出引用的函數,特别是在使用Clang的内置函數家族的compiler-rt
__builtin_*_overflow
時。
您可以訓示 Clang 使用帶有
标志的--rtlib=libgcc
,并非所有平台都支援此功能。libgcc_s
3.2 原子庫(Atomics library)
如果您的程式使用了原子操作,編譯器無法直接降低他們到機器指令(因為沒有合适的機器指令或操作數不知道适當對齊),将會生成對一個運作時庫
__atomic_*
函數的一次調用。這些程式需要一個包含這些原子函數的運作時庫。
-
compiler-rt 包含一個原子庫的實作。compiler-rt (LLVM)
-
libgcc_s 不提供原子庫的實作。相反,GCC 的 libatomic library 可以在使用 libgcc_s 時提供這些原子庫。libatomic (GNU)
注意
當使用
時,Clang目前不會自動連結到
libgcc_s
。在使用非本機原子操作時(如果您看到引用了
libatomic
函數的連結錯誤),可能需要手動添加
__atomic_*
來支援此配置。
-latomic
3.3 Unwind 庫
unwind
庫提供了一系列
_Unwind_*
函數,實作了
Itanium C++ ABI
(第I級)的語言無關的堆棧unwind部分,它是 C++ ABI 庫的依賴項,有時是其他運作時的依賴項。
-
LLVM 的 unwinder 庫是 llvm-project git 存儲庫的一部分。要建構它,請将libunwind (LLVM)
-DLLVM_ENABLE_PROJECTS=libunwind
傳遞給 cmake 調用。
如果使用
,您可能需要将其配置為使用libc++abi
而不是libunwind
,方法是将libgcc_s
傳遞給 cmake。如果将-DLIBCXXABI_USE_LLVM_UNWINDER=YES
配置為使用某個版本的libc++abi
,則該庫将會被隐式連結到二進制檔案,這些二進制檔案連結到libc++abi。libunwind
-
libgcc_s 有一個內建的 unwinder,不需要提供外部的 unwind 庫。libgcc_s (GNU)
-
這是 libunwind 規範的另一個實作。請參閱 libunwind (nongnu.org)。libunwind (nongnu.org)
-
這是 libunwind 規範的另一個實作。請參閱 libunwind (pathscale)。libunwind (PathScale)
3.4 Sanitizer 運作時
Clang 的
sanitizers
(-fsanitize=…)添加的工具隐式地調用一個運作時庫,以便維護程式執行的側狀态,并在檢測到問題時發出診斷消息。
這些運作時的唯一支援實作由 LLVM 的
compiler-rt
提供,以及這個庫(
libclang_rt.<sanitizer>.<arch>.a
) 的相關部分将會被連結當使用一個
-fsanitize=...
标志連結時。
3.5 C 标準庫
Clang 支援多種 C 标準庫實作。
3.6 C++ ABI 庫
C++ ABI 庫
提供了
Itanium C++ ABI
庫部分的實作,包括 main 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)
是 GCC 對該規範的實作。但是,隻有在靜态連結libsupc++
時才使用這個庫。libstdc++
的動态庫版本包含libstdc++
的一個副本。libsupc++
注意
當靜态連結
時,Clang目前不會自動連結到libstdc++
。在使用libatomic
或-static
時,可能需要手動添加-static-libstdc++
來支援此配置。-lsupc++
-
這是 Itanium C++ ABI 規範的另一個實作。請參閱 libcxxrt。libcxxrt (PathScale)
3.7 C++ 标準庫
Clang 支援使用 LLVM 的
libc++
或 GCC 的
libstdc++
C++标準庫實作。
-
libc++ (LLVM)
libc++ 是 LLVM 的 C++ 标準庫實作,旨在從 C++ 11 開始成為全面的 C++ 标準實作。
您可以訓示 Clang 用
标志來使用 libc++。-stdlib=libc++
-
libstdc++ (GNU)
libstdc++ 是 GCC 的 C++ 标準庫實作。Clang 支援各種版本的 libstdc++,從4.2版本開始,并将隐式地處理舊版本libstdc++中的一些bug。
您可以訓示 Clang 用
标志來使用 libstdc++。-stdlib=libstdc++