LLVM 系統入門

概觀

歡迎來到 LLVM 專案!

LLVM 專案有多個元件。專案的核心本身稱為「LLVM」。它包含處理中介表示並將其轉換為物件檔所需的所有工具、函式庫和標頭檔。工具包括組譯器、反組譯器、位元碼分析器和位元碼優化器。它還包含基本的回歸測試。

類 C 語言使用 Clang 前端。此元件將 C、C++、Objective C 和 Objective C++ 程式碼編譯成 LLVM 位元碼,然後使用 LLVM 將其轉換為物件檔。

其他元件包括:libc++ C++ 標準函式庫LLD 連結器 等等。

取得原始碼並建置 LLVM

  1. 簽出 LLVM(包括 Clang 等子專案)

    • git clone https://github.com/llvm/llvm-project.git

    • 或者,在 Windows 上

      git clone --config core.autocrlf=false https://github.com/llvm/llvm-project.git

    • 為了節省儲存空間並加快簽出時間,您可能需要進行 淺層複製。例如,若要取得 LLVM 專案的最新版本,請使用

      git clone --depth 1 https://github.com/llvm/llvm-project.git

    • 您可能對儲存庫中的使用者分支(用於堆疊的拉取請求和還原)不感興趣,您可以使用以下設定從 git fetch(或 git pull)中過濾掉它們

git config --add remote.origin.fetch '^refs/heads/users/*'
git config --add remote.origin.fetch '^refs/heads/revert-*'
  1. 設定並建置 LLVM 和 Clang

    • cd llvm-project

    • cmake -S llvm -B build -G <產生器> [選項]

      一些常見的建置系統產生器有

      • Ninja — 用於產生 Ninja 建置檔案。大多數 LLVM 開發人員使用 Ninja。

      • Unix Makefiles — 用於產生與 make 相容的並行 makefile。

      • Visual Studio — 用於產生 Visual Studio 專案和方案。

      • Xcode — 用於產生 Xcode 專案。

      • 如需更全面的清單,請參閱 CMake 文件

      一些常見的選項

      • -DLLVM_ENABLE_PROJECTS='...' — 以分號分隔的清單,列出您想要額外建置的 LLVM 子專案。可以包含以下任何項目:clang、clang-tools-extra、lldb、lld、polly 或 cross-project-tests。

        例如,要建置 LLVM、Clang 和 LLD,請使用 -DLLVM_ENABLE_PROJECTS="clang;lld"

      • -DCMAKE_INSTALL_PREFIX=目錄 — 為 *目錄* 指定您想要安裝 LLVM 工具和程式庫的完整路徑名稱(預設為 /usr/local)。

      • -DCMAKE_BUILD_TYPE=類型 — 控制建置的最佳化級別和偵錯資訊。 *類型* 的有效選項為 DebugReleaseRelWithDebInfoMinSizeRel。如需更多詳細資訊,請參閱 CMAKE_BUILD_TYPE

      • -DLLVM_ENABLE_ASSERTIONS=ON — 編譯時啟用斷言檢查(預設情況下,偵錯建置為 ON,所有其他建置類型為 OFF)。

      • -DLLVM_USE_LINKER=lld — 使用 lld 連結器 進行連結,假設它已安裝在您的系統上。如果預設連結器速度緩慢,這可以顯著加快連結時間。

      • -DLLVM_PARALLEL_{COMPILE,LINK,TABLEGEN}_JOBS=N — 限制同時並行執行的編譯/連結/表格產生作業的數量。這對於連結尤其重要,因為連結可能會使用大量記憶體。如果您在建置 LLVM 時遇到記憶體問題,請嘗試設定此選項以限制同時執行的編譯/連結/表格產生作業的最大數量。

    • cmake --build build [--target <目標>] 或直接使用上面指定的建置系統。

      • 預設目標(即 cmake --build buildmake -C build)將建置所有 LLVM。

      • check-all 目標(即 ninja check-all)將執行回歸測試,以確保一切正常運作。

      • CMake 將為每個工具和程式庫產生建置目標,並且大多數 LLVM 子專案都會產生自己的 check-<專案> 目標。

      • 執行循序建置會很**慢**。如要提升速度,請嘗試執行平行建置。Ninja 預設會執行平行建置;對於 make,請使用 -j NN 選項,其中 NN 是平行作業的數量,例如可用的 CPU 數量。

    • 一個基本的 CMake 和建置/測試呼叫,只建置 LLVM,沒有其他子專案

      cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug

      ninja -C build check-llvm

      這將設定一個包含除錯資訊的 LLVM 建置,然後編譯 LLVM 並執行 LLVM 測試。

    • 如需 CMake 選項的詳細資訊,請參閱 CMake

    • 如果您遇到建置或測試失敗,請參閱 下方

如需設定和編譯 LLVM 的詳細資訊,請參閱 LLVM 入門 章節。如需原始碼樹狀結構的說明,請參閱 目錄結構

獨立建置

獨立建置允許您針對系統上已存在的預先建置的 clang 或 llvm 程式庫版本建置子專案。

