目录
概述
欢迎来到 LLVM 项目!
LLVM 项目有多个组件。该项目的核心本身称为“LLVM”。这包含处理中间表示并将其转换为目标文件所需的所有工具、库和头文件。工具包括汇编器、反汇编器、位码分析器和位码优化器。它还包含基本的回归测试。
类 C 语言使用Clang前端。该组件使用 LLVM 将 C、C++、Objective C 和 Objective C++ 代码编译为 LLVM 位码,并从那里编译为目标文件。
其他组件包括:libc++ C++ 标准库、LLD 链接器等。
获取源代码并构建 LLVM
LLVM 入门文档可能已过期。Clang 入门页面可能包含更准确的信息。
这是获取和构建 LLVM 源的示例工作流和配置:
-
Checkout LLVM(包括 Clang 等相关子项目):
git clone https://github.com/llvm/llvm-project.git
- 或者,在窗户上,
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
-
配置和构建 LLVM 和 Clang:
-
cd llvm-project
-
mkdir build
-
cd build
-
cmake -G <generator> [options] ../llvm
一些常见的构建系统生成器是:
Ninja
— 用于生成Ninja 构建文件。大多数 llvm 开发人员使用 Ninja。Unix Makefiles
— 用于生成与 make 兼容的并行 makefile。Visual Studio
— 用于生成 Visual Studio 项目和解决方案。Xcode
— 用于生成 Xcode 项目。
一些常见的选项:
-
-DLLVM_ENABLE_PROJECTS='...'
— 您要另外构建的 LLVM 子项目的分号分隔列表。可以包括以下任何一种:clang、clang-tools-extra、lldb、compiler-rt、lld、polly 或跨项目测试。例如,要构建 LLVM、Clang、libcxx 和 libcxxabi,请使用 .
-DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi"
-
-DCMAKE_INSTALL_PREFIX=directory
— 为目录指定要安装 LLVM 工具和库的位置的完整路径名(默认/usr/local
)。 -
-DCMAKE_BUILD_TYPE=type
—类型的有效选项是 Debug、Release、RelWithDebInfo 和 MinSizeRel。默认为调试。 -
-DLLVM_ENABLE_ASSERTIONS=On
— 在启用断言检查的情况下编译(Debug 构建默认为 Yes,所有其他构建类型默认为 No)。
-
cmake --build . [--target <target>]
或上面直接指定的构建系统。- 默认目标(即或)将构建所有 LLVM。
cmake --build .
make
check-all
目标(即)将运行回归测试以确保一切正常。ninja check-all
- CMake 将为每个工具和库生成构建目标,并且大多数 LLVM 子项目都会生成自己的
check-<project>
目标。 - 运行串行构建会很慢。要提高速度,请尝试运行并行构建。这是 Ninja 默认完成的;对于
make
,使用选项,其中是并行作业的数量,例如可用 CPU 的数量。-j NN
NN
- 默认目标(即或)将构建所有 LLVM。
-
有关更多信息,请参阅CMake
-
如果您收到“内部编译器错误 (ICE)”或测试失败,请参见 下文。
-
要求
在开始使用 LLVM 系统之前,请查看下面给出的要求。通过提前了解您将需要哪些硬件和软件,这可能会为您节省一些麻烦。
硬件
众所周知,LLVM 可在以下主机平台上工作:
操作系统 | 拱 | 编译器 |
---|---|---|
Linux | x86 1 | 海合会,铿锵 |
Linux | amd64 | 海合会,铿锵 |
Linux | 手臂 | 海合会,铿锵 |
Linux | 米普斯 | 海合会,铿锵 |
Linux | 电源PC | 海合会,铿锵 |
Linux | SystemZ | 海合会,铿锵 |
索拉里斯 | V9 (Ultraparc) | 海合会 |
蜻蜓BSD | amd64 | 海合会,铿锵 |
自由BSD | x86 1 | 海合会,铿锵 |
自由BSD | amd64 | 海合会,铿锵 |
NetBSD | x86 1 | 海合会,铿锵 |
NetBSD | amd64 | 海合会,铿锵 |
OpenBSD | x86 1 | 海合会,铿锵 |
OpenBSD | amd64 | 海合会,铿锵 |
macOS 2 | 电源PC | 海合会 |
苹果系统 | x86 | 海合会,铿锵 |
赛格温/Win32 | x86 1、3 | 海合会 |
视窗 | x86 1 | 视觉工作室 |
视窗 x64 | x86-64 | 视觉工作室 |
笔记
- Pentium 处理器及更高版本支持代码生成
- 仅支持 32 位 ABI 的代码生成
- 要在基于 Win32 的系统上使用 LLVM 模块,您可以使用
-DBUILD_SHARED_LIBS=On
.
请注意,调试版本需要大量时间和磁盘空间。仅 LLVM 构建将需要大约 1-3 GB 的空间。LLVM 和 Clang 的完整构建将需要大约 15-20 GB 的磁盘空间。确切的空间要求因系统而异。(由于所有的调试信息以及库静态链接到多个工具的事实,它是如此之大)。
如果空间有限,您可以只构建选定的工具或只构建选定的目标。发布版本需要的空间要少得多。
LLVM 套件可以在其他平台上编译,但不能保证这样做。如果编译成功,LLVM 实用程序应该能够组装、反汇编、分析和优化 LLVM 位码。代码生成也应该可以工作,尽管生成的本机代码可能无法在您的平台上工作。
软件
编译 LLVM 需要您安装多个软件包。下表列出了这些必需的软件包。Package 列是 LLVM 所依赖的软件包的常用名称。版本列提供包的“已知工作”版本。Notes 列描述了 LLVM 如何使用该包并提供其他详细信息。
包裹 | 版本 | 笔记 |
---|---|---|
制作 | >=3.13.4 | Makefile/工作区生成器 |
海合会 | >=7.1.0 | C/C++ 编译器1 |
Python | >=3.6 | 自动化测试套件2 |
zlib | >=1.2.3.4 | 压缩库3 |
GNU 制作 | 3.79, 3.79.1 | 生成文件/构建处理器4 |
笔记
- 只需要 C 和 C++ 语言,因此无需为 LLVM 的目的构建其他语言。具体版本信息见下文。
- 仅当您想在
llvm/test
目录中运行自动化测试套件时才需要。 - 可选,为选定的 LLVM 工具添加压缩/解压缩功能。
- 可选,您可以使用 CMake 支持的任何其他构建工具。
此外,您的编译主机应具有通常过多的 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 — 用于构建脚本的 Bourne shell
- tar — 用于分发生成的磁带存档
- test — 测试文件系统中的东西
- unzip — 用于分发检查的解压缩命令
- zip — 用于分发生成的 zip 命令
宿主 C++ 工具链,编译器和标准库
LLVM 对宿主 C++ 编译器的要求非常高,因此往往会暴露编译器中的错误。我们还试图合理地密切关注 C++ 语言和库的改进和发展。因此,我们需要一个现代主机 C++ 工具链,包括编译器和标准库,以构建 LLVM。
LLVM 是使用编码标准中记录的 C++ 子集编写的。为了强制执行此语言版本,我们在我们的构建系统中检查最流行的主机工具链以获取特定的最低版本:
- 铿锵声 5.0
- 苹果叮当 9.3
- 海合会 7.1
- 视觉工作室 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。
本节主要适用于 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 stack exchange和 带有更新命令的github gist上有一个非常好的讨论。但是,并非所有用户都可以使用 PPA,并且还有许多其他发行版,因此从源代码构建和安装 GCC可能是必要的(或者只是有用的,如果您在这里进行编译器开发)。这些天也很容易做到。
安装 GCC 7.1.0 的简单步骤:
% gcc_version=7.1.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 二进制文件将在启动时失败,并且来自加载程序的消息类似于. 这意味着您需要调整 -rpath 链接器标志。libstdc++.so.6: version `GLIBCXX_3.4.20' not found
此方法将为所有可执行文件的 rpath 添加绝对路径。这对当地的发展很好。如果您想分发您构建的二进制文件以便它们可以在旧系统上运行,请复制libstdc++.so.6
到该 lib/
目录中。所有 LLVM 的传送二进制文件都有一个指向 的 rpath $ORIGIN/../lib
,所以它们会在libstdc++.so.6
那里找到。非分布式二进制文件没有 rpath 集,也找不到libstdc++.so.6
. 传递 -DLLVM_LOCAL_RPATH="$HOME/toolchains/lib64"
给 cmake 以添加绝对路径,libstdc++.so.6
如上所述。由于这些二进制文件不是分布式的,因此拥有绝对本地路径对它们来说很好。
当您构建 Clang 时,您需要授予它对现代 C++ 标准库的访问权限,以便在引导程序中将其用作您的新主机。有两种简单的方法可以做到这一点,或者与 Clang 一起构建(和安装)libc++,然后将其与-stdlib=libc++
编译和链接标志一起使用,或者将 Clang 安装到与$HOME/toolchains
GCC 相同的前缀(如上)中。Clang 将在其自己的 libstdc++ 前缀中查找并在找到时使用它。您还可以为 Clang 添加显式前缀以查找带有--gcc-toolchain=/opt/my/gcc/prefix
标志的 GCC 工具链,在使用刚刚构建的 Clang 进行引导时将其传递给编译和链接命令。
LLVM 入门
本指南的其余部分旨在帮助您开始使用 LLVM,并为您提供有关 LLVM 环境的一些基本信息。
本指南的后面部分描述了LLVM 源代码树的一般布局,一个使用 LLVM 工具链的简单示例,以及用于查找有关 LLVM 的更多信息或通过电子邮件获得帮助的链接。
术语和符号
在本手册中,以下名称用于表示特定于本地系统和工作环境的路径。 这些不是您需要设置的环境变量,而只是下面本文档其余部分中使用的字符串。在下面的任何示例中,只需将这些名称中的每一个替换为本地系统上的适当路径名即可。所有这些路径都是绝对的:
SRC_ROOT
这是 LLVM 源代码树的顶级目录。
OBJ_ROOT
这是 LLVM 对象树的顶层目录(即放置对象文件和编译程序的树。它可以与 SRC_ROOT 相同)。
解压 LLVM 档案
如果您有 LLVM 发行版,则需要先将其解压缩,然后才能开始编译。LLVM 作为许多不同的子项目分发。每个都有自己的下载,这是一个用 gzip 程序压缩的 TAR 存档。
文件如下,xy标记版本号:
llvm-x.y.tar.gz
LLVM 库和工具的源代码发布。
cfe-x.y.tar.gz
Clang 前端的源代码发布。
从 Git 签出 LLVM
您还可以从 Git 签出 LLVM 的源代码。
笔记
在我们正确调整.gitattribute设置后,以后应该不需要通过,但在撰写本文时 Windows 用户需要。--config core.autocrlf=false
只需运行:
% git clone https://github.com/llvm/llvm-project.git
或在 Windows 上,
% git clone --config core.autocrlf=false https://github.com/llvm/llvm-project.git
这将在当前目录中创建一个 ' llvm-project
' 目录,并用 LLVM 和所有相关子项目的所有源代码、测试目录和文档文件的本地副本完全填充它。请注意,与将每个子项目包含在单独文件中的 tarball 不同,git 存储库包含所有项目。
如果您想获得特定版本(而不是最新版本),您可以在克隆存储库后签出标签。例如,在上述命令创建的目录中git checkout llvmorg-6.0.1 。llvm-project
使用git tag -l列出所有这些。
请也阅读开发者政策。
我们目前不接受 github 拉取请求,因此您需要通过电子邮件向 llvm-commits 发送补丁,或者最好通过Phabricator发送补丁。
您通常希望确保您的分支有一个提交,对应于您希望发送的评论,与上游 origin/main
分支保持同步,并且不包含合并。一旦你有了它,你就可以开始一个 Phabricator 审查(或使用或 输出差异,并将其附加到电子邮件中)。git show
git format-patch
但是,使用“Arcanist”工具通常更容易。安装 arcanist后,您还需要对您的 arcanist 存储库应用修复以提交补丁:
% cd arcanist
% git fetch https://github.com/rashkov/arcanist update_cacerts
% git cherry-pick e3659d43d8911e91739f3b0c5935598bceb859aa
完成后,您可以使用以下命令上传最新提交:
% arc diff HEAD~1
此外,在发送补丁以供审核之前,还请尝试确保其格式正确。我们为此使用clang-format
它,它通过git-clang-format
脚本集成了 git。在某些系统上,它可能已经安装(或者可以通过您的包管理器安装)。如果是这样,您可以简单地运行它——以下命令将仅格式化最近提交中更改的代码:
% git clang-format HEAD~1
请注意,这会修改文件,但不会提交它们——您可能想要运行
% git commit --amend -a
为了使用所有待处理的更改更新最后一次提交。
笔记
如果您的系统上尚未安装clang-format
或安装,二进制文件将与 clang 一起构建,并且 git 集成可以从 .git clang-format
clang-format
clang/tools/clang-format/git-clang-format
审查补丁后,您应该对其进行变基,在本地重新测试,并将更改提交到 LLVM 的主分支。如果您具有所需的访问权限,则可以使用git push完成此操作。请参阅为基于 Phabricator 的提交提交 更改或为提交访问获取 提交访问。
这是使用 git 的示例工作流。此工作流程假定您在名为branch-with-change的分支上已接受提交。
# Go to the branch with your accepted commit.
% git checkout branch-with-change
# Rebase your change onto the latest commits on Github.
% git pull --rebase origin main
# Rerun the appropriate tests if needed.
% ninja check-$whatever
# Check that the list of commits about to be pushed is correct.
% git log origin/main...HEAD --oneline
# Push to Github.
% git push origin HEAD:main
LLVM 当前有一个线性历史策略,这意味着不允许合并提交。github 上的llvm-project存储库被配置为拒绝包含合并的推送,因此需要上面的git rebase步骤。
如果您在使用特定的 git 工作流程时遇到问题,请寻求帮助。
我们包括一个可选的 pre-push 钩子,它对您将要推送的修订版运行一些健全性检查,并在您一次推送多个提交时询问确认。您可以通过从存储库根目录运行来设置它(在 Unix 系统上):
% ln -sf ../../llvm/utils/git/pre-push.py .git/hooks/pre-push
有关如何在 LLVM 上使用的信息,请参阅二分 LLVM 代码 。git bisect
使用 git 恢复更改时,默认消息将显示“This reverts commit XYZ”。将此保留在提交消息的末尾,但在其之前添加一些详细信息,说明为什么要恢复提交。一个简短的解释和/或证明问题的机器人的链接就足够了。
本地 LLVM 配置
签出存储库后,LLVM 套件源代码必须在构建之前进行配置。此过程使用 CMake。取消链接正常configure
脚本,CMake 以您请求的任何格式生成构建文件以及各种*.inc
文件,以及llvm/include/Config/config.h
.
cmake
使用格式在命令行上 传递变量。以下变量是开发 LLVM 的人使用的一些常用选项。-D<variable name>=<value>
多变的 | 目的 |
---|---|
CMAKE_C_COMPILER | 告诉cmake 使用哪个 C 编译器。默认情况下,这将是 /usr/bin/cc。 |
CMAKE_CXX_COMPILER | 告诉cmake 使用哪个 C++ 编译器。默认情况下,这将是 /usr/bin/c++。 |
CMAKE_BUILD_TYPE | 告诉cmake 您尝试为其生成文件的构建类型。有效选项为 Debug、Release、RelWithDebInfo 和 MinSizeRel。默认为调试。 |
CMAKE_INSTALL_PREFIX | 指定运行构建文件的安装操作时要定位的安装目录。 |
PYTHON_EXECUTABLE | 通过将路径传递给 Python 解释器,强制 CMake 使用特定的 Python 版本。默认情况下,使用 PATH 中解释器的 Python 版本。 |
LLVM_TARGETS_TO_BUILD | 一个分号分隔的列表,控制将构建哪些目标并将其链接到 llvm。默认列表定义为 LLVM_ALL_TARGETS ,并且可以设置为包括树外目标。默认值包括: 。AArch64, AMDGPU, ARM, AVR, BPF, Hexagon, Lanai, Mips, MSP430, NVPTX, PowerPC, RISCV, Sparc, SystemZ, WebAssembly, X86, XCore |
LLVM_ENABLE_DOXYGEN | 从源代码构建基于 doxygen 的文档 默认情况下禁用此功能,因为它很慢并且会生成大量输出。 |
LLVM_ENABLE_PROJECTS | 以分号分隔的列表,选择要另外构建的其他 LLVM 子项目。(仅在使用并排项目布局时有效,例如通过 git)。默认列表为空。可以包括:clang、clang-tools-extra、cross-project-tests、flang、libc、libclc、lld、lldb、mlir、openmp、polly 或 pstl。 |
LLVM_ENABLE_RUNTIMES | 以分号分隔的列表,选择要构建的运行时。(仅在使用完整的 monorepo 布局时有效)。默认列表为空。可以包括:compiler-rt、libc、libcxx、libcxxabi、libunwind 或 openmp。 |
LLVM_ENABLE_SPHINX | 从源代码构建基于 sphinx 的文档。默认情况下禁用此功能,因为它很慢并且会生成大量输出。建议使用 Sphinx 1.5 或更高版本。 |
LLVM_BUILD_LLVM_DYLIB | 生成 libLLVM.so。这个库包含一组默认的 LLVM 组件,可以用LLVM_DYLIB_COMPONENTS . 默认包含 LLVM 的大部分内容,并在 tools/llvm-shlib/CMakelists.txt . 此选项在 Windows 上不可用。 |
LLVM_OPTIMIZED_TABLEGEN | 构建在 LLVM 构建期间使用的发布表生成。这可以显着加快调试构建。 |
要配置 LLVM,请执行以下步骤:
-
将目录更改为对象根目录:
% cd OBJ_ROOT
-
运行
cmake
:% cmake -G "Unix Makefiles" -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 定义了以下构建类型:
调试
这些构建是默认的。构建系统将编译未优化的工具和库,并启用调试信息和断言。
释放
对于这些构建,构建系统将编译启用优化的工具和库,而不生成调试信息。CMakes 默认优化级别是 -O3。这可以通过CMAKE_CXX_FLAGS_RELEASE
在 CMake 命令行上设置变量来配置。
RelWithDebInfo
这些构建在调试时很有用。它们生成带有调试信息的优化二进制文件。CMakes 默认优化级别是 -O2。这可以通过CMAKE_CXX_FLAGS_RELWITHDEBINFO
在 CMake 命令行上设置变量来配置。
配置好 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 可执行文件和库以托管在与构建它们的平台不同的平台上(Canadian Cross 构建)。为了生成用于交叉编译的构建文件,CMake 提供了一个变量,该变量CMAKE_TOOLCHAIN_FILE
可以定义编译器标志和在 CMake 测试操作期间使用的变量。
这种构建的结果是可执行文件不能在构建主机上运行,但可以在目标上执行。例如,以下 CMake 调用可以生成面向 iOS 的构建文件。这将适用于具有最新 Xcode 的 macOS:
% 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 构建时需要传递一些额外的标志。
查看How To Cross-Compile Clang/LLVM using Clang/LLVM和Clang 文档,了解有关如何交叉编译的更多信息。
LLVM 对象文件的位置
LLVM 构建系统能够在多个 LLVM 构建之间共享单个 LLVM 源树。因此,可以使用相同的源代码树为多个不同的平台或配置构建 LLVM。
-
将目录更改为 LLVM 对象文件所在的位置:
% cd OBJ_ROOT
-
运行
cmake
:% cmake -G "Unix Makefiles" SRC_ROOT
LLVM 构建将在OBJ_ROOT下创建一个与 LLVM 源树匹配的结构。在源文件存在于源树中的每一层,在OBJ_ROOTCMakeFiles
中都会有一个对应的目录。在该目录下还有另一个名称以 结尾的目录 ,您可以在该目录下找到每个源的目标文件。.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 源代码库的一个有用信息来源是https://llvm.org/doxygen/上提供的 LLVM doxygen文档 。下面简单介绍一下代码布局:
llvm/cmake
生成系统构建文件。
llvm/cmake/modules
为 llvm 用户定义的选项构建配置。检查编译器版本和链接器标志。
llvm/cmake/platforms
面向 MSVC 的 Android NDK、iOS 系统和非 Windows 主机的工具链配置。
llvm/examples
- 一些简单的示例展示了如何使用 LLVM 作为自定义语言的编译器 - 包括降低、优化和代码生成。
- Kaleidoscope 教程:Kaleidoscope 语言教程贯穿了一个不错的小编译器的实现,用于一种非平凡的语言,包括手写词法分析器、解析器、AST,以及使用 LLVM 的代码生成支持——静态(提前)和各种即时 (JIT) 编译的方法。 完整初学者的万花筒教程。
- BuildingAJIT:BuildingAJIT 教程示例,展示了 LLVM 的 ORC JIT API 如何与 LLVM 的其他部分交互。它还教授如何重新组合它们以构建适合您的用例的自定义 JIT。
llvm/include
从 LLVM 库导出的公共头文件。三个主要子目录:
llvm/include/llvm
所有 LLVM 特定的头文件,以及 LLVM 不同部分的子目录:Analysis
、CodeGen
、Target
、Transforms
等……
llvm/include/llvm/Support
LLVM 提供的通用支持库,但不一定特定于 LLVM。例如,一些 C++ STL 实用程序和命令行选项处理库在此处存储头文件。
llvm/include/llvm/Config
由cmake
. 它们包装“标准”UNIX 和 C 头文件。源代码可以包含这些头文件,它们会自动处理生成的条件#includescmake
。
llvm/lib
大多数源文件都在这里。通过将代码放入库中,LLVM 可以轻松地在工具之间共享代码。
llvm/lib/IR/
实现指令和基本块等核心类的核心 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 项目为 Go、OCaml 和 Python 提供语言绑定。
llvm/projects
项目严格来说不是 LLVM 的一部分,但随 LLVM 一起提供。这也是创建您自己的基于 LLVM 的项目的目录,这些项目利用 LLVM 构建系统。
llvm/test
对 LLVM 基础设施的功能和回归测试以及其他健全性检查。这些旨在快速运行并覆盖很多领域而不是详尽无遗。
test-suite
LLVM 的全面正确性、性能和基准测试套件。这是一个,因为它包含大量的各种许可证下的第三方代码。有关详细信息,请参阅测试指南文档。separate git repository <https://github.com/llvm/llvm-test-suite>
llvm/tools
由上述库构建的可执行文件构成了用户界面的主要部分。您始终可以通过键入来获得工具的帮助。下面简要介绍最重要的工具。更详细的信息在命令指南中。tool_name -help
bugpoint
bugpoint
用于调试优化过程或代码生成后端,方法是将给定的测试用例缩小到最小的通过和/或仍然导致问题的指令数量,无论是崩溃还是错误编译。有关使用bugpoint
. _
llvm-ar
存档器生成一个包含给定 LLVM 位码文件的存档,可选地带有一个索引以便更快地查找。
llvm-as
汇编器将人类可读的 LLVM 汇编转换为 LLVM 位码。
llvm-dis
反汇编程序将 LLVM 位码转换为人类可读的 LLVM 程序集。
llvm-link
llvm-link
毫不奇怪,将多个 LLVM 模块链接到一个程序中。
lli
lli
是LLVM解释器,可以直接执行LLVM bitcode(虽然很慢……)。对于支持它的架构(当前为 x86、Sparc 和 PowerPC),默认情况下,lli
它将作为即时编译器(如果已编译该功能),并且执行代码 的速度比解释器快得多。
llc
llc
是 LLVM 后端编译器,它将 LLVM 位码转换为本机代码汇编文件。
opt
opt
读取 LLVM 位码,将一系列 LLVM 应用于 LLVM 转换(在命令行中指定),并输出结果位码。' ' 是获取 LLVM 中可用的程序转换列表的好方法。opt -help
opt
还可以对输入的 LLVM 位码文件运行特定分析并打印结果。主要用于调试分析或熟悉分析的作用。
llvm/utils
用于处理 LLVM 源代码的实用程序;有些是构建过程的一部分,因为它们是基础设施部分的代码生成器。
codegen-diff
codegen-diff
找出 LLC 生成的代码和 LLI 生成的代码之间的差异。如果您正在调试其中一个,这很有用,假设另一个生成正确的输出。如需完整的用户手册,请运行.`perldoc codegen-diff'
emacs/
LLVM 程序集文件和 TableGen 描述文件的 Emacs 和 XEmacs 语法高亮显示。README
有关使用它们的信息,请参阅。
getsrcs.sh
查找并输出所有未生成的源文件,如果希望跨目录进行大量开发并且不想找到每个文件,这很有用。使用它的一种方法是运行,例如:从 LLVM 源代码树的顶部运行。xemacs `utils/getsources.sh`
llvmgrep
对 LLVM 中的每个源文件执行一次,并将在命令行中提供的正则表达式传递给它。这是在源库中搜索特定正则表达式的有效方法。egrep -H -n
llvmgrep
TableGen/
包含用于从常见的 TableGen 描述文件生成寄存器描述、指令集描述甚至汇编程序的工具。
vim/
用于 LLVM 程序集文件和 TableGen 描述文件的 vim 语法高亮。请参阅README
如何使用它们。
使用 LLVM 工具链的示例
本节给出了一个将 LLVM 与 Clang 前端一起使用的示例。
clang 示例
-
首先,创建一个简单的 C 文件,将其命名为“hello.c”:
#include <stdio.h> int main() { printf("hello world\n"); return 0; }
-
接下来,将 C 文件编译为本机可执行文件:
% clang hello.c -o hello
笔记
默认情况下,Clang 就像 GCC 一样工作。标准的 -S 和 -c 参数照常工作(分别生成本机 .s 或 .o 文件)。
-
接下来,将 C 文件编译成 LLVM 位码文件:
% clang -O3 -emit-llvm hello.c -c -o hello.bc
-emit-llvm 选项可以与 -S 或 -c 选项一起使用来为代码发出 LLVM
.ll
或.bc
文件(分别)。这允许您在位码文件上使用标准 LLVM 工具。 -
以两种形式运行程序。要运行程序,请使用:
% ./hello
和
% lli hello.bc
第二个示例展示了如何调用 LLVM JIT lli。
-
使用该
llvm-dis
实用程序查看 LLVM 汇编代码:% llvm-dis < hello.bc | less
-
使用 LLC 代码生成器将程序编译为本机程序集:
% llc hello.bc -o hello.s
-
将本机汇编语言文件组装成程序:
% /opt/SUNWspro/bin/cc -xarch=v9 hello.s -o hello.native # On Solaris % gcc hello.s -o hello.native # On others
-
执行本机代码程序:
% ./hello.native
请注意,使用CLANG将直接编译为本机代码(即,
-emit-llvm
未存在选项时)为您执行步骤6/7/8。
常见问题
如果您在构建或使用 LLVM 时遇到问题,或者您对 LLVM 有任何其他一般性问题,请参阅常见问题页面。
如果您遇到内存和构建时间有限的问题,请尝试使用 ninja 而不是 make 构建。请考虑使用 cmake 配置以下选项:
-G Ninja 设置此选项将允许您使用 ninja 而不是 make 进行构建。使用 ninja 构建显着缩短了构建时间,尤其是增量构建,并提高了内存使用率。
-DLLVM_USE_LINKER 将此选项设置为 lld 将显着减少 LLVM 可执行文件在基于 ELF 的平台(例如 Linux)上的链接时间。如果您是第一次构建 LLVM,并且 lld 不能作为二进制包提供给您,那么您可能希望使用黄金链接器作为 GNU ld 的更快替代方案。
-DCMAKE_BUILD_TYPE
- 调试——这是默认的构建类型。这会在编译 LLVM 时禁用优化并启用调试信息。在基于 ELF 的平台(例如 Linux)上,链接调试信息可能会消耗大量内存。
- 发布 - 打开优化并禁用调试信息。将 Release 构建类型与 -DLLVM_ENABLE_ASSERTIONS=ON 相结合可能是开发期间速度和可调试性之间的良好折衷,特别是对于运行测试套件。
-DLLVM_ENABLE_ASSERTIONS 对于调试版本,此选项默认为 ON,对于发布版本,默认为 OFF。如前一个选项所述,使用 Release 构建类型并启用断言可能是使用 Debug 构建类型的一个很好的替代方案。
-DLLVM_PARALLEL_LINK_JOBS 将此设置为您希望同时运行的作业数。这类似于与 make 一起使用的 -j 选项,但仅适用于链接作业。此选项只能与忍者一起使用。您可能希望使用非常少的作业,因为这将大大减少构建过程中使用的内存量。如果您的内存有限,您可能希望将其设置为 1。
-DLLVM_TARGETS_TO_BUILD 将此设置为等于您希望构建的目标。您可能希望将其设置为 X86;但是,您会在 llvm-project/llvm/lib/Target 目录中找到完整的目标列表。
-DLLVM_OPTIMIZED_TABLEGEN 将此设置为 ON 以在构建期间生成完全优化的 tablegen。这将显着缩短您的构建时间。这仅在您使用 Debug 构建类型时才有用。
-DLLVM_ENABLE_PROJECTS 将此设置为您希望编译的项目(例如clang、lld 等)。如果编译多个项目,请用分号分隔项目。如果您遇到分号问题,请尝试用单引号括起来。
-DLLVM_ENABLE_RUNTIMES 将此设置为您希望编译的运行时(例如 libcxx、libcxxabi 等)。如果编译多个运行时,请用分号分隔各项。如果您遇到分号问题,请尝试用单引号括起来。
-DCLANG_ENABLE_STATIC_ANALYZER 如果您不需要 clang 静态分析器,请将此选项设置为 OFF。这应该会稍微缩短您的构建时间。
-DLLVM_USE_SPLIT_DWARF 如果您需要调试构建,请考虑将其设置为 ON,因为这将减轻链接器上的内存压力。这将使链接更快,因为二进制文件不包含任何调试信息;但是,这将以 DWARF 对象文件(扩展名为 .dwo)的形式生成调试信息。这仅适用于使用 ELF 的主机平台,例如 Linux。
链接
本文档只是介绍如何使用 LLVM 做一些简单的事情……还有很多更有趣和更复杂的事情你可以做,但这里没有记录(但如果你想写一些东西,我们很乐意接受补丁向上!)。有关 LLVM 的更多信息,请查看: