开始使用 LLVM 系统

1. 概述

欢迎来到 LLVM 项目!在开始之前,你首先需要知道一些基本的信息。

首先,LLVM 项目有多个组件。该项目的核心本身称为“LLVM”。它包含处理中间表示(intermediate representation,IR)并将其转换为目标文件所需的所有工具、库和头文件,例如:汇编器(assembler)、反汇编器(disassembler)、字节码分析器(bitcode analyzer)和字节码优化器(bitcode optimizer)。它还包含基本的回归测试。

另一个重要的部分是 Clang FrontEnd。该组件将 C、C++、Objective C 和 Objective C++ 代码编译成 LLVM 字节码,然后将字节码编译成目标文件。

还有一些其他的组件:libc++ C++标准库LLD链接器等等。

2. 快速入门(总结)

LLVM 入门文档可能已经过时。因此,Clang 入门页面可能也是一个很好的开始。
下面是获取和运行 LLVM 的简要介绍:

  1. 阅读文档。

  2. 阅读文档。

  3. 阅读文档。重要的事情说三次~~~

  4. 签出 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
    
  5. 配置、构建 LLVM 和 Clang:

    cd llvm-project
    mkdir build
    cd build
    cmake -G <generator> [options] ../llvm
    

    一些常见的generator有:

    • Ninja —— 用于生成 Ninja 构建文件。大多数 llvm 开发人员使用Ninja。
    • Unix Makefiles —— 用于生成与 make 兼容的并行 Makefiles。
    • Visual Studio —— 用于生成 Visual Studio 项目和解决方案。
    • Xcode —— 用于生成 Xcode 项目。

    一些常见的options有:

    • -DLLVM_ENABLE_PROJECTS='...' —— 您想要额外构建的 LLVM 子项目列表,使用分号分隔。可以包括以下的任何子项目:clangclang-tools-extralibcxxlibcxxabilibunwindlldbcompiler-rtlldpolly、或 debuginfo-test

      例如,要构建 LLVMClanglibcxxlibcxxabi,使用:

      -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi"
      
    • -DCMAKE_INSTALL_PREFIX=directory —— directory指定您要安装 LLVM 工具和库的完整路径名(默认 /usr/local)。

    • -DCMAKE_BUILD_TYPE=type —— type的有效选项有 DebugReleaseRelWithDebInfoMinSizeRel。默认是 Debug

    • -DLLVM_ENABLE_ASSERTIONS=On —— 启用断言检查进行编译(对于 Debug 构建,默认为Yes;对于所有其他构建类型,默认为No)。

  6. 运行您选择的构建工具:

    • 默认目标(即 ninjamake)将构建 LLVM 的所有组件。
    • check-all 目标(即 ninja check-all)将运行回归测试,以确保一切正常工作。
    • CMake 将为每个工具和库生成构建目标,而大多数 LLVM 子项目将生成它们自己的 check-<project> 目标。
    • 运行一个串行构建将很慢。确保您运行一个并行构建。这在 Ninja 中已经默认完成了;对于 make,使用 make -j NNN(取适当的值给 NNN,例如 CPU 的数量)。
  7. 有关更多信息,请参见 CMake

  8. 如果您得到一个“内部编译器错误(internal compiler error,ICE)”或测试失败,请参见 第3.3节 宿主 C++ 工具链,包括编译器和标准库

有关配置和编译 LLVM 的详细信息,请参阅 第4章 开始使用LLVM。了解源代码树的布局,请参阅 第5章 目录布局

3. 需求

在开始使用 LLVM 系统之前,请检查下面给出的需求。这可能会为您节省一些麻烦,因为您可以提前知道需要什么硬件和软件。

3.1 硬件

现已知,LLVM 可以在以下主机平台上工作:

操作系统架构编译器
Linuxx86(1)GCC, Clang
Linuxamd64GCC, Clang
LinuxARMGCC, Clang
LinuxPowerPCGCC, Clang
SolarisV9 (Ultrasparc)GCC
FreeBSDx86(1)GCC, Clang
FreeBSDamd64GCC, Clang
NetBSDx861GCC, Clang
NetBSDamd64GCC, Clang
macOS(2)PowerPCGCC
macOSx86GCC, Clang
Cygwin/Win32x86(1,3)GCC
Windowsx861Visual Studio
Windowsx64 x86-64Visual Studio

