C++的版本管理简单粗暴,像libc这种基础库如果需要多版本,用起来非常不方便,但c/c++基础库都是向下兼容的,最好的方式就是用一套比较新的系统,带着新的libc,再安装一套和系统版本同年代的新一点的gcc编译器即可,可满足大部分的使用场景,避免一套环境上折腾多套libc、libstdc++,经验之谈:非常麻烦性价比很低!
系统一定会自带libc.so,因为这是C的基础库,内核和所有程序都会依赖系统自带libc.so。
随便一个程序看下依赖库,都能看到Libc的影子:
# ldd /usr/bin/echo
...
...
libc.so.6 => /lib64/libc.so.6 (0x00007fa004df6000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fa004bf2000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa0053c5000)
注意:程序用的时候都会用/lib64/libc.so.6
的名字,而libc.so.6
会指向哭啼某个版本的libc。
查看所依赖的libc版本,可以看出当前Libc的版本是2.28。而Libc是向下兼容的,从库中定义的一些字符串常量可以知道兼容哪些版本:
$ ll /lib64/libc.so.6
lrwxrwxrwx 1 root root 12 Nov 24 2022 /lib64/libc.so.6 -> libc-2.28.so
$ strings /lib64/libc.so.6 | grep -E '^GLIBC' | sort
GLIBC_2.10
GLIBC_2.11
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_2.18
GLIBC_2.22
GLIBC_2.23
GLIBC_2.23
GLIBC_2.24
GLIBC_2.2.5
GLIBC_2.25
GLIBC_2.25
GLIBC_2.2.6
GLIBC_2.2.6
GLIBC_2.26
GLIBC_2.26
GLIBC_2.27
GLIBC_2.28
GLIBC_2.28
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.5
GLIBC_2.6
GLIBC_2.6
GLIBC_2.7
GLIBC_2.7
GLIBC_2.8
GLIBC_2.8
GLIBC_2.9
GLIBC_2.9
GLIBC_PRIVATE
/lib64/目录是短连接,实际位置:
$ ll /lib64
lrwxrwxrwx 1 root root 9 Dec 21 2021 /lib64 -> usr/lib64
$ ll /usr/lib64/ | grep libc.so
-rw-r--r-- 1 root root 253 Nov 24 2022 libc.so
lrwxrwxrwx 1 root root 12 Nov 24 2022 libc.so.6 -> libc-2.28.so
ldd的版本和libc是配套的:
$ ldd --version
ldd (GNU libc) 2.28
Copyright (C) 2018 Free Software Foundation, Inc.
编译器用的Libc版本:
$ gcc -print-file-name=libc.so
/usr/lib/gcc/x86_64-redhat-linux/8/../../../../lib64/libc.so
使用g++编译的c++程序会依赖c++标准库libstdc++.so.6
$ ldd llvm-as
...
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f4cf5ae0000)
libm.so.6 => /lib64/libm.so.6 (0x00007f4cf575e000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f4cf5546000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4cf5180000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4cf68bc000)
libstdc++.so.6的名字也是用短连接指向真正的库文件:
$ ll /lib64/libstdc++.so.6
lrwxrwxrwx 1 root root 19 May 24 22:05 /lib64/libstdc++.so.6 -> libstdc++.so.6.0.25
$ strings /usr/lib64/libstdc++.so.6 | grep LIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_3.4.23
GLIBCXX_3.4.24
GLIBCXX_3.4.25
GLIBCXX_DEBUG_MESSAGE_LENGTH
GA+GLIBCXX_ASSERTIONS
以llvm为例
$ readelf -s llvm-ar | grep -oE "GLIBCXX_.*|GLIBC_.*" | sort | uniq
GLIBCXX_3.4
GLIBCXX_3.4 (6)
GLIBCXX_3.4.11 (14)
GLIBCXX_3.4.14 (26)
GLIBCXX_3.4.15 (11)
GLIBCXX_3.4.18 (22)
GLIBCXX_3.4.19 (21)
GLIBCXX_3.4.20 (5)
GLIBCXX_3.4.21 (8)
GLIBCXX_3.4.9 (13)
GLIBC_2.14
GLIBC_2.14 (7)
GLIBC_2.15 (23)
GLIBC_2.2.5
GLIBC_2.2.5 (15)
GLIBC_2.2.5 (18)
GLIBC_2.2.5 (3)
GLIBC_2.2.5 (4)
GLIBC_2.3
GLIBC_2.3 (17)
GLIBC_2.3 (9)
GLIBC_2.6
GLIBC_2.6 (10)
可以看出llvm-ar需要:
而当前系统提供:
strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_3.4.23
GLIBCXX_3.4.24
GLIBCXX_3.4.25
strings /lib64/libc.so.6 | grep -E '^GLIBC' | sort
GLIBC_2.10
GLIBC_2.11
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_2.18
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.2.6
GLIBC_2.22
GLIBC_2.23
GLIBC_2.23
GLIBC_2.24
GLIBC_2.25
GLIBC_2.25
GLIBC_2.26
GLIBC_2.26
GLIBC_2.27
GLIBC_2.28
GLIBC_2.28
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.5
GLIBC_2.6
GLIBC_2.6
GLIBC_2.7
GLIBC_2.7
GLIBC_2.8
GLIBC_2.8
GLIBC_2.9
GLIBC_2.9
可以满足要求。