Build GNU-free Toolchain
在linux上,最为受欢迎的 C/CXX 编译器之一就是 gcc 系列了,其使用 GNU 协议开源。 除此之外,还有基于llvm的现代编译器 clang/clang++,它则使用更为宽松的 BSD 协议开源。 关于两者的比较,可以参见这里。
本文将尝试编译一套与 gnu 编译器无关的基于 clang 的工具链。
clang 是用C++写的,其依赖于 C 和 C++ 标准库,C++ ABI 库,以及 stack unwinder(实际上,我们编译其他的c/c++源代码也离不开三种)。
在clang编译器工具链中,我们可以采用 musl, libcxx, libc++abi 和 libunwind 四个库来完成。
其中,libc++, libc++abi 和 libunwind 属于llvm 自己开发的 C++ 运行时(C++ runtime)。
clang系列编译器 | GNU 编译器 | |
---|---|---|
C标准库 | musl | glibc |
C++标准库 | libcxx | libstdc++ |
C++ ABI 库 | libc++abi | libgcc(?不确定) |
stack unwinder | libunwind | libgcc |
需要指出的是,使用clang系列编译器时,也可以链接 GUN 的 glibc, libstdc++, libgcc 库, 这里我们为了与GNU无关,则把这个选择直接忽略。
这里插一句libc 和 glibc的区别,
我们在编译程序时,使用ldd命令,可以看到二进制程序的链接库,而且大部分程序都会依赖于 libc。
在linux系统下,系统默认会有一个libc的库,大多数系统里面的这个libc库就是glibc,系统的大多数程序也都依赖于该库。
glibc是C标准库的一个实现,而在较早之前 linux 有自己的C标准库实现,后来改用使用glibc,而自己原先带libc库不再维护。
回到正题,C标准库,除了glibc的实现外,还有另一个开源实现 musl,采用 MIT 协议。 就C++标准库而言,llvm 也有一个实现,叫 libc++。
libc++ is an implementation of the C++ standard library, targeting C++11, C++14 and above. All of the code in libc++ is dual licensed under the MIT license and the UIUC License (a BSD-like license).
相关准备工作
为了实现这些库或clang编译器的编译,因此我们需要一个编译器。 我们还得转到gcc上面来,先安装gcc编译器,用 gcc 编译器编译这些库 (当然,等gcc编译好了clang后,也可以用clang把这些库重新编译一遍,这个过程叫"bootstrap")。
嗯,我们基于alpine系统(一个linux的发行版,很轻量级(约5MiB),常用于构建docker镜像) 因为alpine的C标准库是musl,而非glibc。
Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.
为方便,我们在docker容器中执行各个阶段的编译构建过程。
mkdir build-llvm-project
cd build-llvm-project
docker run -it --rm -v ${PWD}:/root/build-llvm-project alpine:latest ash
后面的所有命令,都将在这个容器中进行,而非宿主机上。
在alpine容器中,安装build-base、make、cmake、python3(构建libcxx和clang编译时需要)等工具:
apk add --no-cache build-base cmake git python3 linux-headers
下载llvm相关源代码:
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout llvmorg-9.0.0 # use 9.0.0 version
在上面git clone 的 llvm-project 的源码中,已经包含了liibunwind,libcxx-abi,libcxx, 此外,还包含llvm libc,lldb,lld,openmp的实现代码(这里就不展开了)。
我们采用自底层往上的原则,分别编译 libunwind,libc++abi,libcxx。
构建 libunwind
cd build-llvm-project/llvm-project
cd libunwind
cmake -B./build -H./ -DLIBUNWIND_ENABLE_SHARED=OFF -DLLVM_PATH=../llvm \ #-DLIBUNWIND_USE_COMPILER_RT=ON
-DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC"
cmake --build ./build --target install
cd ../