您可以使用來自 llvm-project 標準 checkout 的原始碼(如上所述)進行獨立建置,但您也可以從 稀疏 checkout版本 頁面上提供的 tarball 進行建置。

對於獨立建置,您必須安裝一個已正確設定的 llvm,以便其他專案的獨立建置可以使用。這可以是發行版提供的 LLVM 安裝,或者您可以自己建置,如下所示

cmake -G Ninja -S path/to/llvm-project/llvm -B $builddir \
      -DLLVM_INSTALL_UTILS=ON \
      -DCMAKE_INSTALL_PREFIX=/path/to/llvm/install/prefix \
      < other options >

ninja -C $builddir install

安裝 llvm 之後,要設定專案以進行獨立建置,請像這樣呼叫 CMake

cmake -G Ninja -S path/to/llvm-project/$subproj \
      -B $buildir_subproj \
      -DLLVM_EXTERNAL_LIT=/path/to/lit \
      -DLLVM_ROOT=/path/to/llvm/install/prefix

請注意

  • 獨立建置需要在 LLVMN 建置所在的原始資料夾以外的資料夾中進行($builddir!=$builddir_subproj)。

  • LLVM_ROOT 應該指向您的 llvm 安裝路徑,例如,如果 llvm 安裝在 /usr/bin/usr/lib64 中,則您應該傳遞 -DLLVM_ROOT=/usr/

  • 所有子專案都需要 LLVM_ROOTLLVM_EXTERNAL_LIT 選項才能進行獨立建置。下表列出了每個子專案的其他必要選項。

下表列出的子專案支援 check-$subprojinstall 建置目標。

子專案

必要的子目錄

必要的 CMake 選項

llvm

llvm、cmake、third-party

LLVM_INSTALL_UTILS=ON

clang

clang、cmake

CLANG_INCLUDE_TESTS=ON(僅限 check-clang 需要)

lld

lld、cmake

建置獨立 clang 的範例

#!/bin/sh

build_llvm=`pwd`/build-llvm
build_clang=`pwd`/build-clang
installprefix=`pwd`/install
llvm=`pwd`/llvm-project
mkdir -p $build_llvm
mkdir -p $installprefix

cmake -G Ninja -S $llvm/llvm -B $build_llvm \
      -DLLVM_INSTALL_UTILS=ON \
      -DCMAKE_INSTALL_PREFIX=$installprefix \
      -DCMAKE_BUILD_TYPE=Release

ninja -C $build_llvm install

cmake -G Ninja -S $llvm/clang -B $build_clang \
      -DLLVM_EXTERNAL_LIT=$build_llvm/utils/lit \
      -DLLVM_ROOT=$installprefix

ninja -C $build_clang

需求

在開始使用 LLVM 系統之前,請先查看下方列出的需求。事先了解所需的軟硬體可以省去一些麻煩。

硬體

已知 LLVM 可在下列主機平台上運作:

作業系統

架構

編譯器

Linux

x861

GCC、Clang

Linux

amd64

GCC、Clang

Linux

ARM

GCC、Clang

Linux

Mips

GCC、Clang

Linux

PowerPC

GCC、Clang

Linux

SystemZ

GCC、Clang

Solaris

V9 (Ultrasparc)

GCC

DragonFlyBSD

amd64

GCC、Clang

FreeBSD

x861

GCC、Clang

FreeBSD

amd64

GCC、Clang

NetBSD

x861

GCC、Clang

NetBSD

amd64

GCC、Clang

OpenBSD

x861

GCC、Clang

OpenBSD

amd64

GCC、Clang

macOS2

PowerPC

GCC

macOS

x86

GCC、Clang

Cygwin/Win32

x861, 3

GCC

Windows

x861

Visual Studio

Windows x64

x86-64

Visual Studio

備註

  1. 支援 Pentium 處理器及更高版本的程式碼產生

  2. 僅支援 32 位元 ABI 的程式碼產生

  3. 若要在基於 Win32 的系統上使用 LLVM 模組,您可以使用 -DBUILD_SHARED_LIBS=On 設定 LLVM。

請注意,偵錯組建需要大量的時間和磁碟空間。僅限 LLVM 的組建需要大約 1-3 GB 的空間。LLVM 和 Clang 的完整組建需要大約 15-20 GB 的磁碟空間。確切的空間需求會因系統而異。(由於所有偵錯資訊以及程式庫是靜態連結到多個工具中,因此檔案很大)。

如果您的空間有限,則可以僅組建選定的工具或僅組建選定的目標。發行組建所需的空間要少得多。

LLVM 套件「可能」可以在其他平台上編譯,但不能保證一定可以。如果編譯成功,LLVM 工具應該能夠組譯、反組譯、分析和最佳化 LLVM 位元碼。程式碼產生也應該可以運作,但產生的原生程式碼可能無法在您的平台上運作。

軟體

編譯 LLVM 需要安裝多個軟體套件。下表列出了這些必要的套件。「套件」欄是 LLVM 依賴的軟體套件的常用名稱。「版本」欄提供了套件「已知可運作」的版本。「備註」欄描述了 LLVM 如何使用套件並提供了其他詳細資訊。

