使用 CMake 建置 LLVM

簡介

CMake 是一個跨平台的建置產生器工具。CMake 不會建置專案,它會產生您的建置工具(GNU make、Visual Studio 等)建置 LLVM 所需的檔案。

如果您是新的貢獻者,請從LLVM 系統入門頁面開始。本頁面是為從傳統 configure/make 系統轉移過來的現有貢獻者所設計。

如果您真的急於取得可運作的 LLVM 建置版本,請前往快速開始章節。如果您是 CMake 新手,請從基本 CMake 用法開始,然後在您了解自己在做什麼之後,再回到快速開始章節。選項與變數章節是自訂建置的參考。如果您已經有 CMake 經驗,這是建議的起點。

本頁面是為 LLVM CMake 建置的使用者所設計。如果您正在尋找有關修改 LLVM CMake 建置系統的資訊,您可能需要查看CMake Primer頁面。它包含了 CMake 語言的基本概述。

快速開始

我們在此使用命令列、非互動式的 CMake 介面。

  1. 下載並安裝 CMake。最低要求版本為 3.20.0。

  2. 開啟 shell。您的開發工具必須可以透過 PATH 環境變數從此 shell 存取。

  3. 建立建置目錄。不支援在原始碼目錄中建置 LLVM。cd 到此目錄

    $ mkdir mybuilddir
    $ cd mybuilddir
    
  4. 在 shell 中執行此命令,將 path/to/llvm/source/root 替換為您的 LLVM 原始碼樹根目錄的路徑

    $ cmake path/to/llvm/source/root
    

    CMake 將偵測您的開發環境、執行一系列測試,並產生建置 LLVM 所需的檔案。CMake 將對所有建置參數使用預設值。請參閱選項與變數章節,以取得您可以修改的建置參數列表。

    如果 CMake 無法偵測到您的工具組,或認為環境不夠健全,則可能會失敗。在這種情況下,請確保您打算使用的工具組是唯一可以從 shell 存取的工具組,並且 shell 本身是您開發環境的正確 shell。例如,如果您透過 PATH 環境變數可以存取 POSIX shell,CMake 將拒絕建置 MinGW makefile。您可以強制 CMake 使用給定的建置工具;有關說明,請參閱下方的用法章節。您可能也希望控制 LLVM 啟用的目標,或建置哪些 LLVM 組件;請參閱下方的常用 LLVM 相關變數

  5. 在 CMake 完成執行後,繼續使用 IDE 專案檔案,或從建置目錄開始建置

    $ cmake --build .
    

    --build 選項告知 cmake 呼叫底層的建置工具(makeninjaxcodebuildmsbuild 等)

    底層的建置工具當然可以直接呼叫,但 --build 選項是可移植的。

  6. 在 LLVM 完成建置後,從建置目錄安裝它

    $ cmake --build . --target install
    

    除了 --build 選項外,具有 install 參數的 --target 選項告知 cmake 建置 install 目標。

    可以透過呼叫在建置目錄中產生的 cmake_install.cmake 腳本,在安裝時設定不同的安裝前綴

    $ cmake -DCMAKE_INSTALL_PREFIX=/tmp/llvm -P cmake_install.cmake
    

基本 CMake 用法

本節說明 CMake 的基本方面,您在日常使用中可能需要這些方面。

CMake 隨附了廣泛的文件,以 html 檔案的形式,以及透過 cmake 可執行檔本身存取的線上說明。執行 cmake --help 以取得更多說明選項。

CMake 允許您指定建置工具(例如,GNU make、Visual Studio 或 Xcode)。如果在命令列上未指定,CMake 會嘗試根據您的環境猜測要使用的建置工具。一旦它識別出您的建置工具,CMake 就會使用對應的產生器來建立您的建置工具的檔案(例如,Makefile 或 Visual Studio 或 Xcode 專案檔案)。您可以使用命令列選項 -G "產生器名稱" 明確指定產生器。若要查看系統上可用的產生器列表,請執行

$ cmake --help

cmake --help

這將在說明文字的末尾列出產生器名稱。

$ cmake -G "Visual Studio 12" path/to/llvm/source/root

產生器的名稱區分大小寫,並且可能包含空格。因此,您應該完全按照 cmake --help 輸出中列出的名稱輸入它們,並加上引號。例如,若要專門為 Visual Studio 12 產生專案檔案,您可以執行

cmake -G "Visual Studio 12" path/to/llvm/source