注意
(1) 支持奔腾处理器及以上的代码生成
(2) 只支持32位 ABI 的代码生成
(3) 要在基于 Win32 的系统上使用 LLVM 模块,可以使用 -DBUILD_SHARED_LIBS=On 来配置 LLVM。

注意,Debug 构建需要大量的时间和磁盘空间。一个仅有 LLVM 的构建将需要大约 1-3GB 的空间;而完整的 LLVM 和 Clang 构建需要大约 15-20GB 的磁盘空间。确切的空间需求会因系统而异。(它之所以这么大,是因为包含了所有的调试信息以及库被静态地链接到多个工具中)。

如果空间有限,则只能构建选定的工具或选定的目标。发行版构建所需的空间要小得多。

LLVM 套件可能可以在其他平台上编译,但不能保证这样做。如果编译成功,LLVM 实用程序应该能够汇编、反汇编、分析和优化 LLVM 字节码。代码生成也应该能够工作,尽管生成的本地代码可能无法在您的平台上工作。

3.2 软件

编译 LLVM 需要安装几个软件包。下表列出了这些所需的包。Package 列是 LLVM 所依赖的软件包的常用名称。Version 列提供包的“已知工作”版本。Notes列描述了LLVM如何使用这个包,并提供了其他细节。

PackageVersionNotes
GNU Make3.79, 3.79.1Makefile/build processor
GCC>=5.1.0C/C++ compiler(1)
python>=2.7Automated test suite(2)
zlib>=1.2.3.4Compression library(3)

注意
(1) 只需要 C 和 C++ 语言,不需要为 LLVM 构建其他语言。有关特定版本信息,请参见下面。
(2) 只有希望在 llvm/test 目录中运行自动化测试套件时才需要。
(3) 可选,向选定的 LLVM 工具添加压缩/解压功能。

此外,您的编译主机应该具有通常过多的 Unix 实用程序。具体地说:

  • ar —— 归档库构建器
  • bzip2 —— 用于分发版生成的bzip2命令
  • bunzip2 —— 用于分发版检查的bunzip2命令
  • chmod —— 更改文件的权限
  • cat —— 输出连接实用程序
  • cp —— 复制文件
  • date —— 打印当前日期/时间
  • echo —— 打印到标准输出
  • egrep —— 扩展正则表达式搜索工具
  • find —— 在文件系统中查找文件/目录
  • grep —— 正则表达式搜索工具
  • gzip —— 用于分发版生成的gzip命令
  • gunzip —— 用于分发版检查的gunzip命令
  • install —— 安装目录/文件
  • mkdir —— 创建一个目录
  • mv —— 移动(重命名)文件
  • ranlib —— 用于存档库的符号表生成器
  • rm —— remove (delete)文件和目录
  • sed —— 用于转换输出的sed流编辑器
  • sh —— 用于生成构建脚本 - Bourne shell
  • tar —— 磁带存档,用于分发版生成
  • test —— 在文件系统中测试东西
  • unzip —— 用于分发版检查的unzip命令
  • zip —— 用于分发版生成的zip命令
3.3 宿主 C++ 工具链,包括编译器和标准库

LLVM 对宿主 C++ 编译器的要求非常高,因此很容易暴露编译器中的bug。我们还试图密切关注 C++ 语言和库的改进和开发。因此,为了构建 LLVM,我们需要一个现代的宿主 C++ 工具链,包括编译器和标准库。

LLVM 是使用编码标准中记录的 C++ 子集编写的。为了加强这一语言版本,我们检查了最流行的宿主工具链,以指定我们的构建系统支持的最低版本:

  • Clang 3.5
  • Apple Clang 6.0
  • GCC 5.1
  • Visual Studio 2017

当我们转换到上面列出的新编译器版本时,下面的版本当前是软错误。目前已知 LLVM 代码库可以使用以下编译器正确编译,不过这一点在不久的将来会发生变化:

  • Clang 3.1
  • Apple Clang 3.1
  • GCC 4.8
  • Visual Studio 2015 (Update 3)

