建置 LLVM 的發行版本¶
簡介¶
本文檔旨在為想要建置和封裝 LLVM 以及任何 LLVM 子專案工具組合以進行發行的人員而撰寫。本文檔涵蓋了 LLVM 建置系統的實用功能,以及關於封裝 LLVM 的最佳實務和一般資訊。
如果您是 CMake 的新手,您可能會發現 使用 CMake 建置 LLVM 或 CMake 入門 文件很有用。本文檔中涵蓋的某些內容是在 進階建置配置 文件中描述的建置的內部運作方式。
一般發行版本指南¶
在建置編譯器的發行版本時,一般建議執行編譯器的引導式建置。這表示使用您的主機工具鏈建置「階段 1」編譯器,然後使用「階段 1」編譯器建置「階段 2」編譯器。這樣做的目的是為了讓您發行的編譯器能夠受益於新編譯器提供的所有錯誤修復、效能最佳化和一般改進。
在決定如何建置您的發行版本時,您需要評估一些權衡。最重要的兩個是
發行版本的編譯時間與已建置編譯器的效能之間的權衡
發行版本的二進制大小與已建置編譯器的效能之間的權衡
最大化產生編譯器效能的指南是使用 LTO、PGO 和靜態連結所有內容。這將導致整體發行版本更大,並且需要更長的時間來產生,但它為編譯器提供了最多的最佳化機會。
最小化發行版本大小的指南是將 LLVM 和 Clang 程式庫動態連結到工具中,以減少程式碼重複。這將對產生的二進制檔案造成相當大的效能損失,因為它減少了最佳化機會,而且動態連結需要在進程啟動時解析符號,這對於 C++ 程式碼來說可能非常慢。
使用合理效能建置發行版本的最簡單範例,可以在位於 clang/cmake/caches/DistributionExample.cmake 的 DistributionExample CMake 快取檔案中找到。以下命令將執行並安裝發行版本建置
$ cmake -G Ninja -C <path to clang>/cmake/caches/DistributionExample.cmake <path to LLVM source>
$ ninja stage2-distribution
$ ninja stage2-install-distribution
install
和 install-distribution
之間的差異¶
一個細微但重要的注意事項是 install
和 install-distribution
目標之間的差異。install
目標預期安裝您建置配置為產生的 LLVM 的每個部分,除了 LLVM 測試工具。或者,建議用於建置發行版本的 install-distribution
目標,僅安裝在配置時由 LLVM_DISTRIBUTION_COMPONENTS 指定的 LLVM 的特定部分。
此外,預設情況下,install
目標將 LLVM 測試工具作為公開工具安裝。可以透過將 LLVM_INSTALL_TOOLCHAIN_ONLY 設定為 On
來很好地更改此設定。LLVM 工具旨在用於 LLVM 的開發和測試,並且僅應包含在支援 LLVM 開發的發行版本中。
當使用 LLVM_DISTRIBUTION_COMPONENTS 建置時,建置系統也會產生一個 distribution
目標,該目標建置列表中指定的所有組件。這是一個方便的建置目標,允許僅建置發行的部分,而無需建置所有已配置的目標。
多發行版本配置¶
上面描述的 install-distribution
目標用於建置單個發行版本。LLVM 的建置系統也支援建置多個發行版本,可用於例如,一個發行版本僅包含工具,另一個發行版本用於程式庫(以啟用開發)。這些是透過將 LLVM_DISTRIBUTIONS 變數設定為保存所有發行版本名稱的列表(通常以大寫字母開頭,例如「Development」),然後將 LLVM_<distribution>_DISTRIBUTION_COMPONENTS 變數設定為該發行版本的目標列表來配置的。對於每個發行版本,建置系統都會產生一個 install-${distribution}-distribution
目標,其中 ${distribution}
是小寫的發行版本名稱,用於安裝該發行版本。
每個發行版本都會建立自己的 CMake 導出,並且用於為專案安裝特定發行版本的 CMake 導出的目標命名為 ${project}-${distribution}-cmake-exports
,其中 ${project}
是小寫的專案名稱,${distribution}
是小寫的發行版本名稱,除非專案是 LLVM,在這種情況下,目標僅命名為 ${distribution}-cmake-exports
。這些目標需要明確包含在 LLVM_<distribution>_DISTRIBUTION_COMPONENTS 變數中,才能作為發行版本的一部分包含在內。
與單個發行版本設定不同,在建置多個發行版本時,LLVM_RUNTIME_DISTRIBUTION_COMPONENTS 中指定的任何組件都不會自動新增到任何發行版本。相反,您必須在某些 LLVM_<distribution>_DISTRIBUTION_COMPONENTS 列表中明確包含這些目標。
預設情況下,每個目標可以出現在多個發行版本中;目標將作為其出現的所有發行版本的一部分安裝,並且它將由其出現的最後一個發行版本導出(發行版本的順序是它們在 LLVM_DISTRIBUTIONS 中出現的順序)。我們還定義了一些總括目標(例如 llvm-libraries
以安裝所有 LLVM 程式庫);目標可以出現在與其總括不同的發行版本中,在這種情況下,目標將由其出現的發行版本導出(而不是其總括出現的發行版本導出)。如果您想要強制目標僅出現在一個發行版本中,並且總括發行版本與目標發行版本保持一致,請將 LLVM_STRICT_DISTRIBUTIONS 設定為 On
。
我們強烈建議查看 clang/cmake/caches/MultiDistributionExample.cmake
作為配置多個發行版本的範例。
僅限程式庫發行版本的特別注意事項¶
LLVM 最強大的功能之一是其程式庫優先的設計理念,以及您可以使用 LLVM 的不同部分組合各種工具的方式。即使在這種情況下,也不支援使用 BUILD_SHARED_LIBS。如果您想將 LLVM 作為共享程式庫發行以在工具中使用,建議的方法是使用 LLVM_BUILD_LLVM_DYLIB,您可以使用 LLVM_DYLIB_COMPONENTS 來配置哪些 LLVM 組件是 libLLVM 的一部分。注意:LLVM_BUILD_LLVM_DYLIB 在 Windows 上不可用。
最佳化 LLVM 的選項¶
我們的 CMake 建置系統支援四種主要的建置最佳化。在執行引導式建置時,除了將 CMAKE_BUILD_TYPE 設定為階段 1 編譯器的 Release
之外,執行任何其他操作都沒有好處。這是因為更密集的最佳化執行成本很高,並且階段 1 編譯器會被丟棄。描述的所有進一步選項都應設定在階段 2 編譯器上,可以使用 CMake 快取檔案,或透過在選項前加上 BOOTSTRAP_。
第一個也是最簡單使用的選項是編譯器最佳化級別,透過設定 CMAKE_BUILD_TYPE 選項。感興趣的主要值是 Release
或 RelWithDebInfo
。預設情況下,Release
選項使用 -O3
最佳化級別,而 RelWithDebInfo
使用 -O2
。如果您想要產生偵錯資訊並使用 -O3
,您可以覆寫 C 和 CXX 的 CMAKE_<LANG>_FLAGS_RELWITHDEBINFO 選項。DistributionExample.cmake 就是這樣做的。
另一個易於使用的選項是連結時最佳化。您可以將階段 2 建置中的 LLVM_ENABLE_LTO 選項設定為 Thin
或 Full
,以啟用使用 LTO 建置 LLVM。這些選項將顯著增加發行版本中二進制檔案的連結時間,但它將建立更快的二進制檔案。如果您的發行版本包含靜態封存,則不應使用此選項,因為封存內部的物件將是 LLVM 位元碼,這不具可移植性。
進階建置配置 文件描述了用於產生 LLVM 分析資訊以驅動設定檔引導最佳化的內建工具。樹狀結構內分析測試非常有限,並且產生設定檔需要大量時間,但它可以顯著提高產生二進制檔案的效能。
除了 PGO 分析之外,我們在樹狀結構內也有限度地支援產生連結器順序檔案。這些檔案為連結器提供最終二進制檔案佈局中函數的建議順序。這可以透過物理上將時間上彼此接近呼叫的函數分組來顯著加快 clang 的速度。目前的工具僅在具有 dtrace(1)
的 Darwin 系統上可用。值得注意的是,dtrace 是非確定性的,因此使用 dtrace 產生順序檔案也是非確定性的。
縮減大小的選項¶
警告
任何為縮減二進制檔案大小而採取的步驟都會以產生二進制檔案的執行時效能為代價。
縮減二進制檔案大小的最簡單且最不顯著的方法是將 CMAKE_BUILD_TYPE 變數設定為 MinSizeRel
,這會將編譯器最佳化級別設定為 -Os
,從而針對二進制檔案大小進行最佳化。這將對大小產生最少的效益,並且對效能的影響最小。
縮減二進制檔案大小的最有效方法是將 LLVM 動態連結到所有工具中。這透過減少基於 LLVM 的工具之間常見程式碼的重複來縮減程式碼大小。這可以透過將以下兩個 CMake 選項設定為 On
來完成:LLVM_BUILD_LLVM_DYLIB 和 LLVM_LINK_LLVM_DYLIB。
警告
永遠不應使用 BUILD_SHARED_LIBS CMake 選項來建置發行版本。(請參閱上面的警告以獲取更多說明。)。
相關的 CMake 選項¶
本節提供旨在幫助建構發行版本的 CMake 選項的文件。這不是一個詳盡的列表,並且 使用 CMake 建置 LLVM 頁面中記錄了許多其他選項。一些已記錄的關鍵選項包括:LLVM_TARGETS_TO_BUILD、LLVM_ENABLE_PROJECTS、LLVM_ENABLE_RUNTIMES、LLVM_BUILD_LLVM_DYLIB 和 LLVM_LINK_LLVM_DYLIB。
- LLVM_ENABLE_RUNTIMES:STRING
在建置包含 LLVM 執行時專案(即 libcxx、compiler-rt、libcxxabi、libunwind…)的發行版本時,重要的是使用剛建置的編譯器來建置這些專案。
- LLVM_DISTRIBUTION_COMPONENTS:STRING
此變數可以設定為要安裝的 LLVM 建置系統組件的分號分隔列表。所有基於 LLVM 的工具都是組件,大多數程式庫和執行時也是如此。組件名稱與建置系統目標的名稱相符。
- LLVM_DISTRIBUTIONS:STRING
此變數可以設定為發行版本的分號分隔列表。有關配置多個發行版本的詳細資訊以及其他 CMake 變數,請參閱上面的 多發行版本配置 章節。
- LLVM_RUNTIME_DISTRIBUTION_COMPONENTS:STRING
此變數可以設定為執行時程式庫組件的分號分隔列表。它與 LLVM_ENABLE_RUNTIMES 結合使用,以指定您想要包含在發行版本中的執行時程式庫的組件。與 LLVM_DISTRIBUTION_COMPONENTS 一樣,組件名稱與建置系統目標的名稱相符。
- LLVM_DYLIB_COMPONENTS:STRING
此變數可以設定為 LLVM 程式庫組件的分號分隔名稱。LLVM 程式庫組件是已移除 LLVM 字首的程式庫名稱(即 Support、Demangle…)、LLVM 目標名稱或特殊用途組件名稱。特殊用途組件名稱為
all
- 所有可用的 LLVM 組件程式庫Native
- 本機系統的 LLVM 目標AllTargetsAsmParsers
- 所有包含的目標 ASM 解析器程式庫AllTargetsDescs
- 所有包含的目標描述程式庫AllTargetsDisassemblers
- 所有包含的目標反組譯器程式庫AllTargetsInfos
- 所有包含的目標資訊程式庫
- LLVM_INSTALL_TOOLCHAIN_ONLY:BOOL
此選項預設為
Off
:當設定為On
時,它會從預設install
目標中移除許多 LLVM 開發和測試工具以及組件程式庫。不建議發行版本包含開發工具,因為許多 LLVM 工具僅用於開發和測試用途。