闲来无事,尝试编译一下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选项可以在链接是提供给相应的链接器
  • 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的开关参考

其他参考