任何比这些工具链更老的工具都可能可以工作,但是需要强制构建系统使用一个特殊的选项,而且实际上并不是一个支持的宿主平台。还要注意,这些编译器的旧版本经常崩溃或错误编译LLVM。
对于不太常用的宿主工具链,如 ICCxlC,请注意,可能需要一个非常新的版本来支持 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 时导致大量链接时间(分钟而不是秒)的 bug。我们建议升级到更新的版本(2.17.50.0.4或更高版本)。
  • GNU Binutils 2.19.1 Gold
    这个版本的 Gold 包含一个 bug,它在使用位置无关代码构建 LLVM 时导致间歇性故障。症状是关于循环依赖关系的错误。我们建议升级到更新版本的 Gold。
3.3.1 获得一个现代的宿主 C++ 工具链

本节主要适用于 Linux 和较老的 BSDs。在 macOS 上,您应该有一个足够现代的 Xcode,否则您可能需要升级,直到您这样做。Windows没有“系统编译器”,因此必须安装 Visual Studio 2015 或 mingw64 的最新版本。FreeBSD 10.0 和更新的版本有一个现代化的 Clang 作为系统编译器。

然而,一些 Linux 发行版和一些其他的或更老的 BSDs 有时有非常老的 GCC 版本。这些步骤试图帮助您升级编译器,即使是在这样的系统上。但是,如果可能的话,我们鼓励您使用发行版的最新版本,并使用符合这些要求的现代系统编译器。注意,安装 Clang 和 libc++ 的早期版本作为宿主编译器是很有诱惑力的,但是 libc++ 直到最近才经过很好的测试或安装以在 Linux 上构建。因此,本指南建议只使用 libstdc++ 和现代 GCC 作为引导程序中的初始主机,然后使用 Clang(可能还有 libc++)

第一步是安装一个最新的 GCC 工具链。用户在版本要求上遇到困难的最常见的发行版是 Ubuntu Precise,12.04 LTS。对于这个发行版,一个简单的选择是安装工具链测试 PPA 并使用它安装现代 GCC。在 ask ubuntu stack exchange 和一个 github gist 上有一个关于这个的很好的讨论。然而,并不是所有用户都可以使用 PPAs,而且还有许多其他发行版,所以从源代码构建和安装 GCC 可能是必要的(或者仅仅是有用的,如果您在这里进行编译器开发的话)。现在做起来也很容易。

安装 GCC 5.1.0 的简单步骤:

% gcc_version=5.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++ 的新版本不在系统库搜索路径上,所以需要传递额外的链接器 flags,以便在链接时(-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 链接器标志。

构建 Clang 时,需要让它访问现代 C++ 标准库,以便在引导程序中使用它作为新主机的一部分。有两种简单的方法可以做到这一点,要么与 Clang 一起构建(并安装) libc++,然后使用 -stdlib=libc++ 编译和链接标志一起使用它,要么将 Clang 安装到与 GCC 相同的前缀中(上面的$HOME/toolchains)。Clang 将在它自己的 libstdc++ prefix中查找,如果找到就使用它。您还可以为 Clang 添加一个显式前缀,以便使用 --gcc-toolchain=/opt/my/gcc/prefix 标志查找 GCC 工具链,在使用刚刚构建的 Clang 引导时,将其传递给编译命令和链接命令。

4. 开始使用 LLVM

本指南的其余部分旨在帮助您启动和运行 LLVM,并提供有关 LLVM 环境的一些基本信息。

本指南后面的部分描述了 LLVM 源代码树的总体布局,一个使用 LLVM 工具链的简单示例,并且第8章 Link提供了有关 LLVM 的更多信息或通过电子邮件获得帮助。

4.1 术语和符号

在本手册中,以下名称用于表示特定于本地系统和工作环境的路径。这些不是您需要设置的环境变量,而是下面这个文档其余部分中使用的字符串。在下面的任何示例中,只需用本地系统上适当的路径名替换这些名称。所有这些路径都是绝对的:

  • SRC_ROOT:这是 LLVM 源代码树的顶层目录。
  • OBJ_ROOT:这是 LLVM 目标文件树的顶层目录(即对象文件和编译程序将放在其中的树。它可能与 SRC_ROOT 相同)。
4.2 解压 LLVM 存档

如果您拥有 LLVM 发行版,则需要在开始编译它之前将其解压。LLVM 作为许多不同的子项目分发。每一个都有自己的下载,这是一个TAR存档文件,用 gzip 程序压缩。
文件如下,x.y 标记版本号:

  • llvm-x.y.tar.gz:LLVM 库和工具的源代码发布。
  • cfe-x.y.tar.gz:Clang 前端的源代码发布。
4.3 从 Git 签出 LLVM

您还可以从 Git 签出 LLVM 的源代码。虽然 LLVM 项目的官方源代码存储库是 Subversion,但是我们正在迁移到 git 的过程中。我们目前建议所有开发人员在日常开发中使用 Git。

注意
在我们正确调整 .gitattribute 设置之后,将来不应该需要传递 --config core.autocrlf=false;但是在撰写本文时,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 不同,tarball将每个子项目包含在单独的文件中,git 存储库将所有项目都包含在一起。

如果您想获得一个特定的版本(与最近的版本相反),您可以在克隆存储库之后签出一个tag。例如,在上面命令创建的 llvm-project 目录中,git checkout llvmorg-6.0.1。使用 git tag -l 列出所有这些。

4.3.1 发送补丁

请阅读开发人员策略
我们目前不接受 github pull 请求,所以您需要通过电子邮件向 llvm-commit 发送补丁,或者最好通过 Phabricator 发送补丁。
您通常希望确保您的分支有一个单独的提交,与您希望发送的评审相对应,与上游 origin/master 分支保持最新,并且不包含合并。有了这些之后,可以使用 git showgit format-patch 来输出差异,并将其附加到一个 Phabricator 评审(或电子邮件消息)中。
然而,使用 “Arcanist” 工具通常更容易。在安装 arcanist 后,你可以上传最新的提交使用:

% arc diff HEAD~1

另外,在发送补丁进行检查之前,请确保它的格式正确。为此,我们使用了 clang-format,它通过 git-clang-format 脚本集成了 git。在某些系统上,它可能已经安装(或者可以通过包管理器安装)。如果是的话,你可以简单地运行它 —— 下面的命令将只格式化最近提交时更改的代码:

% git clang-format HEAD~1

注意,这将修改文件,但不会提交它们 —— 您可能想要运行:

% git commit --amend -a

以便让所有挂起的更改更新最后一次提交。

注意
如果您的系统上还没有安装clang-formatgit clang-format,那么 clang-format 二进制文件将与 clang 一起构建,git 集成可以从 clang/tools/clang-format/git-clang-format 运行。

4.3.2 让开发人员从 Git 提交更改

llvm/utils/git-svn/git-llvm 中提供了一个帮助脚本。将其添加到路径后,可以使用 git llvm push 向上推送提交的更改。虽然这创建了一个 Subversion 签出并将其打补丁,但它不需要您与它进行交互。

% export PATH=$PATH:$TOP_LEVEL_DIR/llvm-project/llvm/utils/git-svn/
% git llvm push

在 push subversion 几分钟后,svn 提交将被转换回 Git 提交,并进入正式的 Git 存储库。此时,git pull应该在提交更改时返回更改。
您可能希望 git pull --rebase 将正式的git提交下载回存储库。每个提交的 SVN 修订号可以在提交消息的末尾找到,例如 llvm-svn: 350914
您还可能发现 -n 标志很有用,比如 git llvm push -n。这将运行 committing _without_ actually 执行提交的所有步骤,并告诉您它将执行什么操作。如果你不确定是否会发生正确的事情,这是很有用的。

4.3.3 使用 Git 时还原更改

如果您正在使用 Git,并且需要恢复补丁,那么 Git 需要提供 commit hash,而不是 svn 修订。为了使事情变得更简单,您可以使用 `git llvm revert`` 来恢复 SVN 修订或 Git hash。

此外,您可以先使用 git llvm revert -n 运行来打印将要运行哪些 git 命令,而不需要做任何操作。

运行 git llvm revert 只会还原本地存储库中的内容。要将恢复推到上游,您仍然需要像前面描述的那样运行 git llvm push

% git llvm revert rNNNNNN       # Revert by SVN id
% git llvm revert abcdef123456  # Revert by Git commit hash
% git llvm revert -n rNNNNNN    # Print the commands without doing anything
4.3.4 通过 SVN 签出(不推荐)

在完全迁移到 Git 之前,您还可以从官方 Subversion 存储库中获得代码的新副本。

  • cd where-you-want-llvm-to-live
  • 只读:svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
  • 读写:svn co https://user@llvm.org/svn/llvm-project/llvm/trunk llvm

这将在当前目录中创建一个 ‘llvm’ 目录,并使用 LLVM 源代码、Makefiles、测试目录和文档文件的本地副本完全填充它。

如果您想获得一个特定的版本(与最近的版本相反),您可以从 “tags” 目录(而不是 “trunk” 目录)查看它。以下版本位于 “tags” 目录的以下子目录中:

  • Release 3.5.0 及以后版本:RELEASE_350/final 等等
  • Release 2.9 到 3.4:RELEASE_29/final 等等
  • Release 1.1 到 2.8:RELEASE_11 等等
  • Release 1.0: RELEASE_1
4.4 本地 LLVM 配置

签出存储库后,必须在构建前配置 LLVM 套件源代码。这个过程使用 CMake。取消到常规 configure 脚本的链接,CMake 以您请求的任何格式以及各种*.inc文件、和llvm/include/Config/config.h生成构建文件。
变量在命令行上使用 -D<variable name>=<value> 传递给 cmake。以下变量是开发 LLVM 的人员使用的一些常见选项。

变量目的
CMAKE_C_COMPILER告诉 cmake 使用哪个 C 编译器。默认情况下,这是 /usr/bin/cc
CMAKE_CXX_COMPILER告诉 cmake 使用哪个 C++ 编译器。默认情况下,这是 /usr/bin/c++
CMAKE_BUILD_TYPE告诉 cmake 您要为哪种类型的构建生成文件。有效的选项有 Debug、Release、RelWithDebInfo 和 MinSizeRel。默认是 Debug。
CMAKE_INSTALL_PREFIX在运行构建文件的 install 操作时指定目标的 install 目录。
LLVM_TARGETS_TO_BUILD构建一个分号分隔的列表,控制将构建哪些目标并将其链接到 llvm。默认列表定义为LLVM_ALL_TARGETS,可以将其设置为包含树外目标。默认值包括:AArch64、AMDGPU、ARM、BPF、Hexagon、Mips、MSP430、NVPTX、PowerPC、Sparc、SystemZ、X86、XCore。
LLVM_ENABLE_DOXYGEN从源代码构建基于doxygen的文档,这在默认情况下是禁用的,因为它很慢,并且生成了很多输出。
LLVM_ENABLE_PROJECTS一个分号分隔的列表,选择要额外构建的其他LLVM子项目。(只有在使用并行项目布局时才有效,例如通过git)。默认列表为空。可以包括:clang、libcxx、libcxxabi、libunwind、lldb、编译器-rt、lld、polly或debugin -test。
LLVM_ENABLE_SPHINX从源代码构建基于sphinx的文档。这在默认情况下是禁用的,因为它很慢,而且会生成很多输出。建议使用Sphinx 1.5或更高版本。
LLVM_BUILD_LLVM_DYLIB生成libLLVM.so。这个库包含一组可以用LLVM_DYLIB_COMPONENTS重写的默认LLVM组件。默认值包含大部分LLVM,在tools/ LLVM -shlib/CMakelists.txt中定义。
LLVM_OPTIMIZED_TABLEGEN构建一个在LLVM构建期间使用的发行版tablegen。这可以显著加快调试构建。

要配置LLVM,请遵循以下步骤:

  1. 将目录更改为目标文件根目录:
    % cd OBJ_ROOT
    
  2. 运行cmake:
    % cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/install/path
      [other options] SRC_ROOT
    
4.5 编译 LLVM 套件源代码

与 autotools 不同,使用 CMake 时您的构建类型是在 configuration 中定义的。如果您想更改构建类型,可以通过以下调用重新运行 cmake:

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

在运行之间,CMake 保存所有选项的值集。CMake 定义了以下构建类型:

  • Debug
    这个构建是默认的。构建系统将不经过优化地编译工具和库,并启用调试信息和断言。
  • Release
    对于这些构建,构建系统将编译启用了优化的工具和库,而不会生成调试信息。cmake默认优化级别为-O3。这可以通过在CMake命令行上设置CMAKE_CXX_FLAGS_RELEASE变量来配置。
  • RelWithDebInfo
    这些构建在调试时非常有用。它们生成带有调试信息的优化二进制文件。默认优化级别为-O2。这可以通过在CMake命令行上设置CMAKE_CXX_FLAGS_RELWITHDEBINFO变量来配置。

一旦配置好LLVM,就可以通过进入 OBJ_ROOT 目录并发出以下命令来构建它:

% make

如果构建失败,请检查这里,看看您是否使用了已知不编译 LLVM 的 GCC 版本。

如果您的计算机中有多个处理器,您可能希望使用 GNU Make 提供的一些并行构建选项。例如,您可以使用以下命令:

% make -j2

在使用 LLVM 源代码时,有几个特别的目标非常有用:

  • make clean
    删除构建生成的所有文件。这包括目标文件、生成的 C/C++ 文件、库和可执行文件。
  • make install
    $PREFIX 下的一个层次结构中安装 LLVM 头文件、库、工具和文档,$PREFIXCMAKE_INSTALL_PREFIX 指定,默认值为 /usr/local
  • make docs-llvm-html
    如果配置为 -DLLVM_ENABLE_SPHINX=On ,这将在 OBJ_ROOT/docs/html 中生成一个目录,其中包含 html 格式的文档。
4.6 交叉编译 LLVM

可以交叉编译 LLVM 本身。也就是说,您可以创建 LLVM 可执行程序和库,并将其托管在不同于构建它们的平台(一个Canadian交叉构建)上。要生成用于交叉编译的构建文件,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 构建时需要传递一些额外的 flags。
查看如何使用 Clang/LLVM 交叉编译 Clang/LLVM关于如何交叉编译的Clang文档,了解有关交叉编译的更多信息。

4.7 LLVM 对象文件的位置

LLVM 构建系统能够在多个 LLVM 构建中共享一个 LLVM 源代码树。因此,可以使用相同的源代码树为几个不同的平台或配置构建 LLVM。

  • 将目录更改为 LLVM 目标文件应该位于的位置:
    % cd OBJ_ROOT
    
  • 运行 cmake:
    % cmake -G "Unix Makefiles" 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
4.8 可选配置项

如果您运行在支持 binfmt_misc 模块的 Linux 系统上,并且您在系统上具有根访问权限,那么您可以将您的系统设置为直接执行 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'

5. 目录布局

关于 LLVM 源代码库的一个有用信息来源是 LLVM doxygen 文档,可以从 http://llvm.org/doxygen/ 获得。下面是对代码布局的简要介绍:

5.1 llvm/examples

使用 LLVM IR 和 JIT 的简单示例。

5.2 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 生成的条件 #include
5.3 llvm/lib

大多数源文件都在这里。通过将代码放入库中,LLVM 使得在工具之间共享代码变得很容易。

  • llvm/lib/IR/
    核心 LLVM 源文件,实现核心类,如 InstructionBasicBlock
  • llvm/lib/AsmParser/
    LLVM 汇编语言解析器库的源代码。
  • llvm/lib/Bitcode/
    用于读取和写入字节码的代码。
  • llvm/lib/Analysis/
    各种程序分析,如调用图、归纳变量、自然循环识别等。
  • llvm/lib/Transforms/
    IR-to-IR 程序转换,如主动死代码消除、稀疏条件常数传播、内联、循环不变代码运动、死全局消除等。
  • llvm/lib/Target/
    描述用于代码生成的目标体系结构的文件。例如,llvm/lib/Target/X86 包含X86机器描述。
  • llvm/lib/CodeGen/
    代码生成器的主要部分:指令选择器、指令调度和寄存器分配。
  • llvm/lib/MC/
    (FIXME: T.B.D.) ….?
  • llvm/lib/ExecutionEngine/
    用于在解释和 JIT 编译的场景中在运行时直接执行字节码的库。
  • llvm/lib/Support/
    对应于 llvm/include/ADT/llvm/include/Support/ 中的头文件的源代码。
5.4 llvm/projects

Projects 不是严格意义上的 LLVM 的一部分,而是随 LLVM 一起发布的。这也是创建您自己的基于 LLVM 的项目的目录,这些项目利用 LLVM 构建系统。

5.5 llvm/test

特性和回归测试以及对 LLVM 基础设施的其他完整性检查。它们的目的是快速运行并覆盖很多领域,而不是面面俱到。

5.6 test-suite

为 LLVM 提供全面的正确性、性能和基准测试套件。这来自于一个单独的 git 存储库https://github.com/llvm/llvm-test-suite,因为它包含了大量第三方代码,使用各种许可证。有关详细信息,请参阅测试指南文档。

5.7 llvm/tools

由上述库构建的可执行程序,构成用户接口的主要部分。您总是可以通过键入 tool_name -help 来获得工具的帮助。下面是对最重要的工具的简要介绍。更详细的信息在命令指南中。

  • bugpoint
    bugpoint 用于调试优化传递或代码生成后端,方法是将给定的测试用例缩小到仍然会导致问题(无论是崩溃还是错误编译)的最小传递和/或指令数量。有关使用 bugpoint 的更多信息,请参见 HowToSubmitABug.html
  • llvm-ar
    归档器生成一个包含给定 LLVM 字节码文件的归档文件,可以选择使用索引来加快查找速度。
  • llvm-as
    汇编程序将人类可读的 LLVM assembly 转换为LLVM字节码。
  • llvm-dis
    反汇编程序将 LLVM 字节码转换为人类可读的 LLVM assembly。
  • 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 中可用的程序转换列表的好方法。
    opt 还可以对输入 LLVM 字节码文件运行特定的分析并打印结果。主要用于调试分析,或者熟悉分析的功能。
5.8 llvm/utils

使用 LLVM 源代码的实用程;有些是构建过程的一部分,因为它们是基础设施部分的代码生成器。

  • codegen-diff
    codegen-diff 发现 LLC 生成的代码和 LLI 生成的代码之间的差异。如果您正在调试其中一个,假设另一个生成正确的输出,那么这将非常有用。要获得完整的用户手册,请运行 ``perldoc codegen-diff’`。
  • emacs/
    EmacsXEmacs 语法高亮显示 LLVM assembly 文件和 TableGen 描述文件。有关使用它们的信息,请参阅 README 文件。
  • getsrcs.sh
    查找和输出所有非生成的源文件,如果希望跨目录进行大量开发而不想查找每个文件,那么这非常有用。使用它的一种方法是运行,例如:xemacs 'utils/getsources.sh',从 LLVM 源代码树的顶部。
  • llvmgrep
    对 LLVM 中的每个源文件执行一个 egrep -H -n,并将 llvmgrep 命令行上提供的正则表达式传递给它。这是搜索特定正则表达式的源库的一种有效方法。
  • `TableGen
    包含用于从公共 TableGen 描述文件生成寄存器描述、指令集描述甚至汇编器的工具。
  • vim/
    vim 语法高亮显示 LLVM assembly 文件和 TableGen 描述文件。请参阅 README 文件了解如何使用它们。

6. 一个使用 LLVM 工具链的例子

本节给出一个使用带 Clang 前端的 LLVM 的示例。

6.1 使用 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 assembly 代码:

    % 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步骤。

7. 常见问题

如果您在构建或使用 LLVM 时遇到问题,或者对 LLVM 有任何其他一般问题,请参阅常见问题页面。

8. 链接

本文档只是介绍如何使用 LLVM 来做一些简单的事情……还有许多有趣而复杂的事情您可以做,但这里没有文档说明(但是如果您想编写一些东西,我们很乐意接受一个补丁!)有关 LLVM 的更多信息,请查看:

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值