环境搭建

本机:ubuntu 18.04

直接安装

mac

1
$ brew install llvm

配置环境变量:

1
2
3
4
5
6
If you need to have llvm first in your PATH run:
echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc

For compilers to find llvm you may need to set:
export LDFLAGS="-L/usr/local/opt/llvm/lib"
export CPPFLAGS="-I/usr/local/opt/llvm/include"

ubuntu

1
2
$ sudo apt install llvm
$ sudo apt install clang

llvm和clang混合编译

要求:

Package Version Notes
GCC >=5.1.0 C/C++ compiler1
python >=2.7 Automated test suite2
zlib >=1.2.3.4 Compression library3
GNU Make 3.79, 3.79.1 Makefile/build processor4
CMake >=3.4.3 Makefile/workspace generator
1
2
3
4
5
6
7
$ sudo apt install cmake
$ git clone https://github.com/llvm/llvm-project.git
$ cd llvm-project
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" --enable-optimized --enable-targets=host-only -DLLVM_ENABLE_PROJECTS=clang ../llvm
$ cmake --build .

--enable-optimized 打开优化,默认情况下是关闭的。这样会生成大量 debug 信息,需要较多的磁盘空间。

--enable-targets=host-only 选择目标平台,默认情况下会生成所有平台的。 host-only 只选择本机即可。

错误处理:

collect2: fatal error: ld terminated with signal 9 [Killed]

虚拟机内存不够,调大即可。

collect2: error: ld returned 1 exit status

个人情况是硬盘容量不足,拓展一下即可。

单独编译llvm

1
2
3
4
5
6
7
8
下载环境包:https://releases.llvm.org/download.html
$ mkdir llvm
$ cd llvm
$ tar xf llvm-7.0.1.src.tar.xz
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" --enable-optimized --enable-targets=host-only ../llvm-7.0.1.src
$ cmake --build . #编译

第9行代码对应如下:

cmake -G <generator> [options] ../llvm

Some common build system generators are:

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

https://llvm.org/docs/GettingStarted.html

还有一些可选的 options:

  • -DCMAKE_INSTALL_PREFIX=directory 明确LLVM工具和库被安装的位置,默认在/usr/local下。
  • -DCMAKE_BUILD_TYPE=type Debug选项,默认就是使用Debug,可以改为Release减少不必要的文件。
  • -DLLVM_ENABLE_ASSERTIONS=On 编译时开启断言检查(assertion),默认就是开启
    要注意整个llvm和build的绝对路径中不要出现中文,否则会出问题。

LLVM工具链的使用示例

  1. Clang示例

    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>

    int main() {
    printf("hello world\n");
    return 0;
    }

    //$ clang hello.c -o hello

    此时得到一个可执行的 hello文件。c

  2. hello.c编译为LLVM字节码文件

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

    ps:-emit-llvm选项可与-S-c选项一起使用,以分别为代码发出LLVM .ll.bc文件。

  3. 使用两种方式运行程序:

    1
    2
    $ ./hello
    $ lli hello.bc # show llvm JIT
  4. 使用llvm-dis命令查看LLVM的汇编代码:

    1
    llvm-dis < hello.bc | less
  5. 使用llc将程序编译为本地汇编代码:

    1
    llc hello.bc -o hello.s

命令小结:

  • llvm-as:把LLVM IR从文本格式汇编成二进制格式。注意:此处得到的不是目标平台的机器码。
  • llvm-disllvm-as的逆过程,即反汇编。 不过这里的反汇编的对象是LLVM IR的二进制格式,而不是机器码。
  • opt:优化LLVM IR。输出新的LLVM IR。
  • llc:把LLVM IR编译成汇编码。需要用as进一步得到机器码。
  • lli:解释执行LLVM IR。

参考文章:

https://llvm.zcopy.site/docs/start.html

http://clang.llvm.org/get_started.html