對於給定的開發平台,可能有多個適當的產生器。如果您使用 Visual Studio,“NMake Makefiles” 是您可以使用的產生器,用於使用 NMake 進行建置。依預設,CMake 會選擇您的開發環境支援的最特定的產生器。如果您想要替代產生器,您必須使用 -G 選項告知 CMake。

$ cmake -DVARIABLE=value path/to/llvm/source

選項與變數

$ cmake -UVARIABLE path/to/llvm/source

變數自訂建置的產生方式。選項是布林變數,可能的值為 ON/OFF。選項和變數在 CMake 命令列上定義,如下所示

cmake -DVARIABLE_NAME=value path/to/llvm/source

$ cmake -DVARIABLE:TYPE=value path/to/llvm/source

您可以在初始 CMake 呼叫後設定變數以變更其值。您也可以取消定義變數

cmake -UVARIABLE_NAME path/to/llvm/build

變數儲存在 CMake 快取中。這是一個名為 CMakeCache.txt 的檔案,儲存在您的建置目錄的根目錄中,由 cmake 產生。不建議您自行編輯它。

變數在 CMake 快取中以及本文稍後的部分中列出,變數名稱和類型以冒號分隔。您也可以在 CMake 命令列上指定變數和類型

cmake -DVARIABLE_NAME:TYPE=value path/to/llvm/source

常用 CMake 變數

以下是一些常用的 CMake 變數,以及簡要說明。如需完整文件,請查閱 CMake 手冊,或執行 cmake --help-variable VARIABLE_NAME。請參閱下方的常用 LLVM 相關變數,以取得有關常用變數的資訊,這些變數控制 LLVM 的功能和啟用的子專案。

CMAKE_BUILD_TYPE:STRING

這會設定 makeninja 建置的最佳化層級。

可能的值

建置類型

最佳化

偵錯資訊

偵錯資訊

斷言

最適合用於

Release

為了速度

為了速度

LLVM 和 Clang 的使用者

最佳化

為了速度

偵錯資訊

Debug

偵錯資訊

偵錯資訊

LLVM 的開發人員

  • RelWithDebInfo

  • 也需要偵錯的使用者

  • MinSizeRel

為了大小

當磁碟空間很重要時

最佳化使 LLVM/Clang 執行更快,但可能會阻礙逐步偵錯。

具有偵錯資訊的建置版本可能會使用大量 RAM 和磁碟空間,並且執行速度通常較慢。您可以透過使用 lld 來改善 RAM 使用量,請參閱LLVM_USE_LINKER 選項。

斷言是內部檢查,可協助您找到錯誤。它們通常會在啟用時減慢 LLVM 和 Clang 的速度,但在開發期間可能很有用。您可以手動設定 LLVM_ENABLE_ASSERTIONS 以覆寫 CMAKE_BUILD_TYPE 的預設值。

如果您使用 IDE(例如 Visual Studio 或 Xcode),您應該使用 IDE 設定來設定建置類型。

注意:在 Windows 上(使用 MSVC 或 clang-cl 建置),CMake 的 RelWithDebInfo 設定不會啟用與 Release 相同的最佳化。使用 Release 建置類型並設定 LLVM_ENABLE_PDB 可能是一個更好的選擇。

CMAKE_INSTALL_PREFIX:PATH

建置 llvm 工具鏈可能會使用大量資源,尤其是在連結時。當您使用 Ninja 產生器時,這些選項可讓您限制平行處理。例如,為了避免 OOM 或進入交換空間,在 32GB 機器上,允許每個 15GB 可用 RAM 僅執行一個連結作業,請指定 -G Ninja -DLLVM_PARALLEL_LINK_JOBS=2

LLVM_TARGETS_TO_BUILD:STRING

控制啟用哪些目標。例如,您可能只需要啟用您的原生目標,例如 -DLLVM_TARGETS_TO_BUILD=X86

LLVM_USE_LINKER:STRING

覆寫系統的預設連結器。例如,使用 lld-DLLVM_USE_LINKER=lld

少用 CMake 變數

以下是一些少用的 CMake 變數,以及簡要說明和 LLVM 相關注意事項。如需完整文件,請查閱 CMake 手冊,或執行 cmake --help-variable VARIABLE_NAME

CMAKE_CXX_STANDARD:STRING

設定建置 LLVM 時要符合的 C++ 標準。可能的值為 17 和 20。LLVM 需要 C++17 或更高版本。預設為 17。

CMAKE_INSTALL_BINDIR:PATH