套件

版本

備註

CMake

>=3.20.0

Makefile/工作區產生器

python

>=3.8

自動化測試套件1

zlib

>=1.2.3.4

壓縮程式庫2

GNU Make

3.79, 3.79.1

Makefile/建置處理器3

PyYAML

>=5.1

標頭檔產生器4

備註

  1. 僅在您想要在 llvm/test 目錄中執行自動化測試套件時,或是在您打算使用任何 Python 程式庫、工具程式或繫結時才需要。

  2. 選用,為選定的 LLVM 工具新增壓縮/解壓縮功能。

  3. 選用,您可以使用 CMake 支援的任何其他建置工具。

  4. 僅在使用 New Headergen 建置 libc 時才需要。主要由 libc 使用。

此外,您的編譯主機預計會安裝大量的 Unix 工具程式。具體來說:

  • ar — 靜態程式庫建置器

  • bzip2 — 用於產生發行版的 bzip2 命令

  • bunzip2 — 用於檢查發行版的 bunzip2 命令

  • chmod — 變更檔案權限

  • cat — 輸出串聯工具程式

  • cp — 複製檔案

  • date — 顯示目前的日期/時間

  • echo — 顯示到標準輸出

  • egrep — 擴充的正規表示式搜尋工具程式

  • find — 在檔案系統中尋找檔案/目錄

  • grep — 正規表達式搜尋工具程式

  • gzip — 用於產生發行套件的 gzip 命令

  • gunzip — 用於檢查發行套件的 gunzip 命令

  • install — 安裝目錄/檔案

  • mkdir — 建立目錄

  • mv — 移動(重新命名)檔案

  • ranlib — 靜態庫的符號表建立工具

  • rm — 移除(刪除)檔案和目錄

  • sed — 轉換輸出的串流編輯器

  • sh — 用於 make 建置腳本的 Bourne shell

  • tar — 用於產生發行套件的磁帶封存程式

  • test — 測試檔案系統中的項目

  • unzip — 用於檢查發行套件的 unzip 命令

  • zip — 用於產生發行套件的 zip 命令

主機 C++ 工具鏈,包含編譯器和標準函式庫

LLVM 對主機 C++ 編譯器的要求非常高,因此往往會暴露出編譯器中的錯誤。我們也嘗試緊跟 C++ 語言和函式庫的改進和發展。因此,我們需要一個現代化的主機 C++ 工具鏈,包含編譯器和標準函式庫,才能建置 LLVM。

LLVM 是使用 編碼標準 中記載的 C++ 子集編寫的。為了強制執行這個語言版本,我們會在建置系統中檢查最受歡迎的主機工具鏈的特定最低版本

  • Clang 5.0

  • Apple Clang 10.0

  • GCC 7.4

  • Visual Studio 2019 16.7

任何比這些工具鏈舊的版本「可能」可以運作,但需要使用特殊選項強制建置系統,而且並非真正支援的主機平台。另請注意,這些編譯器的舊版本經常會在編譯 LLVM 時當機或編譯錯誤。

對於較少使用的主機工具鏈,例如 ICC 或 xlC,請注意可能需要非常新的版本才能支援 LLVM 中使用的所有 C++ 功能。

我們會追蹤某些「已知」在用作主機工具鏈的一部分時會失敗的軟體版本。這些軟體甚至有時包含連結器。

GNU ld 2.16.X。某些 2.16.X 版本的 ld 連結器會產生非常長的警告訊息,抱怨某些「.gnu.linkonce.t.*」符號是在已捨棄的區段中定義的。您可以安全地忽略這些訊息,因為它們是錯誤的,而且連結是正確的。使用 ld 2.17 時,這些訊息就會消失。

GNU binutils 2.17:Binutils 2.17 包含 一個錯誤,這個錯誤會導致在建置 LLVM 時連結時間過長(幾分鐘而不是幾秒鐘)。我們建議升級到較新的版本(2.17.50.0.4 或更新版本)。

GNU Binutils 2.19.1 Gold:這個版本的 Gold 包含 一個錯誤,這個錯誤會導致在使用位置獨立程式碼建置 LLVM 時出現間歇性失敗。症狀是有關循環依存關係的錯誤。我們建議升級到較新版本的 Gold。

取得現代化的主機 C++ 工具鏈

本節主要適用於 Linux 和較舊的 BSD。在 macOS 上,您應該要有夠新版本的 Xcode,否則您可能需要升級到夠新的版本。Windows 沒有「系統編譯器」,因此您必須安裝 Visual Studio 2019(或更新版本)或最新版本的 mingw64。FreeBSD 10.0 和更新版本使用現代化的 Clang 作為系統編譯器。

然而,部分 Linux 發行版與其他或較舊的 BSD 版本,有時會搭載極舊版的 GCC。以下步驟將嘗試協助您在這些系統上,升級您的編譯器。不過,我們仍然強烈建議您,盡可能使用搭載符合這些需求的新版系統編譯器的最新發行版。請注意,您可能會想安裝舊版的 Clang 和 libc++ 作為主機編譯器,然而 libc++ 在 Linux 上的建置測試與設定作業,直到近期才趨於完善。因此,本指南建議您先使用 libstdc++ 和新版 GCC 作為初始主機進行啟動載入,之後再使用 Clang(以及 libc++,視情況而定)。

第一步是安裝新的 GCC 工具鏈。最常讓使用者在版本需求上遇到問題的發行版是 Ubuntu Precise 12.04 LTS。針對此發行版,一種簡單的解決方案是安裝 工具鏈測試 PPA 並使用它來安裝新的 GCC。在 ask ubuntu 堆疊交換區github gist 中,有一些關於此主題的優質討論和包含更新指令的說明。然而,並非所有使用者都能使用 PPA,而且還有許多其他的發行版,因此可能需要(或僅是有幫助,畢竟您現在正在進行編譯器開發)從原始碼建置和安裝 GCC。這在現今做起來也相當容易。

安裝特定 GCC 版本的簡單步驟

% gcc_version=7.4.0
% wget https://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.bz2
% wget https://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.bz2.sig
% wget https://ftp.gnu.org/gnu/gnu-keyring.gpg
% signature_invalid=`gpg --verify --no-default-keyring --keyring ./gnu-keyring.gpg gcc-${gcc_version}.tar.bz2.sig`
% if [ $signature_invalid ]; then echo "Invalid signature" ; exit 1 ; fi
% tar -xvjf gcc-${gcc_version}.tar.bz2
% cd gcc-${gcc_version}
% ./contrib/download_prerequisites
% cd ..
% mkdir gcc-${gcc_version}-build
% cd gcc-${gcc_version}-build
% $PWD/../gcc-${gcc_version}/configure --prefix=$HOME/toolchains --enable-languages=c,c++
% make -j$(nproc)
% make install

如需更多詳細資訊,請參閱極富參考價值的 GCC Wiki 條目,本文大部分資訊皆取自於此。

取得 GCC 工具鏈後,請將您的 LLVM 組建設定為將新的工具鏈用於您的主機編譯器和 C++ 標準程式庫。由於新版 libstdc++ 不在系統程式庫搜尋路徑中,因此您需要傳遞額外的連結器旗標,以便在連結時 (-L) 和執行階段 (-rpath) 找到它。如果您使用的是 CMake,則呼叫此指令應該會產生有效的二進位檔案

% mkdir build
% cd build
% CC=$HOME/toolchains/bin/gcc CXX=$HOME/toolchains/bin/g++ \
  cmake .. -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$HOME/toolchains/lib64 -L$HOME/toolchains/lib64"

