闲来无事,尝试编译一下glibc。
编译注意事项
glibc可以说是Linux系统最根本的库了,基本上除了Linux自身的API以外,所有的库都依赖于glibc。如果更新当前系统中的glibc的版本的行为是相当具有挑战性的。
首先有很多人可能会疑惑,其实glibc并不包含在gcc里面(参考Why glibc is maintained separately from GCC?)。因为其他编译器,或者其他没有gcc的操作系统也可以使用glibc。
gcc自身带有两三个库,比如libgcc,libstdc++,libm等等。
glibc对系统有强依赖性,在Linux编译glibc需要提供当前内核的头文件。
一般来说Linux的头文件是单独打包单独安装的。也可以使用内核源码的make系统来生成这些头文件。很简单,只需要执行
make headers_install
。 默认情况下这些文件会安装到/usr/src/linux-VERSION-obj/x86_64/default/include
吧。
不同版本的glibc对Linux头文件有不同的要求,从发布的消息来看,glibc 2.23往上的版本需要Linux 3.2版本以上的头文件。
glibc使用的预编译系统是autoconf,但是编译目录必须在源码目录之外,将glibc(假设版本是2.23)的源代码解压以后,进入目录执行:
# 假设glibc的源码在./glibc-2.23
# 创建并进入编译目录
mkdir build
cd build
# 执行预编译配置
../glibc-2.23/configure
# 执行编译
make
实际上,我们在configure的时候,往往需要指定一些选项,例如
--with-headers=
,指定Linux头文件的位置,如果不在标准的/usr/include/linux
下面的话--prefix=
,指定安装路径--disable-werror
,消除一些讨厌的告警错误,如果你用太新的编译器来编译较老的glibc,大概率会出现一些告警信息--without-selinux
,取消对selinux的支持--enable-add-ons
,打开一些附加项,比如对libthread的支持
加上选项的configure命令可能是这样的:
../glibc-2.23/configure --with-headers=/opt/linux/linux-3.0.101-108.84-obj/x86_64/default/usr/include --prefix=$HOME/glibc --disable-werror --without-selinux --enable-add-ons
使用glibc
编译glibc是一门学问,使用glibc更是一门学问。
假设有一个glibc-version.c的源文件(来自Check glibc version for a particular gcc compiler),内容如下:
#include <stdio.h>
#include <stdlib.h>
#include <gnu/libc-version.h>
int main(int argc, char *argv[]) {
printf("GNU libc version: %s\n", gnu_get_libc_version());
exit(EXIT_SUCCESS);
}
可以尝试使用下面的命令来指定glibc(之前编译的版本):
gcc glibc-version.c -Wl,--rpath=$HOME/glibc/2.23/lib -Wl,--dynamic-linker=$HOME/glibc/2.23/lib/ld-linux-x86-64.so.2
上面的方法使用动态链接--dynamic-linker
,还有一种使用-rpath-link
的方法,在Re: Linking against different glibc version?里面有介绍.
如果使用的glibc版本不对,可能会出现这种错误:
Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions:
Assertion `needed != ((void *)0)' failed!
其他小贴士
- CMake相关
- 对于CMake生成的Makefile,
make VERBOSE=1
可以查看Make所执行的底层命令。 - CMake的
CMAKE_C_FLAGS
选项可以在编译C代码的时候提供给相应的C编译器 - CMake的
CMAKE_CXX_FLAGS
选项可以在编译C++代码的时候提供给相应的C++编译器 - CMake的
CMAKE_EXE_LINKER_FLAGS
选项可以在链接是提供给相应的链接器
- 对于CMake生成的Makefile,
objdump -x a.out
,可以查看可执行文件的符号表- gcc相关
gcc --print-file-name=include
,打印默认的头文件包含地址gcc --print-libgcc-file-name
,打印libgcc的文件名gcc --print-file-name=libstdc++.so
,打印libstdc++.so的文件名cpp -v /dev/null -o /dev/null
,查看C预处理内置的头文件包含地址,echo | gcc -E -Wp,-v -
或者echo | cpp -xc++ -Wp,-v
也能达到类似效果
GCC的开关参考
- 2.3 Search Path
- 3.8 Options to Request or Suppress Warnings
- 3.14 Options for Linking
- 3.15 Options for Directory Search
其他参考
- glibc由来已久,历史包袱有点沉重。现在有一个小清新一点的C运行库musl libc,正在逐渐崭露头角,希望有一天能够开花结果,可以打破glibc一统天下的局面。
- 编译 Libc 2.23
- Testing a glibc build
- How can I link to a specific glibc version?
- Linking to Older Versioned Symbols (glibc)
- Check glibc version for a particular gcc compiler
- Multiple glibc libraries on a single host
- Link with an older version of libstdc++
- GCC linking libc static and some other library dynamically, revisited?
- How to Statically Link C and C++ Programs on Linux with gcc
- Re: Linking against different glibc version?
- debugging ld, “Inconsistency detected by ld.so”
- 6. Compiling with the non-primary libc.