LLVM 之 Clang 篇(1):如何从源码构建并安装 Clang

Author: stormQ

Created: Tuesday, 30. March 2021 11:38PM

Last Modified: Saturday, 03. April 2021 09:35PM



摘要

本文介绍了在 Ubuntu 20.04 系统中从源码构建和安装 Clang 的过程,从而更好地了解 LLVM 结构。


如何从源码构建并安装 Clang

step 1: 获取源码

1) 获取 Clang 的源码

$ git clone https://github.com/llvm/llvm-project.git

注:Clang 的源码位于目录llvm-project/clang中。

2) 切换到指定的版本(optional)

如果要以发布版本release/12.x作为接下来编译的基础版本。在 llvm-project 目录下执行如下命令:

$ git checkout release/12.x

step 2: 选择构建工具

构建工具可以是GNU makeninja等。为了更快的增量编译,Clang 官网推荐使用ninja

1) 安装 ninja

在 Ubuntu 20.04 中安装ninja的命令如下:

$ sudo apt-get install ninja-build

查看ninja的版本:

$ ninja --version
1.10.0

step 3: 调整配置参数(optional)

我们可以调整配置参数,以获取定制的编译器。接下来,介绍一些常用的配置参数。

1) 指定编译哪些目标机器(optional)

默认情况下,所有可支持的目标机器的相关代码都会被编译。这些目标机器如下所示:

-- Targeting AArch64
-- Targeting AMDGPU
-- Targeting ARM
-- Targeting AVR
-- Targeting BPF
-- Targeting Hexagon
-- Targeting Lanai
-- Targeting Mips
-- Targeting MSP430
-- Targeting NVPTX
-- Targeting PowerPC
-- Targeting RISCV
-- Targeting Sparc
-- Targeting SystemZ
-- Targeting WebAssembly
-- Targeting X86
-- Targeting XCore

为了减少编译时间,我们可以只编译可能会用到的目标机器。

如果要指定只编译的目标机器为X86AArch64RISCV。可以使用如下选项:

-DLLVM_TARGETS_TO_BUILD="X86;AArch64;RISCV"

注意: 目标机器之间用英文分号;隔开。

上述选项的用法如下:

$ cmake -DLLVM_TARGETS_TO_BUILD="X86;AArch64;RISCV" -G Ninja ../llvm/

执行上述命令后,可以从控制台的输出看出,仅上述指定的目前机器的相关代码会被编译。如下所示:

-- Targeting X86
-- Targeting AArch64
-- Targeting RISCV

2) 指定编译哪些项目(optional)

如果要指定只编译的项目为clang。可以使用如下选项:

-DLLVM_ENABLE_PROJECTS=clang

目前,所有的可选项如下所示:

clang;clang-tools-extra;compiler-rt;debuginfo-tests;libc;libclc;libcxx;libcxxabi;libunwind;lld;lldb;mlir;openmp;parallel-libs;polly;pstl;flang

注意: 项目之间用英文分号;隔开。

上述选项的用法如下:

$ cmake -DLLVM_ENABLE_PROJECTS=clang -G Ninja ../llvm/

执行上述命令后,可以从控制台的输出看出,仅上述指定的项目会被编译。如下所示:

-- clang project is enabled
-- clang-tools-extra project is disabled
-- compiler-rt project is disabled
-- debuginfo-tests project is disabled
-- libc project is disabled
-- libclc project is disabled
-- libcxx project is disabled
-- libcxxabi project is disabled
-- libunwind project is disabled
-- lld project is disabled
-- lldb project is disabled
-- mlir project is disabled
-- openmp project is disabled
-- parallel-libs project is disabled
-- polly project is disabled
-- pstl project is disabled
-- flang project is disabled

3) 指定生成的版本是 DEBUG 还是 RELEASE(optional)

默认情况下,生成的是DEBUG版本。相应地,执行cmake命令时会有如下输出:

-- No build type selected, default to Debug

如果要指定生成RELEASE版本,可以使用如下选项:

-DCMAKE_BUILD_TYPE=Release

上述选项的用法如下:

$ cmake -DCMAKE_BUILD_TYPE=Release -G Ninja ../llvm/

4) 指定生成静态库还是共享库(optional)

默认情况下,生成的是静态库。相应地,build目录(由我们创建的)中的CMakeCache.txt文件中会包含如下内容:

//Build all libraries as shared libraries instead of static
BUILD_SHARED_LIBS:BOOL=OFF

如果要指定生成共享库,可以使用如下选项:

-DBUILD_SHARED_LIBS=ON

上述选项的用法如下:

$ cmake -DBUILD_SHARED_LIBS=ON -G Ninja ../llvm/

执行上述命令后,该CMakeCache.txt文件中会包含如下内容:

//Build all libraries as shared libraries instead of static
BUILD_SHARED_LIBS:BOOL=ON

step 4: 编译

1) 创建并切到 build 目录

在 llvm-project 目录中执行如下命令:

$ mkdir build && cd build

2) 仅编译 Clang

在 llvm-project/build 目录中执行如下命令:

$ cmake -DLLVM_TARGETS_TO_BUILD="X86;AArch64;RISCV" -DLLVM_ENABLE_PROJECTS=clang -DBUILD_SHARED_LIBS=ON -G Ninja ../llvm/
$ ninja clang -j8

注:选项-j8表示并发任务最多可以有 8 个,从而减少编译时间。如此指定是由于笔者机器中的逻辑 CPU 数量为 8。

注意: 执行上述命令时,需要确保可用的内存(包括交换空间)大小至少 25 G,可用的磁盘空间至少 15 G。

编译的 Clang——clang-12位于 llvm-project/build/bin 目录中。如下所示:

$ ll -h bin/
total 89M
drwxrwxr-x  2 xxq xxq 4.0K Apr  3 12:32 ./
drwxrwxr-x 16 xxq xxq 4.0K Apr  3 11:44 ../
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang -> clang-12*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang++ -> clang-12*
-rwxrwxr-x  1 xxq xxq  11M Apr  3 12:32 clang-12*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang-cl -> clang-12*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang-cpp -> clang-12*
-rwxrwxr-x  1 xxq xxq 1.7M Apr  3 12:31 clang-offload-bundler*
-rwxrwxr-x  1 xxq xxq 3.0M Apr  3 12:31 clang-offload-wrapper*
-rwxrwxr-x  1 xxq xxq  14M Apr  3 12:10 clang-tblgen*
-rwxrwxr-x  1 xxq xxq 1.8K Apr  3 11:41 llvm-lit*
-rwxrwxr-x  1 xxq xxq  61M Apr  3 11:46 llvm-tblgen*

查看编译的 Clang 是否是DEBUG版本。在 llvm-project/build/bin 目录中执行如下命令:

file clang-12
clang-12: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bf9c06b83fd7a850f8fc7433a6bd001455943a2b, for GNU/Linux 3.2.0with debug_info, not stripped

从上面可以看出,上述编译的clang-12确实是DEBUG版本。

step 5: 测试

1) 安装 Clang 测试套件的依赖

在笔者机器上运行时,只需安装如下依赖:

$ sudo apt-get install python3-distutils

注:在不同的机器上运行时,缺少的依赖可能不同。如果运行 Clang 测试套件失败,则根据报错内容进行相应地解决。

2) 运行 Clang 测试套件

在 llvm-project/build 目录中执行如下命令:

$ ninja check-clang

注意: 执行上述命令时,需要确保可用的内存(包括交换空间)大小至少 15 G,可用的磁盘空间至少 5 G。

如果 Clang 测试套件运行成功,则会有如下类似输出:

Testing Time: 3045.74s
  Unsupported      :   474
  Passed           : 26697
  Expectedly Failed:    27

运行 Clang 测试套件后,llvm-project/build/bin 目录中的内容更新如下:

$ ll -h bin/
total 249M
drwxrwxr-x  2 xxq xxq 4.0K Apr  3 14:12 ./
drwxrwxr-x 16 xxq xxq 4.0K Apr  3 11:44 ../
-rwxrwxr-x  1 xxq xxq 519K Apr  3 13:55 apinotes-test*
-rwxrwxr-x  1 xxq xxq 5.3M Apr  3 13:56 arcmt-test*
-rwxrwxr-x  1 xxq xxq  22K Apr  3 14:01 c-arcmt-test*
-rwxrwxr-x  1 xxq xxq 6.9M Apr  3 14:01 c-index-test*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang -> clang-12*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang++ -> clang-12*
-rwxrwxr-x  1 xxq xxq  11M Apr  3 12:32 clang-12*
-rwxrwxr-x  1 xxq xxq 5.2M Apr  3 13:56 clang-check*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang-cl -> clang-12*
lrwxrwxrwx  1 xxq xxq    8 Apr  3 12:32 clang-cpp -> clang-12*
-rwxrwxr-x  1 xxq xxq 5.3M Apr  3 13:55 clang-diff*
-rwxrwxr-x  1 xxq xxq 5.4M Apr  3 13:56 clang-extdef-mapping*
-rwxrwxr-x  1 xxq xxq 2.3M Apr  3 13:55 clang-format*
-rwxrwxr-x  1 xxq xxq 6.9M Apr  3 13:56 clang-import-test*
-rwxrwxr-x  1 xxq xxq 1.7M Apr  3 12:31 clang-offload-bundler*
-rwxrwxr-x  1 xxq xxq 3.0M Apr  3 12:31 clang-offload-wrapper*
-rwxrwxr-x  1 xxq xxq 7.7M Apr  3 13:56 clang-refactor*
-rwxrwxr-x  1 xxq xxq 5.4M Apr  3 13:56 clang-rename*
-rwxrwxr-x  1 xxq xxq 6.4M Apr  3 13:56 clang-scan-deps*
-rwxrwxr-x  1 xxq xxq  14M Apr  3 12:10 clang-tblgen*
-rwxrwxr-x  1 xxq xxq  20K Apr  3 13:52 count*
-rwxrwxr-x  1 xxq xxq 4.8M Apr  3 13:55 diagtool*
-rwxrwxr-x  1 xxq xxq 1.4M Apr  3 13:52 FileCheck*
-rwxrwxr-x  1 xxq xxq 9.8K Apr  3 14:11 hmaptool*
-rwxrwxr-x  1 xxq xxq 4.7M Apr  3 14:11 llc*
-rwxrwxr-x  1 xxq xxq 2.2M Apr  3 14:11 llvm-as*
-rwxrwxr-x  1 xxq xxq 720K Apr  3 14:11 llvm-bcanalyzer*
-rwxrwxr-x  1 xxq xxq 2.2M Apr  3 14:11 llvm-cat*
-rwxrwxr-x  1 xxq xxq 776K Apr  3 13:52 llvm-config*
-rwxrwxr-x  1 xxq xxq 681K Apr  3 14:11 llvm-cxxfilt*
-rwxrwxr-x  1 xxq xxq 2.7M Apr  3 14:11 llvm-dis*
-rwxrwxr-x  1 xxq xxq 3.3M Apr  3 14:11 llvm-dwarfdump*
-rwxrwxr-x  1 xxq xxq 1.4M Apr  3 14:11 llvm-ifs*
-rwxrwxr-x  1 xxq xxq 1.8K Apr  3 11:41 llvm-lit*
-rwxrwxr-x  1 xxq xxq 4.9M Apr  3 13:50 llvm-lto*
-rwxrwxr-x  1 xxq xxq 4.6M Apr  3 14:12 llvm-lto2*
-rwxrwxr-x  1 xxq xxq 2.1M Apr  3 14:11 llvm-modextract*
-rwxrwxr-x  1 xxq xxq 4.0M Apr  3 14:12 llvm-nm*
-rwxrwxr-x  1 xxq xxq  15M Apr  3 14:12 llvm-objcopy*
-rwxrwxr-x  1 xxq xxq  11M Apr  3 14:12 llvm-objdump*
-rwxrwxr-x  1 xxq xxq 5.0M Apr  3 13:52 llvm-profdata*
lrwxrwxrwx  1 xxq xxq   12 Apr  3 14:12 llvm-readelf -> llvm-readobj*
-rwxrwxr-x  1 xxq xxq  17M Apr  3 14:12 llvm-readobj*
lrwxrwxrwx  1 xxq xxq   12 Apr  3 14:12 llvm-strip -> llvm-objcopy*
-rwxrwxr-x  1 xxq xxq 1.4M Apr  3 14:12 llvm-symbolizer*
-rwxrwxr-x  1 xxq xxq  61M Apr  3 11:46 llvm-tblgen*
-rwxrwxr-x  1 xxq xxq 242K Apr  3 13:52 not*
-rwxrwxr-x  1 xxq xxq  14M Apr  3 14:12 opt*
-rwxrwxr-x  1 xxq xxq 546K Apr  3 14:12 split-file*
-rwxrwxr-x  1 xxq xxq 889K Apr  3 14:12 yaml2obj*

step 6: 安装

由于 Ubuntu 20.4 系统中默认安装了版本为 10 的 Clang,如下所示:

$ clang --version
clang version 10.0.0-4ubuntu1 
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

因此,为了让我们编译的 Clang 作为默认使用的版本,可以通过如下的安装方式来做到这一点。

1) 安装方式 1

如果选择的构建工具是ninja,在 llvm-project/build 目录中执行如下命令进行安装:

$ sudo ninja install

注:命令ninja install实际调用 llvm-project/build 目录中的cmake_install.cmake脚本进行安装。

默认的安装目录为/usr/local。相应地,cmake_install.cmake脚本中会有如下内容:

Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
  set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")

从上面的代码可以看出,如果要更改默认安装目录,则可以通过设置CMAKE_INSTALL_PREFIX选项做到这一点。

2) 查看默认使用的 Clang 版本

$ clang --version
clang version 12.0.0 (省略...)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin

从上面可以看出,默认使用的clang版本确实是由我们生成的。

3) 查看默认使用的其他工具的版本(以 clang-check 为例)

$ clang-check --version
LLVM (http://llvm.org/):
  LLVM version 12.0.0
  DEBUG build with assertions.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: skylake

从上面可以看出,默认使用的clang-check版本也确实是由我们生成的。


References


下一篇:LLVM 之 Clang 篇(2):Clang 的编译流程

上一篇:上一级目录

首页