如果未設定 rpath,則大多數 LLVM 二進位檔案在啟動時會失敗,並顯示載入器發出的類似 libstdc++.so.6: version `GLIBCXX_3.4.20' not found 的訊息。這表示您需要調整 -rpath 連結器旗標。

此方法會將絕對路徑新增至所有可執行檔的 rpath。這對於本機開發而言不成問題。如果您要發佈建置的二進位檔案,以便它們可以在較舊的系統上執行,請將 libstdc++.so.6 複製到 lib/ 目錄中。所有 LLVM 發佈的二進位檔案都有一個指向 $ORIGIN/../lib 的 rpath,因此它們可以在該處找到 libstdc++.so.6。未發佈的二進位檔案沒有設定 rpath,因此找不到 libstdc++.so.6。將 -DLLVM_LOCAL_RPATH="$HOME/toolchains/lib64" 傳遞至 cmake,以上述方式新增 libstdc++.so.6 的絕對路徑。由於這些二進位檔案未發佈,因此使用本機的絕對路徑不成問題。

當您建置 Clang 時,您需要讓*它*能夠存取現代的 C++ 標準函式庫,以便在引導程式的一部分中將其用作您的新主機。 有兩種簡單的方法可以做到這一點,一種是與 Clang 一起建置(並安裝)libc++,然後使用 -stdlib=libc++ 編譯和連結旗標來使用它,或者將 Clang 安裝到與 GCC 相同的前置字元(上方的 $HOME/toolchains)。 Clang 將在其自己的前置字元中尋找 libstdc++,如果找到就會使用它。 您也可以使用 --gcc-toolchain=/opt/my/gcc/prefix 旗標為 Clang 新增一個明確的前置字元,以便在使用剛建置的 Clang 進行引導時將其傳遞給編譯和連結命令。

LLVM 入門

本指南的其餘部分旨在讓您開始使用 LLVM 並為您提供有關 LLVM 環境的一些基本信息。

本指南的後續章節將說明 LLVM 原始程式碼樹的一般佈局、使用 LLVM 工具鏈的簡單範例,以及連結以取得有關 LLVM 的更多信息或透過電子郵件尋求幫助。

術語和符號

在本手冊中,以下名稱用於表示特定於本地系統和工作環境的路徑。 *這些不是您需要設定的環境變數,而是在下方本文件的其餘部分中使用的字串*。 在以下任何範例中,只需將每個名稱替換為本地系統上的適當路徑名稱。 所有這些路徑都是絕對路徑

SRC_ROOT

這是 LLVM 原始程式碼樹的頂層目錄。

OBJ_ROOT

這是 LLVM 物件樹的頂層目錄(即放置物件檔案和已編譯程式的樹。它可以與 SRC_ROOT 相同)。

傳送修補程式

請參閱投稿

對提交進行二分搜尋

請參閱對 LLVM 程式碼進行二分搜尋,以了解如何在 LLVM 上使用 git bisect

還原變更

使用 git 還原變更時,預設訊息會顯示「這會還原提交 XYZ」。 將此保留在提交訊息的末尾,但在其之前新增一些關於為何要還原提交的詳細信息。 簡要說明和/或指向顯示問題的機器人的連結就足夠了。

本地 LLVM 設定

簽出儲存庫後,必須先設定 LLVM 套件原始程式碼,然後才能建置。 此過程使用 CMake。 與普通的 configure 腳本不同,CMake 會以您要求的任何格式產生建置檔案以及各種 *.inc 檔案和 llvm/include/llvm/Config/config.h.cmake

在命令列中,可以使用 -D<變數 名稱>=<值> 的格式將變數傳遞給 cmake。以下變數是開發 LLVM 的人員常用的一些選項。

  • CMAKE_C_COMPILER

  • CMAKE_CXX_COMPILER

  • CMAKE_BUILD_TYPE

  • CMAKE_INSTALL_PREFIX

  • Python3_EXECUTABLE

  • LLVM_TARGETS_TO_BUILD

  • LLVM_ENABLE_PROJECTS

  • LLVM_ENABLE_RUNTIMES

  • LLVM_ENABLE_DOXYGEN

  • LLVM_ENABLE_SPHINX

  • LLVM_BUILD_LLVM_DYLIB

  • LLVM_LINK_LLVM_DYLIB

  • LLVM_PARALLEL_LINK_JOBS

  • LLVM_OPTIMIZED_TABLEGEN

有關更多資訊,請參閱常用 CMake 變數列表

若要設定 LLVM,請遵循以下步驟

  1. 將目錄變更為物件根目錄

    % cd OBJ_ROOT
    
  2. 執行 cmake

    % cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=<type> -DCMAKE_INSTALL_PREFIX=/install/path
      [other options] SRC_ROOT
    

編譯 LLVM 套件原始碼

與 autotools 不同,使用 CMake 時,建置類型是在設定時定義的。如果要變更建置類型,可以使用以下呼叫重新執行 cmake

% cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=<type> SRC_ROOT

在兩次執行之間,CMake 會保留為所有選項設定的值。CMake 定義了以下建置類型

偵錯

這些建置是預設值。建置系統將編譯未最佳化的工具和程式庫,並啟用偵錯資訊和斷言。

發布

對於這些建置,建置系統將使用已啟用的最佳化來編譯工具和程式庫,並且不會產生偵錯資訊。CMake 的預設最佳化級別為 -O3。這可以透過在 CMake 命令列上設定 CMAKE_CXX_FLAGS_RELEASE 變數來設定。

RelWithDebInfo

這些建置在偵錯時很有用。它們會產生帶有偵錯資訊的最佳化二進位檔。CMake 的預設最佳化級別為 -O2。這可以透過在 CMake 命令列上設定 CMAKE_CXX_FLAGS_RELWITHDEBINFO 變數來設定。

設定好 LLVM 後,您可以透過輸入 *OBJ_ROOT* 目錄並發出以下命令來建置它

% make

如果建置失敗,請在此處查看您是否使用已知無法編譯 LLVM 的 GCC 版本。

如果您的機器中有多個處理器,您可能會希望使用 GNU Make 提供的一些平行建置選項。例如,您可以使用以下命令

% make -j2

在使用 LLVM 原始碼時,有幾個特殊的目標很有用

make clean

移除建置產生的所有檔案。這包括物件檔案、產生的 C/C++ 檔案、程式庫和可執行檔。

make install

將 LLVM 標頭檔、程式庫、工具和文件安裝在 $PREFIX 下的階層中,使用 CMAKE_INSTALL_PREFIX 指定,預設為 /usr/local

make docs-llvm-html

如果使用 -DLLVM_ENABLE_SPHINX=On 設定,這將在 OBJ_ROOT/docs/html 中產生一個目錄,其中包含 HTML 格式的文件。

交叉編譯 LLVM

可以交叉編譯 LLVM 本身。也就是說,您可以創建 LLVM 可執行文件和函式庫,以託管在與構建它們的平台不同的平台上(加拿大交叉構建)。為了生成用於交叉編譯的構建文件,CMake 提供了一個變數 CMAKE_TOOLCHAIN_FILE,它可以定義在 CMake 測試操作期間使用的編譯器標誌和變數。

此類構建的結果是在構建主機上不可運行的可執行文件,但可以在目標上執行。例如,以下 CMake 調用可以生成針對 iOS 的構建文件。這將適用於 macOS 上最新的 Xcode

% cmake -G "Ninja" -DCMAKE_OSX_ARCHITECTURES="armv7;armv7s;arm64"
  -DCMAKE_TOOLCHAIN_FILE=<PATH_TO_LLVM>/cmake/platforms/iOS.cmake
  -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=Off -DLLVM_INCLUDE_TESTS=Off
  -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_ENABLE_BACKTRACES=Off [options]
  <PATH_TO_LLVM>

注意:由於 iOS SDK 的限制,在為 iOS 構建時需要傳遞一些額外的標誌。

如需有關交叉編譯的更多信息,請查看如何使用 Clang/LLVM 交叉編譯 Clang/LLVM有關如何交叉編譯的 Clang 文檔

LLVM 目標文件的存放位置

LLVM 構建系統能夠在多個 LLVM 構建之間共享單個 LLVM 源代碼樹。因此,可以使用相同的源代碼樹為多個不同的平台或配置構建 LLVM。

  • 將目錄更改為 LLVM 目標文件應存放的位置

    % cd OBJ_ROOT
    
  • 運行 cmake

    % cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release SRC_ROOT
    

LLVM 構建將在 OBJ_ROOT 下創建一個與 LLVM 源代碼樹匹配的結構。在源代碼樹中存在源文件的每個級別,OBJ_ROOT 中都會有一個對應的 CMakeFiles 目錄。在該目錄下,還有另一個名稱以 .dir 結尾的目錄,您可以在其中找到每個源的目標文件。

例如

% cd llvm_build_dir
% find lib/Support/ -name APFloat*
lib/Support/CMakeFiles/LLVMSupport.dir/APFloat.cpp.o

可選配置項目

如果您在支持 binfmt_misc 模塊的 Linux 系統上運行,並且您具有系統的 root 訪問權限,則可以將系統設置為直接執行 LLVM 位碼文件。為此,請使用如下命令(如果您已經在使用該模塊,則第一個命令可能不是必需的)

% mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
% echo ':llvm:M::BC::/path/to/lli:' > /proc/sys/fs/binfmt_misc/register
% chmod u+x hello.bc   (if needed)
% ./hello.bc

這允許您直接執行 LLVM 位碼文件。在 Debian 上,您也可以使用此命令代替上面的“echo”命令

% sudo update-binfmts --install llvm /path/to/lli --magic 'BC'

目錄佈局

有關 LLVM 源碼庫的一個有用信息來源是 LLVM doxygen 文檔,網址為 https://llvm.dev.org.tw/doxygen/。以下是對代碼佈局的簡要介紹

llvm/cmake

生成系統構建文件。

llvm/cmake/modules

llvm 用戶定義選項的構建配置。檢查編譯器版本和鏈接器標誌。

llvm/cmake/platforms

Android NDK、iOS 系統和非 Windows 主機的工具鏈配置,以面向 MSVC。

llvm/examples

  • 一些簡單的例子,展示瞭如何使用 LLVM 作為自定義語言的編譯器 - 包括降低、優化和代碼生成。

  • 萬花筒教學:萬花筒語言教學,涵蓋了一個完整編譯器的實現,包括手寫的詞法分析器、語法分析器、抽象語法樹,以及使用 LLVM 的代碼生成支持,包含靜態(預先)和各種即時 (JIT) 編譯方法。 適用於完全初學者的萬花筒教學

  • BuildingAJIT:BuildingAJIT 教學 的示例,展示了 LLVM 的 ORC JIT API 如何與 LLVM 的其他部分交互。它還教導如何重新組合它們以構建適合您的用例的自定義 JIT。

llvm/include

從 LLVM 庫導出的公開標頭檔。三個主要子目錄:

llvm/include/llvm

所有特定於 LLVM 的標頭檔,以及 LLVM 不同部分的子目錄:AnalysisCodeGenTargetTransforms 等……

llvm/include/llvm/Support

LLVM 提供的通用支持庫,但不一定特定於 LLVM。例如,一些 C++ STL 工具程式和命令列選項處理庫將標頭檔存儲在此處。

llvm/include/llvm/Config

cmake 配置的標頭檔。它們包裝了“標準”UNIX 和 C 標頭檔。原始碼可以包含這些標頭檔,這些標頭檔會自動處理 cmake 生成的條件 #includes。

llvm/lib

大多數原始程式碼檔案都在這裡。通過將代碼放入庫中,LLVM 可以輕鬆地在 工具 之間共享代碼。

llvm/lib/IR/

實現核心類別(如 Instruction 和 BasicBlock)的核心 LLVM 原始程式碼檔案。

llvm/lib/AsmParser/

LLVM 組合語言解析器庫的原始程式碼。

llvm/lib/Bitcode/

讀取和寫入位元碼的代碼。

llvm/lib/Analysis/

各種程式分析,例如呼叫圖、歸納變數、自然迴圈識別等。

llvm/lib/Transforms/

IR 到 IR 的程式轉換,例如積極的無用代碼消除、稀疏條件常數傳播、內聯、迴圈不變代碼移動、無用全局變數消除等等。

llvm/lib/Target/

描述代碼生成的目標架構的檔案。例如,llvm/lib/Target/X86 包含 X86 機器描述。

llvm/lib/CodeGen/

代碼生成器的主要部分:指令選擇器、指令調度和寄存器分配。

llvm/lib/MC/

庫在機器碼級別表示和處理代碼。處理組合語言和物件檔的發出。

llvm/lib/ExecutionEngine/

用於在直譯和 JIT 編譯場景中於運行時直接執行位元碼的庫。

llvm/lib/Support/

llvm/include/ADT/llvm/include/Support/ 中的標頭檔相對應的原始程式碼。

llvm/bindings

包含 LLVM 編譯器基礎結構的綁定,允許使用 C 或 C++ 以外的語言編寫的程式利用 LLVM 基礎結構。LLVM 項目為 OCaml 和 Python 提供了語言綁定。

llvm/projects

並非嚴格屬於 LLVM 但隨 LLVM 一起發佈的專案。這也是用於創建您自己的基於 LLVM 的專案的目錄,這些專案利用了 LLVM 編譯系統。

llvm/test

功能和回歸測試,以及 LLVM 基礎架構的其他健全性檢查。這些測試旨在快速運行並涵蓋廣泛的領域,但並非詳盡無遺。

test-suite

一個全面的 LLVM 正確性、性能和基準測試套件。這位於一個獨立的 git 倉庫 <https://github.com/llvm/llvm-test-suite> 中,因為它包含大量在各種許可證下的第三方代碼。有關詳細信息,請參閱測試指南文檔。

llvm/tools

從上面的函式庫構建的可執行文件,它們構成了使用者介面的主要部分。您始終可以通過鍵入tool_name -help 來獲得工具的幫助。以下是對最重要工具的簡要介紹。更詳細的信息請參閱命令指南

bugpoint

bugpoint 用於通過將給定的測試用例縮小到最少數量的仍然導致問題的過程和/或指令來調試優化過程或代碼生成後端,無論是崩潰還是錯誤編譯。有關使用bugpoint 的更多信息,請參閱HowToSubmitABug.html

llvm-ar

封存器生成一個包含給定 LLVM 位元碼文件的封存,可選地包含一個用於更快查找的索引。

llvm-as

組譯器將人類可讀的 LLVM 組合語言轉換為 LLVM 位元碼。

llvm-dis

反組譯器將 LLVM 位元碼轉換為人類可讀的 LLVM 組合語言。

llvm-link

毫不奇怪,llvm-link 將多個 LLVM 模組連結到單個程序中。

lli

lli 是 LLVM 解釋器,它可以直接執行 LLVM 位元碼(儘管速度非常慢……)。對於支持它的架構(目前是 x86、Sparc 和 PowerPC),默認情況下,lli 將充當即時編譯器(如果已編譯該功能),並且執行代碼的速度將比解釋器*快得多*。

llc

llc 是 LLVM 後端編譯器,它將 LLVM 位元碼轉換為原生代碼組合語言文件。

opt

opt 讀取 LLVM 位元碼,應用一系列 LLVM 到 LLVM 的轉換(在命令行中指定),並輸出結果位元碼。‘opt -help’ 是一個獲取 LLVM 中可用程序轉換列表的好方法。

您也可以在輸入的 LLVM 位元碼檔案上執行特定的分析,並列印結果。這主要用於除錯分析,或讓您熟悉分析的功能。

llvm/utils

用於處理 LLVM 原始碼的工具;有些是建置過程的一部分,因為它們是基礎結構部分的程式碼產生器。

codegen-diff

codegen-diff 會找出 LLC 產生的程式碼與 LLI 產生的程式碼之間的差異。如果您正在除錯其中一個,並假設另一個產生的輸出是正確的,那麼這會很有用。如需完整的使用者手冊,請執行 `perldoc codegen-diff'