安裝可執行檔的路徑,相對於 CMAKE_INSTALL_PREFIX。預設為 “bin”。

CMAKE_INSTALL_DOCDIR:PATH

CMake 快取

最近,LLVM 和 Clang 一直在新增一些更複雜的建置系統功能。利用這些新功能通常涉及在命令列上傳遞的複雜 CMake 變數鏈。Clang 提供了一系列 CMake 快取腳本,使這些功能更易於使用。

CMake 快取檔案使用 CMake 的 -C 旗標來使用

$ cmake -C <path to cache file> <path to sources>

CMake 快取腳本在隔離範圍內處理,只有快取變數在主要配置執行時保持設定。除非指定 FORCE 選項,否則 CMake 快取變數不會重設已設定的變數。

關於 CMake 快取的一些注意事項

  • 命令列引數的順序很重要

    • 在 -C 之前指定的 -D 引數會在處理快取之前設定,並且可以在快取檔案內讀取

    • 在 -C 之後指定的 -D 引數會在處理快取之後設定,並且在快取檔案內未設定

  • 所有 -D 引數都將覆寫快取檔案設定

  • CMAKE_TOOLCHAIN_FILE 在快取檔案和命令列引數之後評估

  • 建議所有 -D 選項都應在 -C之前指定

有關透過快取檔案支援的一些進階建置配置的更多資訊,請參閱 進階建置配置

執行測試

測試在建置 check-all 目標時執行。例如,如果您正在使用 Makefiles,請在您的建置目錄的根目錄中執行此命令

$ make check-all

在 Visual Studio 上,您可以透過建置專案「check-all」來執行測試。有關測試的更多資訊,請參閱 LLVM 測試基礎結構指南

交叉編譯

有關如何使用 CMake 進行交叉編譯的通用說明,請參閱 此 wiki 頁面。它深入探討了詳細的解釋,並且可能看起來令人望而生畏,但事實並非如此。在 wiki 頁面上,有幾個範例,包括工具鏈檔案。直接前往 Information how to set up various cross compiling toolchains 區段以取得快速解決方案。

另請參閱 LLVM 相關變數區段,以了解交叉編譯時使用的變數。

在您的專案中嵌入 LLVM

從 LLVM 3.5 開始,CMake 建置系統將 LLVM 程式庫匯出為可匯入的 CMake 目標。這表示 LLVM 的用戶端現在可以可靠地使用 CMake 來針對已安裝版本的 LLVM 開發其自己的基於 LLVM 的專案,而無論它是如何建置的。

以下是一個簡單的 CMakeLists.txt 檔案範例,該檔案匯入 LLVM 程式庫並使用它們來建置簡單的應用程式 simple-tool

cmake_minimum_required(VERSION 3.20.0)
project(SimpleProject)

find_package(LLVM REQUIRED CONFIG)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")

# Set your project compile flags.
# E.g. if using the C++ header files
# you will need to enable C++11 support
# for your compiler.

include_directories(${LLVM_INCLUDE_DIRS})
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})

# Now build our tools
add_executable(simple-tool tool.cpp)

# Find the libraries that correspond to the LLVM components
# that we wish to use
llvm_map_components_to_libnames(llvm_libs support core irreader)

# Link against LLVM libraries
target_link_libraries(simple-tool ${llvm_libs})

當在 CONFIG 模式下使用 find_package(...) 指令時(如上述範例中所示),它將在各種位置尋找 LLVMConfig.cmake 檔案(有關詳細資訊,請參閱 cmake 手冊)。它建立一個 LLVM_DIR 快取項目,以儲存找到 LLVMConfig.cmake 的目錄,或允許使用者指定目錄(例如,透過將 -DLLVM_DIR=/usr/lib/cmake/llvm 傳遞給 cmake 命令,或透過在 ccmakecmake-gui 中直接設定它)。

此檔案在兩個不同的位置可用。

  • <LLVM_INSTALL_PACKAGE_DIR>/LLVMConfig.cmake,其中 <LLVM_INSTALL_PACKAGE_DIR> 是 LLVM CMake 模組作為已安裝版本的 LLVM 的一部分安裝到的位置。這通常是 lib 目錄中的 cmake/llvm/。在 Linux 上,這通常是 /usr/lib/cmake/llvm/LLVMConfig.cmake

  • <LLVM_BUILD_ROOT>/lib/cmake/llvm/LLVMConfig.cmake,其中 <LLVM_BUILD_ROOT> 是 LLVM 建置樹狀結構的根目錄。注意:這僅在使用 CMake 建置 LLVM 時可用。

