【LLVM】Getting Started with the LLVM System(Part 2)

LLVM入门

本指南的其余部分旨在帮助您启动并运行LLVM,并为您提供有关LLVM环境的一些基本信息。
本指南后面的部分介绍了LLVM源代码树的总体布局、一个使用LLVM工具链的简单示例,以及查找有关LLVM的更多信息或通过电子邮件获取帮助的链接。

术语和符号

在本手册中,以下名称用于表示特定于本地系统和工作环境的路径。这些不是您需要设置的环境变量,而只是本文档其余部分中使用的字符串。在下面的任何一个示例中,只需在本地系统上将这些名称替换为相应的路径名即可。所有这些路径都是绝对的:
SRC_ROOT: 这是LLVM源代码树的顶级目录。
OBJ_ROOT: 这是LLVM对象树的顶层目录(即对象文件和编译程序所在的树。它可以与SRC_ROOT相同)。

解压LLVM包

如果您有LLVM包,则需要先将其解压缩,然后才能开始编译。LLVM中包含多个子项目,每个项目都有独立的压缩包。
文件如下,x.y标记版本号:
llvm-x.y.tar.gz LLVM库和工具的源码压缩包。
cfe-x.y.tar.gz Clang前端源码压缩包。

用git获取代码

可以用Git来获取LLVM的源码。
简单命令:

% 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和所有相关子项目的所有源代码、测试目录和文档文件的本地副本完全填充该目录。请注意,与tarballs不同,tarballs将每个子项目包含在一个单独的文件中,git存储库将所有项目都包含在一起。
如果您想要获得一个特定的版本(而不是最新的版本),您可以在克隆存储库之后加上一个一个标记。例如,在上面命令创建llvm-project之后加上git checkout llvmrg-6.0.1。使用git tag -l列出所有这些。

发送补丁

请阅读开发人员政策
我们目前不接受github pull请求,因此您需要通过给llvm-commits发电子邮件,或者最好通过Phabricator发送补丁。
通常,与发送的评审信息对应的代码会有一次提交,并更新到origin/main分支,但是不包吃住合并。一旦你做到了这一点,你就可以开始Phabricator审查(或者使用git show或git格式补丁来输出差异,并将其附加到电子邮件中)。
然而,使用“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。某些系统上,可能已经安装(或可以通过包管理器安装)了clang-format。如果是这样,您可以简单地运行它–下面的命令将只格式化在最近的提交中更改的代码:

% git clang-format HEAD~1

请注意,这会修改文件,但不会提交文件。可以使用以下命令将所有修改提交:

% git commit --amend -a

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

用git提交修改

一旦一个补丁审查完毕,你应该rebase它,在本地重新测试,并将修改提交到LLVM的主干。如果您拥有所需的访问权限,可以使用git push来完成。
下面是一个使用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项目repo配置为拒绝包含合并的推送,因此需要上面的git rebase步骤。

Git pre-push hook

我们提供了一个可选的pre-push hook,它可以对您要推送的修订版运行一些健全性检查,并询问您是否同时推送多个提交。可以通过从存储库根目录运行(在Unix系统上)以下命令进行设置:

% ln -sf ../../llvm/utils/git/pre-push.py .git/hooks/pre-push

Bisecting提交

可以通过官网文档学习怎么在LLVM中使用git bisect。

回退修改

使用git还原更改时,默认消息将显示“This Revertes commit XYZ”。请在提交消息的末尾保留这一点,但在其前面添加一些详细信息,说明提交被还原的原因。一个简短的解释和/或到机器人程序的链接就足以证明问题。

LLVM本地配置

获取代码之后,必须要用CMake先对LLVM进行一些配置,才能构建。CMake将生成*.inc 和llvm/include/Config/config.h构建文件。
使用-D=将变量会给CMake。以下变量是开发LLVM的人员使用的一些常见选项:
在这里插入图片描述
要配置LLVM,请按照下列步骤操作:

  1. 切换到对象根目录:
% cd OBJ_ROOT
  1. 执行CMake命令:
% cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/install/path
  [other options] SRC_ROOT

编译LLVM源码

CMake可以通过以下命令在配置时定义构建类型:

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

在运行期间,CMake会保留为所有选项设置的值。CMake定义了以下构建类型:
Debug:默认构建类型。构建系统将编译未优化的工具和库,并启用调试信息和断言。
Release:对于这些构建,构建系统将编译启用优化的工具和库,而不生成调试信息。CMakes的默认优化级别为-O3。这可以通过在CMAKE命令行上设置CMAKE_CXX_FLAGS_RELEASE变量来配置。
RelWithDebInfo:这些构建在调试时很有用。它们生成带有调试信息的优化二进制文件。CMakes的默认优化级别为-O2。这可以通过在CMAKE命令行上设置CMAKE_CXX_FLAGS_RELWITHDEBINFO变量来配置。

LLVM配置完毕,就可以在OBJ_ROOT目录下用以下命令来构建:

% make

如果构建失败,请在这里查看您是否使用了已知不编译LLVM的GCC版本。
如果需要并行构建,可以使用GNU Make的以下命令:

% make -j2

在使用LLVM源代码时,有几个特别的target非常有用:
make clean:删除构建生成的所有文件。包括对象文件、生成的C/C++文件、库和可执行文件。
make install:在$PREFIX下的路径中安装LLVM头文件、库、工具和文档,使用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系统的构建文件。这将适用于使用最新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构建时需要传递一些额外的flag。
可以从官网How To Cross-Compile Clang/LLVM using Clang/LLVMClang docs on how to cross-compile in general这两篇文档,了解到更多关于交叉编译的信息。

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