emacs/

Emacs 和 XEmacs 語法高亮顯示,適用於 LLVM 組合語言檔案和 TableGen 描述檔案。如需使用方式的資訊,請參閱 README

getsrcs.sh

尋找並輸出所有非產生的原始碼檔案,如果您想跨目錄進行大量開發,並且不想一一尋找每個檔案,那麼這會很有用。一種使用方法是從 LLVM 原始碼樹的頂層執行,例如:xemacs `utils/getsources.sh`

llvmgrep

對 LLVM 中的每個原始碼檔案執行 egrep -H -n,並將 llvmgrep 命令列上提供的正規表示式傳遞給它。這是搜尋原始碼庫中特定正規表示式的有效方法。

TableGen/

包含用於從常見的 TableGen 描述檔案產生暫存器描述、指令集描述,甚至組譯器的工具。

vim/

vim 語法高亮顯示,適用於 LLVM 組合語言檔案和 TableGen 描述檔案。如需使用方式,請參閱 README

使用 LLVM 工具鏈的範例

本節將以 Clang 為前端,示範如何使用 LLVM。

使用 clang 的範例

  1. 首先,建立一個簡單的 C 檔案,將其命名為「hello.c」

    #include <stdio.h>
    
    int main() {
      printf("hello world\n");
      return 0;
    }
    
  2. 接下來,將 C 檔案編譯成原生可執行檔

    % clang hello.c -o hello
    

    備註

    Clang 預設的運作方式與 GCC 相同。標準的 -S 和 -c 參數會照常運作(分別產生原生 .s 或 .o 檔案)。

  3. 接下來,將 C 檔案編譯成 LLVM 位元碼檔案

    % clang -O3 -emit-llvm hello.c -c -o hello.bc
    

    -emit-llvm 選項可以與 -S 或 -c 選項一起使用,以便為程式碼發出 LLVM .ll.bc 檔案(分別)。這讓您可以在位元碼檔案上使用標準 LLVM 工具

  4. 以兩種形式執行程式。若要執行程式,請使用

    % ./hello
    

    % lli hello.bc
    

    第二個範例顯示如何叫用 LLVM JIT,lli

  5. 使用 llvm-dis 工具來查看 LLVM 組合語言程式碼

    % llvm-dis < hello.bc | less
    
  6. 使用 LLC 程式碼產生器將程式編譯成原生組合語言

    % llc hello.bc -o hello.s
    
  7. 將原生組合語言檔案組譯成程式

    % /opt/SUNWspro/bin/cc -xarch=v9 hello.s -o hello.native   # On Solaris
    
    % gcc hello.s -o hello.native                              # On others
    
  8. 執行原生程式碼

    % ./hello.native
    

    請注意,使用 clang 直接編譯成原生代碼(即未出現 -emit-llvm 選項時)會自動執行步驟 6/7/8。

