最直接的方案是从LLVM-project的Github Release页面上下载编译好的二进制包,我的环境是ubuntu-20.04 WSL2,因此可以直接开箱即用。如果是远古系统,例如CentOS7之类的,需要先编译一套GCC-11.2工具链,然后再通过GCC工具链编译LLVM+Clang;
编译llvm+clang
(系统自带GCC版本>5的情况)
cmake -H. -Bbuild_release -DCMAKE_BUILD_TYPE=Release \
-G "Ninja" \
-DLLVM_USE_LINKER="gold" \
-DLLVM_TARGETS_TO_BUILD="X86" \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb" \
-DLLVM_ENABLE_RUNTIMES="libc;compiler-rt;libcxx;libcxxabi;libunwind"
参数解释
-H.
:表示从当前目录.
获取CMakeLists.txt
;-Bbuild
:表示将构建文件输出到当前目录下的./build_release
目录,如无则新建目录;-DCMAKE_BUILD_TYPE=Release
:采用Release
方式编译,好处在于编译产物体积较小;-G "Ninja"
:采用ninja
作为构建工具,好处是能够利用多核多CPU加快编译速度,坏处是内存消耗较大;-DLLVM_USE_LINKER="gold"
:采用gnu-gold
作为连接器,好处是比普通的gnu-ld
速度快,内存开销小;-DLLVM_TARGETS_TO_BUILD="X86"
:只编译目标平台X86
,可以减少编译所需的时间(根据实际目标平台决定);-DLLVM_ENABLE_PROJECTS
:编译项目列表clang
:编译器前端,以及一些相关的编译器前端工具集;clang-tools-extra
:额外的clang工具,如:clangd
,clang-format
等;lld
:LLVM的链接器,链接速度贼快,LLVM+CLANG工具集必选;lldb
:LLVM项目的调试器,作用和GDB一样;
-DLLVM_ENABLE_RUNTIMES
:编译的运行时列表:libc
:LLVM后端的libc
运行时库;compiler-rt
:LLVM后端的编译器运行时库;libcxx
:作为libstdc++
的替代,LLVM后端的C++运行时库;libcxxabi
:LLVM后端的C++二级制接口运行时库;libunwind
:LLVM后端的栈回滚库,主要是用于获取程序的调用栈和异常处理和跳转需要;
如果是远古操作系统,编译的命令参考如下(GCC-11.2编译可以参考我之前的文章Ubuntu20.04 LTS 安装GCC11.2教程,包教包会!):
# 注意 TOOL变量代表了GCC-11.2安装的目录 根据实际情况自行设置环境变量
export CC=$TOOL/bin/gcc
export CXX=$TOOL/bin/g++
cmake -H. -Bbuild_release -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$TOOL/lib64 -L$TOOL/lib64 -L/usr/local/lib" \
-DLLVM_TARGETS_TO_BUILD="X86" \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb" \
-DLLVM_ENABLE_RUNTIMES="libc;compiler-rt;libcxx;libcxxabi;libunwind" \
-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=1 \
-G "Ninja"
最重要的的两个参数,是传递给CMake的:
-DCMAKE_CXX_LINK_FLAGS
:在编译clang+llvm时使用给定的rpath
作为链接路径,如果不使用,默认链接的是远古CentOS自带的4.8.5版本GNU工具链,它是不满足llvm项目的编译要求的;-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=1
:允许在安装时导入编译期链接阶段的rpath
路径,不需要在安装后手动指定$LD_LIBRARY_PATH
路径,安装好的clang+llvm运行时自动会查找编译时的rpath
路径,也就是上面传递的-Wl,-rpath,$TOOL/lib64
的位置(即GCC-11.2运行时的安装位置,可以通过readelf -d executable |grep RPATH
验证,这里就不多说明了)
使用clang+llvm工具链的详细说明
直接安装二进制包的情况下,使用clang filename
编译文件会发生链接错误,因为找不到对应的头文件;需要使用-lstdc++
指定本机的gnu
工具集后端,才能正常编译;如果要完全采用LLVM+Clang工具链编译,需要使用:
clang filename.cc --stdlib=libc++ -fuse-ld=lld -lc++
我们可以比较一下两种方式的-v
输出内容(左为clang+gnu,右为clang+llvm):
-
使用
-lstdc++
编译的时候,注意序号1处的差异;可以看出,此时编译的后端采用的还是GNU工具集,尤其重点是:- 左边引入的C++头文件来自
/usr/lib/gcc/X86_64-linux-gnu/10/../../../../include/c++/10
下面;这个位置实际上就是/usr/include/c++/10
,也就是系统自带的GNU工具链的C++头文件所在地; - 右边引入的C++头文件来自
/usr/local/llvm-13.0.1/bin/../include/c++/v1
;这个地方正是我们安装LLVM+Clang工具链所在的位置;
- 左边引入的C++头文件来自
-
在第2处差异,可以明显看出
include <...> search
查找头文件的路径发生了区别,在1中已经描述过了; -
在第3处差异,可以明显看到链接器的区别,左为
/usr/bin/ld
,右为/usr/local/bin/ld.lld
(注意,这里我在/usr/local/bin
下建立了ld.lld
的软连接,默认是没有的);同时,链接过程载入的运行时库也是完全不同的,左边载入的是GNU的libstdc++
,右边载入的是LLVM的libc++
;