可选配置项

如果你是在支持binfmt_misc模块的Linux系统上运行,并且拥有root访问权限,则可以将系统设置为直接执行LLVM bitcode文件。可以执行以下命令来设置(如果您已经在使用该模块,则可能不需要第一个命令):

% 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

在Debian上,您也可以使用此命令,而不是上面的“echo”命令:

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

目录结构

可以从https://llvm.org/doxygen/ 网站查看到LLVM doxygen文档,了解到LLVM源代码的信息。以下是代码目录结构的简要介绍:

llvm/cmake

生成系统构建文件。
llvm/cmake/modules:构建llvm用户自定义选项的配置。检查编译器版本和链接器flag。
llvm/cmake/platforms:在Android NDK、iOS系统和非Windows主机上构建MSVC目录文件的工具链配置。

llvm/examples

  • 一些简单的例子,展示了如何使用LLVM作为自定义语言的编译器,包括降低、优化和代码生成。
  • Kaleidoscope教程:Kaleidoscope语言教程为一种非普通语言实现一个小编译器,包括一个手写的词法分析器、解析器、AST,以及使用LLVM的代码生成支持——包括静态(提前)和各种即时(JIT)编译方法。Kaleidoscope入门教程
  • BuildingJit:BuildingJit教程的示例,展示了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头文件。源代码可以包含这些头文件,这些头文件自动处理cmake生成的条件#includes。

llvm/lib

大多数源文件都在这个目录下。通过将代码放入库中,LLVM使得在工具之间共享代码变得容易。
llvm/lib/IR/:核心LLVM源文件,实现Instruction和BasicBlock等核心类。
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/:这些库的机器代码级别的表示和处理代码。处理汇编和对象文件的发送。
llvm/lib/ExecutionEngine/:用于在解释和JIT编译场景中在运行时直接执行bitcode 的库。
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的全面正确性、性能和基准测试套件。这在一个单独的git库中提供https://github.com/llvm/llvm-test-suite,因为它在各种license下包含大量第三方代码。有关详细信息,请参阅测试指南

llvm/tools

由上述库构建的可执行文件构成了用户界面的主要部分。您可以通过键入tool_name -help来获取工具的帮助。以下是对最重要工具的简要介绍。更多详细信息请参见命令指南
bugpoint:bugpoint用于调试优化过程或代码生成后端,方法是将给定的测试用例缩小到仍然会导致问题的过程和/或指令的最小数量,无论是崩溃还是编译错误。查阅HowToSubmitABug.html获取有关使用bugpoint的更多信息。
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:LLVM的后端编译器,将将LLVM位代码转换为本机代码的汇编文件。
opt:opt读取LLVM位码,应用一系列LLVM到LLVM的转换(在命令行上指定),并输出结果位码。“opt-help”是获取LLVM中可用程序转换列表的好方法。opt还可以对输入的LLVM位代码文件运行特定分析,并打印结果。主要用于调试分析,或熟悉分析的功能。

llvm/utils

使用LLVM源代码的实用程序;有些是构建过程的一部分,因为它们是部分基础工具的代码生成器。
codegen-diff:codegen diff可以看到LLC生成的代码和LLI生成的代码之间的差异。如果您正在调试其中一个,并且假设另一个生成正确的输出,这将非常有用。要查看完整的用户手册,请运行“perldoc codegen diff”。
emacs/:LLVM程序集文件和TableGen描述文件的Emacs和XEmacs语法高亮显示。
getsrcs.sh:查找并输出所有未生成的源文件,如果希望跨目录进行大量开发而不希望查找每个文件,这将非常有用。使用它的一种方法是在LLVM源代码的根目录下运行 xemacs utils/getsources.sh
llvmgrep:对LLVM中的每个源文件执行egrep -H -n,并将llvmgrep命令行上提供的正则表达式传递给它。这是在源代码库中搜索特定正则表达式的有效方法。
TableGen/:包含用于从常用TableGen描述文件生成寄存器描述、指令集描述甚至汇编程序的工具。
vim/:用于LLVM程序集文件和TableGen描述文件的vim语法高亮显示。


使用LLVM工具链的示例

本节给出了一个将LLVM与Clang前端结合使用的示例。

使用Clang的示例

  1. 首先,创建一个简单的C文件,将其命名为“hello.c”:
#include <stdio.h>
int main() {
  printf("hello world\n");
  return 0;
}
  1. 其次将C文件编译为可执行文件:
% clang hello.c -o hello

注意: 默认情况下,Clang与GCC一样工作。标准的-S和-c参数照常工作(分别生成本机的.s或.o文件)。
3. 将C文件编译为LLVM bitcode文件

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

-emit-llvm选项可以与-S或-c选项一起使用来生成.ll或.bc文件。这允许您在位代码文件上使用标准LLVM工具。
4. 以上面生成的两种格式来运行代码:

% ./hello

以及:

% lli hello.bc
  1. 使用llvm-dis查看LLVM的汇编代码:
% llvm-dis < hello.bc | less
  1. 用LLC代码生成器将程序编译成汇编语言:
% llc hello.bc -o hello.s
  1. 将本机汇编语言文件汇编成程序
% /opt/SUNWspro/bin/cc -xarch=v9 hello.s -o hello.native   # On Solaris

% gcc hello.s -o hello.native                              # On others
  1. 执行本机代码程序:
% ./hello.native

请注意,使用clang直接编译为本机代码(即当-emit-llvm选项不存在时)会执行6/7/8步。


Common Problems

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值