常見問題

如果您在建置或使用 LLVM 時遇到問題,或者您對 LLVM 有任何其他一般性問題,請參閱常見問題頁面。

如果您在記憶體和建置時間方面遇到問題,請嘗試使用 ninja 而不是 make 進行建置。請考慮使用 cmake 配置以下選項

  • -G Ninja 設定此選項將允許您使用 ninja 而不是 make 進行建置。使用 ninja 進行建置可以顯著縮短建置時間,尤其是在增量建置時,並且可以改善記憶體使用量。

  • -DLLVM_USE_LINKER 將此選項設定為 lld 將顯著縮短基於 ELF 的平台(例如 Linux)上 LLVM 可執行檔的連結時間。如果您是第一次建置 LLVM 且 lld 不作為二進制套件提供給您,那麼您可以考慮使用 gold 連結器作為 GNU ld 的更快替代方案。

  • -DCMAKE_BUILD_TYPE 控制建置的優化級別和除錯資訊。此設定可能會影響 RAM 和磁碟使用量,請參閱CMAKE_BUILD_TYPE以獲取更多資訊。

  • -DLLVM_ENABLE_ASSERTIONS 對於偵錯建置,此選項預設為開啟,對於發行建置,此選項預設為關閉。如前一個選項中所述,使用發行建置類型並啟用斷言可能是使用偵錯建置類型的一個不錯的替代方案。

  • -DLLVM_PARALLEL_LINK_JOBS 將此設定為您希望同時執行的作業數量。這類似於 make 中使用的 -j 選項,但僅適用於連結作業。此選項只能與 ninja 一起使用。您可能希望使用非常少的作業數量,因為這將大大減少建置過程中使用的記憶體量。如果您的記憶體有限,則可能需要將其設定為 1。

  • -DLLVM_TARGETS_TO_BUILD 將此設定為您希望建置的目標。您可能希望將其設定為 X86;但是,您可以在 llvm-project/llvm/lib/Target 目錄中找到完整的目標列表。

  • -DLLVM_OPTIMIZED_TABLEGEN 將此設定為開啟將在建置期間生成完全優化的 tablegen。這將顯著縮短您的建置時間。這僅在您使用偵錯建置類型時才有用。

  • -DLLVM_ENABLE_PROJECTS 將此設定為您希望編譯的專案(例如 clang、lld 等)。如果編譯多個專案,請使用分號分隔各個專案。如果您在使用分號時遇到問題,請嘗試用單引號將其括起來。

  • -DLLVM_ENABLE_RUNTIMES 將此設定為您希望編譯的運行時(例如 libcxx、libcxxabi 等)。如果編譯多個運行時,請使用分號分隔各個運行時。如果您在使用分號時遇到問題,請嘗試用單引號將其括起來。

  • -DCLANG_ENABLE_STATIC_ANALYZER 如果您不需要 clang 靜態分析器,請將此選項設定為關閉。這應該會稍微縮短您的建置時間。

  • -DLLVM_USE_SPLIT_DWARF 如果您需要偵錯建置,請考慮將此設定為開啟,因為這將減輕連結器上的記憶體壓力。這將使連結速度更快,因為二進制檔案將不包含任何偵錯資訊;但是,這會以 DWARF 物件檔案的形式(副檔名為 .dwo)生成偵錯資訊。這僅適用於使用 ELF 的主機平台,例如 Linux。