如果 LLVM 安裝在作業系統的正常安裝前置詞中(例如,在 Linux 上,這通常是 /usr/),如果正確安裝了 LLVM,則 find_package(LLVM ...) 將自動找到 LLVM。如果未安裝 LLVM,或者您希望直接針對 LLVM 建置樹狀結構進行建置,則可以使用先前提及的 LLVM_DIR

LLVMConfig.cmake 檔案設定了各種有用的變數。值得注意的變數包括

LLVM_CMAKE_DIR

LLVM CMake 目錄的路徑(即包含 LLVMConfig.cmake 的目錄)。

LLVM_DEFINITIONS

在針對 LLVM 建置時應使用的一系列前處理器定義。

LLVM_ENABLE_ASSERTIONS

如果使用斷言建置 LLVM,則設定為 ON,否則為 OFF。

LLVM_ENABLE_EH

如果使用異常處理 (EH) 啟用建置 LLVM,則設定為 ON,否則為 OFF。

LLVM_ENABLE_RTTI

如果使用執行階段型別資訊 (RTTI) 建置 LLVM,則設定為 ON,否則為 OFF。

LLVM_INCLUDE_DIRS

包含 LLVM 標頭檔的目錄的一系列包含路徑。

LLVM_PACKAGE_VERSION

LLVM 版本。此字串可以與 CMake 條件語句一起使用,例如 if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.5")

LLVM_TOOLS_BINARY_DIR

包含 LLVM 工具(例如 llvm-as)的目錄的路徑。

請注意,在上面的範例中,我們將 simple-tool 與多個 LLVM 程式庫連結。程式庫清單由使用 llvm_map_components_to_libnames() CMake 函數決定。有關可用組件的清單,請查看執行 llvm-config --components 的輸出。

請注意,對於 LLVM < 3.5,使用 llvm_map_components_to_libraries() 而不是 llvm_map_components_to_libnames()。現在已棄用,並將在 LLVM 的未來版本中移除。

在原始碼外部開發 LLVM passes

可以開發 LLVM passes 在 LLVM 的原始碼樹狀結構外部(即,針對已安裝或已建置的 LLVM)。下面提供了專案佈局的範例。

<project dir>/
    |
    CMakeLists.txt
    <pass name>/
        |
        CMakeLists.txt
        Pass.cpp
        ...

<project dir>/CMakeLists.txt 的內容

find_package(LLVM REQUIRED CONFIG)

separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
include_directories(${LLVM_INCLUDE_DIRS})

add_subdirectory(<pass name>)

<project dir>/<pass name>/CMakeLists.txt 的內容

add_library(LLVMPassname MODULE Pass.cpp)

請注意,如果您希望將此 pass 在未來某個時間點合併到 LLVM 原始碼樹中,那麼使用 LLVM 內部的 add_llvm_library 函數,並改用 MODULE 參數可能會更有意義,方法是…

將以下內容添加到 <project dir>/CMakeLists.txt 中 (在 find_package(LLVM ...) 之後)

list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
include(AddLLVM)

然後將 <project dir>/<pass name>/CMakeLists.txt 更改為

add_llvm_library(LLVMPassname MODULE
  Pass.cpp
  )

當您完成 pass 的開發後,您可能會希望將其整合到 LLVM 原始碼樹中。您可以透過兩個簡單的步驟達成此目的

  1. <pass name> 資料夾複製到 <LLVM root>/lib/Transforms 目錄。

  2. add_subdirectory(<pass name>) 行添加到 <LLVM root>/lib/Transforms/CMakeLists.txt 中。

編譯器/平台特定主題

特定編譯器和/或平台的注意事項。

Windows

LLVM_COMPILER_JOBS:STRING

指定在使用 msbuild 或 Visual Studio 建置時,每個專案要使用的最大平行編譯器任務數量。僅支援 Visual Studio 2010 CMake 產生器。0 表示使用所有處理器。預設值為 0。

CMAKE_MT:STRING

當使用 clang-cl 編譯時,最近的 CMake 版本預設會選擇 llvm-mt 作為 Manifest Tool,而不是 Microsoft 的 mt.exe。這通常會導致類似以下的錯誤

-- Check for working C compiler: [...]clang-cl.exe - broken
[...]
    MT: command [...] failed (exit code 0x1) with the following output:
    llvm-mt: error: no libxml2
    ninja: build stopped: subcommand failed.

為了解決這個錯誤,請設定 CMAKE_MT=mt