一、什么是 glibc
glibc 是 gnu 发布的 libc 库,即 C 运行库。它是 linux 最底层的 api,它包括很多规范,例如 system V、ISO C、POSIX 等。其他很多的函数库,都依赖 glibc,在其基础上进行各种拓展,如 X 库等。
glibc 是一种按照 LGPL 许可协议发布的,自由的,公开源码的,方便下载的 C 编译程序,是 GNU/Linux 操作系统的一个重要的组成部分。GNU C 运行库,是一种 C 函数库,是程序运行时使用到的一些 API 集合,它们一般是已预先编译好,以二进制代码形式存在 Linux 系统中,GNU C 运行库通常作为 GNU C 编译程序的一个部分发布。
glibc 除了封装 linux 操作系统所提供的系统服务外,还有其他必要的功能性服务:
- string,字符串处理
- signal,信号处理
- dlfcn,管理共享库的动态加载
- direct,文件目录操作
- elf,共享库的动态加载器,即 interpreter
- iconv,不同字符集的编码转换
- inet,socket 接口的实现
- intl,国际化,即 gettext 的实现
- io
- linuxthreads
- locale,本地化
- login,虚拟终端设备的管理,以及系统的安全访问
- malloc,动态内存的分配与管理
- nis
- stdlib,其他基本功能
libc、glibc(eglibc) 、glib 的关系和 libstdc++
libc 和 glibc 都是 linux 下的 C 函数库。libc 是 Linux 下的 ANSI C 函数库;glibc 是 Linux 下的 GNU C 函数库。
ANSI C 函数库是基本的 C 语言函数库,包含了 C 语言最基本的库函数。包含的头文件都是很熟悉的、很常用的头文件,一共有 15 个部分:
- <ctype.h>:包含用来测试某个特征字符的函数的函数原型,以及用来转换大小写字母的函数原型;
- <errno.h>:定义用来报告错误条件的宏;
- <float.h>:包含系统的浮点数大小限制;
- <math.h>:包含数学库函数的函数原型;
- <stddef.h>:包含执行某些计算 C 所用的常见的函数定义;
- <stdio.h>:包含标准输入输出库函数的函数原型,以及他们所用的信息;
- <stdlib.h>:包含数字转换到文本,以及文本转换到数字的函数原型,还有内存分配、随机数字以及其他实用函数的函数原型;
- <string.h>:包含字符串处理函数的函数原型;
- <time.h>:包含时间和日期操作的函数原型和类型;
- <stdarg.h>:包含函数原型和宏,用于处理未知数和类型的函数的参数列表;
- <signal.h>:包含函数原型和宏,用于处理程序执行期间可能出现的各种条件;
- <setjmp.h>:包含可以绕过一般函数调用并返回序列的函数的原型,即非局部跳转;
- <locale.h>:包含函数原型和其他信息,使程序可以针对所运行的地区进行修改;
- <
- <assert.h>:包含宏和信息,用于进行诊断,帮助程序调试。
glibc 是 linux 下面 C 标准库的实现,即 GNU C Library。glibc 本身是 GNU 旗下的 C 标准库,后来逐渐成为了 Linux 的标准 C 库,而 Linux 下原来的标准 C 库 Linux libc 逐渐不再被维护。
Linux 下面的标准 C 库不仅仅只有这一个,例如 uclibc、klibc,以及上面的 Linux libc,但是 glibc 无疑是用的最多的。glibc 在 /lib 目录下的 .so 文件是 libc.so.6。
主流的 Debian、Ubuntu、RedHat、CentOS 等用的 C 标准库都默认是 glibc(或者是其变种)
例如:在 C 代码中直接使用 fopen 函数就能打开文件,这是因为其在调用了系统中的 sys_open 系统调用,而 fopen 就是通过 glibc 来完成中间的处理过程的。
拓展(eglibc)
eglibc 就是一种变种的 glibc 标准 C 库,这里的 e 是 Embedded 的意思。
eglibc 主要特性是为了更好的支持嵌入式架构,可以支持不同的 shell (包括嵌入式),但它是二进制兼容 glibc 的,就是说如果代码之前依赖 eglibc 库,那么换成 glibc 后也不需要重新编译。
ubuntu 系统用的就是 eglibc(而不是 glibc),可以用 ldd -version 或者在 (32位系统)/lib/i386-linux-gnu/libc.so.6 (64位系统)/lib/x86_64-linux-gnu/libc.so.6 看看,可以显示 eglibc/glibc 的版本信息。
glib 和 glibc 基本上没有太大的联系,都是 C 编程需要调用的库而已。
glib 是 GTK+ 库和 GNOME 的基础,可以在多个平台下使用,如 Linux、Unix、Windows 等。
glib 是 GTK+ 库的基础库,它由基础类型、对核心应用的支持、实用功能、数据类型和对象系统五个部分组成,是一个综合用途的实用的轻量级 C 程序库。它提供 C 语言常用的数据结构的定义、相关的处理函数,有趣而使用的宏,可移植的封装和一些运行时机能(如事件循环、线程、动态调用、对象系统等的 API)。
GNOME 也是需要依靠 glib 库的,是图形化相关的库,不再此记述。
libstdc++ 和 glibc 有什么关系呢?
libstdc++ 与 gcc 是捆绑在一起的,也就是说安装了 gcc 的时候会把 libstdc++ 装上。那为什么 glibc 和 gcc 没有捆绑在一起?
相比 glibc,libstdc++ 虽然提供了 C++ 程序的标准库,它她并不与内核打交道。对于系统级别的事件,libstdc++ 首先是会与 glibc 交互,才能和内核通信,说白了 C++ 在 C 的基础上,libstdc++ 就需要在 glibc 的支持。
拓展(gcc、g++)
C 代码 .c 文件通过 gcc 首先转化为会变 .S 文件,之后汇编器 as 将 .S 文件转化为机械代码 .o 文件,生成的 .o 文件再与其他的 .o 文件,或者之前提到的 libc.so.6 库文件通过 ld 链接器链接在一块生成可执行文件。(在你编译代码使用 gcc 的时候,gcc 命令已经帮你把这些细节全部做好。)
那 g++ 呢?不要以为 gcc 只能编译 C 代码,g++ 只能编译 C++ 代码。
后缀为 .c 的,gcc 把它当做是 C 程序,而 g++ 会当做 C++ 程序;后缀为 .cpp 的文件,两者都会认为是 C++ 程序。虽然 C++ 是 C 的超集,但两者对语法的要求还是有些区别的。在编译阶段,g++ 会调用 gcc,对于 C++ 代码,两者是等价的,但是因为 gcc 命令不能自动与 C++ 程序使用的库联接,所以需要这样:gcc -lstdc++,所以在 Makefile 文件并没有手动加上 libstdc++ 库,一般就会提示错误,要求你安装 g++ 编译器了。
关于 /usr/lib64/libstdc++.so.6:version ‘GLIBCXX_3.4.21’ not found 的报错和如何升级 GCC 可以浏览另一篇文章:http://fsemouse.com/wordpress/2019/03/05/centos-7-%e5%ae%89%e8%a3%85%e5%8d%87%e7%ba%a7-gcc/
二、怎么查看系统的 GLIBC(可能会导致环境出错,看完再操)
解决”libc.so.6: version `GLIBC_2.24′ not found”问题
glibc 版本太低了,需要升级
一般 glibc 的 .so 文件是在 /lib64/libc.so,查看系统 glibc 库版本可使用如下命令:
1 |
$ strings /lib64/libc.so | grep GLIBC |
检查 libc.so 的结构,可以发现其是用软链的,这也就提供了多版本 glibc 的可能,高版本的 glibc 需要在官网上下载源码进行编译:http://ftp.gnu.org/gnu/glibc/
1 2 3 4 5 6 7 8 |
(以2.32版本为例) $ tar -zxvf glibc-2.32.tar.gz $ cd glibc-2.32 $ mkdir build $ cd build $ ../configure --prefix=/opt/glibc-2.32 $ make $ make install |
编译安装完后,可以建立软链接到安装目录里生成的 /opt/libc-2.32/lib/libc-2.32.so,也可以复制 .so 文件到 /lib64 中,方便多版本软链切换。
1 2 |
$ sudo rm -rf /lib64/libc.so.6 $ sudo ln -s /opt/glibc-2.32/lib/glib-2.32.so /lib64/libc.so.6 |
注意:删除 libc.so.6 之后可能导致系统命令不可用的情况,可使用一下方法解决:
1 |
$ LD_PRELOAD=/opt/glibc-2.32/lib/libc-2.32.so ln -s /opt/glibc-2.32/lib/libc-2.32.so /lib64/libc.so.6 |
如果上述更新失败可使用如下命令还原:
1 |
$ LD_PRELOAD=/lib64/libc-2.17.so ln -s /lib64/libc-2.17.so /lib64/libc.so.6 |
上述不一定能成功,可以参考: