使用 CMake 建置 LLVM

簡介

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

如果您是**新貢獻者**,請從 LLVM 系統入門 頁面開始。本頁面適用於從舊版 configure/make 系統轉換而來的現有貢獻者。

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

本頁面適用於 LLVM CMake 建置的使用者。如果您正在尋找有關修改 LLVM CMake 建置系統的資訊,您可能需要查看 CMake 入門 頁面。它對 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 本身是適合您的開發環境的。例如,如果您可以透過 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 就會使用相應的「產生器」為您的建置工具建立檔案(例如,Makefiles 或 Visual Studio 或 Xcode 專案檔案)。您可以使用命令列選項 -G "產生器名稱" 明確指定產生器。若要查看系統上可用產生器的清單,請執行

$ cmake --help

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

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

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

對於特定的開發平台,可能會有超過一種適用的生成器。如果您使用 Visual Studio,「NMake Makefiles」是一種您可以用於使用 NMake 進行建置的生成器。預設情況下,CMake 會選擇您的開發環境所支援的最特定的生成器。如果您想要使用其他生成器,您必須使用 -G 選項將此訊息告知 CMake。

選項和變數

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

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

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

$ cmake -UVARIABLE path/to/llvm/source

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

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

$ cmake -DVARIABLE: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 的預設值。

如果您使用的是 Visual Studio 或 Xcode 等 IDE,則應使用 IDE 設定來設定建置類型。

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

CMAKE_INSTALL_PREFIX:PATH

建置「安裝」目標時要安裝 LLVM 的路徑。

CMAKE_{C,CXX}_FLAGS:STRING

分別在編譯 C 和 C++ 原始檔時使用的額外標記。

CMAKE_{C,CXX}_COMPILER:STRING

指定要使用的 C 和 C++ 編譯器。如果您安裝了多個編譯器,CMake 可能不會預設使用您想要使用的編譯器。

較少使用的 CMake 變數

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

CMAKE_CXX_STANDARD:字串

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

CMAKE_INSTALL_BINDIR:路徑

安裝可執行檔的路徑,相對於 CMAKE_INSTALL_PREFIX。預設值為「bin」。

CMAKE_INSTALL_DOCDIR:路徑

安裝文件的路徑,相對於 CMAKE_INSTALL_PREFIX。預設值為「share/doc」。

CMAKE_INSTALL_INCLUDEDIR:路徑

安裝標頭檔的路徑,相對於 CMAKE_INSTALL_PREFIX。預設值為「include」。

CMAKE_INSTALL_MANDIR:路徑

安裝手冊頁檔案的路徑,相對於 CMAKE_INSTALL_PREFIX。預設值為「share/man」。

CMake 快取

最近 LLVM 和 Clang 加入了一些更複雜的建置系統功能。使用這些新功能通常涉及在命令列上传遞複雜的 CMake 變數鏈。Clang 提供了一組 CMake 快取腳本來讓這些功能更容易使用。

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

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

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

關於 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 頁面上有幾個範例,包括工具鏈檔案。請直接前往 設定各種交叉編譯工具鏈的資訊 章節,以快速找到解決方案。

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

將 LLVM 嵌入您的專案中

從 LLVM 3.5 版開始,CMake 建置系統會將 LLVM 函式庫匯出為可匯入的 CMake 目標。這表示 LLVM 的用戶端現在可以可靠地使用 CMake 開發自己的基於 LLVM 的專案,並對應已安裝的 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})

find_package(...) 指令在 CONFIG 模式下使用時(如上述範例所示),會在多個位置尋找 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/),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

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

LLVM_ENABLE_RTTI

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

LLVM_INCLUDE_DIRS

包含 LLVM 標頭檔的目錄的 include 路徑清單。

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 原始碼樹之外開發 LLVM passes(即針對已安裝或建置的 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. <LLVM 根目錄>/lib/Transforms/CMakeLists.txt 中加入 add_subdirectory(<傳遞 名稱>) 行。

編譯器/平台特定主題

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

Windows

LLVM_COMPILER_JOBS:字串

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

CMAKE_MT:字串

使用 clang-cl 編譯時,最近的 CMake 版本預設會選擇 llvm-mt 作為資訊清單工具,而不是 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