LLVM 使用简介

2018-12-08 language c/cpp

LLVM 计划启动于 2000 年,由 UIUC 大学的 Chris Lattner 博士主持,后入职 Apple 继续推广,所以 Apple 就成了主要的赞助商。

最初是 Low Level Virtual Machine 的缩写,不过随着发展,逐渐整合成了一整套的编译工具,所以官方也就放弃了原有的缩写,而修改成 The LLVM Compiler Infrastructure 。

其强大之处在于模块化,可以很方便适配不同的语言以及硬件平台。

LLVM

LLVM 是一个模块化、可重用的编译器及其工具链相关的技术。

llvm arch

一般编译器分成了三部分:A) Frontend 前端,包括了词法分析、语法分析、语义分析、生成中间代码;B) Optimizer 优化器,中间代码优化;C) Backend 后端,生成机器码。

不同的前端后端使用统一中间代码,如果需要支持一种新的变成语言,那么只需要实现一个新的前端;同样,如果支持一种新的硬件设备,只需要实现一个新的后端。

优化阶段不论是支持新的变成语言,还是支持新的硬件设备,都不需要对优化阶段做修改。

安装

Release 中下载对应的版本,注意是对应的 SourceCode 压缩包,然后通过如下命令进行编译。

$ mkdir build && cd build
$ cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;lld;lldb;clang-tools-extra;compiler-rt" \
    -DCMAKE_INSTALL_PREFIX=/opt/clang -DCMAKE_BUILD_TYPE=Release ../llvm
$ make -j 16 install

其中 -DLLVM_ENABLE_PROJECTS 参数指定的就是在源码中的目录,常见的组件包含如下几个:

  • lld 连接器。
  • lldb 调试器。
  • clang 编译前端。
  • clang-tools-extra 包含类似 clangd 等工具。
  • compiler-rt 相当于 GCC 中的 libgcc,提供了底层的优化实现,例如 asan、tsan、crt、fuzzer 等工具。

clang

Clang 是 LLVM 项目的一个子项目,用作 C C++ Objective-C 编译器的前端,可以通过如下方式安装。

# yum install clang

如下是常见的使用命令。

$ cat main.c
int main(void)
{
	return 0;
}

----- 打印各个阶段
$ clang -ccc-print-phases main.c

----- 预处理结果
$ clang -E main.c

----- 词法分析
$ clang -fmodules -E -Xclang -dump-tokens main.c

----- 打印语法树
$ clang -fmodules -fsyntax-only -Xclang -ast-dump main.c

也以生成保存中间码。

常见问题

编译报错

当通过 GCC 编译 CLang 代码时,最好使用高的版本,例如在 GCC v7.3.0 编译 LLVM v16.0.6 时会有如下的报错,此时可以升级 GCC 版本。

error: duplicate initialization of ‘llvm::AnalysisGetter::HasLegacyWrapper<Analysis, std::void_t<typename Analysis::LegacyWrapper> >’

GCC 依赖

在编译过程中会依赖 GCC 的头文件、动态库等,甚至可以选择连接器,默认会自动选择,如果失败可以通过如下方式指定。

----- 查看当前默认的gcc路径
$ clang -v
Ubuntu clang version 16.0.6 (++20230610113324+7cbf1a259152-1~exp1~20230610233415.100)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /opt/ldb/bin
Found candidate GCC installation: /opt/ldb/bin/../lib/gcc/x86_64-linux-gnu/11
Selected GCC installation: /opt/ldb/bin/../lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64

----- 可以通过如下参数指定
$ clang -v --gcc-toolchain='/opt/rh/gcc-toolset-10/root/usr'
----- 而对于16.0.0之后的版本,除了上述的参数之外,还可以使用如下参数
$ clang -v --gcc-install-dir='/opt/rh/gcc-toolset-10/root/usr/lib/gcc/x86_64-pc-linux-gnu/10.3.0'

其中 16.0.0 的两个参数可以参考 LLVM Phabricator 中的介绍,搜索路径也可以通过 clang --print-search-dirs 查看,而编译参数通过 clang -E -x c++ - -v 查看,包括头文件搜索路径。

参考