前言
这次在排查 gcc 编译时遇到的问题时,对 gcc 编译的理解又加深了一点,现分享给大家。在这之前,请先阅读下我之前写的两篇文章:详解三大编译器:gcc、llvm 和 clang 详解 gcc 编译、链接原理—揭开应用程序运行背后的奥秘
什么是 gcc
[gcc 官方网站](https://gcc.gnu.org/)
GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器。它是以 GPL(General Public License)许可证所发行的自由软件,也是 GNU 计划的关键部分(GPU 是一个软件工程项目,是 GNU’s Not Unix 的缩写)。
GCC 原本作为 GNU 操作系统的官方编译器,现已被大多数类 Unix 操作系统(如Linux、BSD、Mac OS X等)采纳为标准的编译器,GCC 同样适用于微软的Windows。GCC 是自由软件过程发展中的著名例子,由自由软件基金会以 GPL 协议发布。
什么是 glibc
[glibc 官方网站](
https://www.gnu.org/software/libc/)
glibc 是 gnu 发布的 libc 库,即 c 运行库。glibc 是 linux 系统中最底层的 api,几乎其他任何的运行库都会依赖 glibc. glibc 除了封装 linux 操作系统所提供的系统服务外,它本身提供了许多其它一些必要服务的实现,主要有:
- string:字符串处理
- signal:信号处理
- dlfcn:管理共享库的动态加载
- direct:文件目录操作
- elf:共享库的动态加载器,即 interpreter
- iconv:不同字符集的编码转换
- inet:socket 接口的实现
- intl:gettext 的实现
- io
- linuxthreads
- locale:本地化
- login:虚拟终端设备的管理,及系统的安全访问
- malloc:动态内存管理的分配与管理
- nis
- stdlib
- math
gcc 和 glibc 的关系
首先,gcc 是编译器,基本上 linux 下所有程序(包括内核)都是 gcc 编译的,libc 也是。但 gcc 和 libc 又是相互依赖的,什么意思呢?就是在编译 c/cpp 代码时,既需要 gcc,也需要 libc.
gcc 发行版本
截止2021年8月,最新版本已经到 gcc11.2 了。
glibc 发行版本
截止2021年8月,最新版本已经到 glibc2.34 了,历史版本有 glibc2.29、2.30、2.31、2.32、2.33 等。
查看命令
1、查看当前系统的 glibc 版本
- 方法1:
/lib/x86_64-linux-gnu/libc.so.6
为什么这个库可以直接运行呢?原来是在 libc 的代码中有一点小手脚:
void
__libc_main (void)
{
__libc_print_version ();
_exit (0);
}
- 方法2:
ldd 命令也是 glibc 提供的,所以也能查看 glibc 版本:
ldd --version
2、查看 glibc 的 api 版本
strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC
3、查看 so 信息
`objdump -p test_gcc.so`,其他类似命令还有 `nm` 和 `readelf`
4、查看当前so依赖哪些so
- 方法1:
`ldd test_gcc.so`
- 方法2:
`objdump -x test_gcc.so | grep NEEDED`
5、获取 gcc 依赖的某个 so 文件位置
`gcc --print-file-name=libz.so.1`
6、查看当前使用的 gcc 版本和引用的头文件路径
`echo | gcc -v -x c -E -`
7、查看当前so使用了GLIBC_2.23中哪些函数
`objdump -T test_gcc.so | grep GLIBC_2.23`
8、查看当前so使用的memcpy版本
`nm test_gcc.so | grep memcpy -w`
`objdump -T /lib/x86_64-linux-gnu/libc.so.6 | grep memcpy`
9、设置 c、c++ 头文件路径
`export CPLUS_INCLUDE_PATH=/opt/compiler/gcc-8.2/x86_64-custom-linux-gnu/include/c++/8.2.0:/usr/include/x86_64-linux-gnu/`
`export C_INCLUDE_PATH=......`
10、编译时如何设置链接器版本
指定正确的 ldd 路径,也就是对应具体的 glibc 版本(非常重要)。
11、设置链接库路径
- 方法1:
先查看:`echo $LD_LIBRARY_PATH`,可通过该环境变量直接设置。
或者,`gcc –print-search-dirs`
- 方法2:使用动态库管理命令 ldconfig
`ldconfig -v`: 查看所有动态链接库
`vim /etc/ld.so.conf`,显示 `include /etc/ld.so.conf.d/*.conf`,然后`cd /etc/ld.so.conf.d`
修改完之后,要重新运行下 `ldconfig`
解释:
linux 下的共享库机制采用了类似于高速缓存的机制,将库信息保存在`/etc/ld.so.cache`里边。
程序连接的时候首先从这个文件里边查找,然后再到`ld.so.conf`的路径里边去详细找。
这就是为什么修改了`ld.so.conf`要重新运行一下`ldconfig`的原因
12、c++ 标准库: stdlibc++ 和 libc 的版本号是不一样的
`objdump -T /usr/lib/gcc/x86_64-linux-gnu/5/libstdc++.so | grep GLIBCXX`
13、gcc 头文件的搜索路径顺序
1. 优先搜索`-I`指定的路径
2. 查找GCC的环境变量`C_INCLUDE_PATH`/`CPLUS_INCLUDE_PATH`/`OBJC_INCLUDE_PATH`指定的路径
3. 查找默认的搜索路径`/usr/include`、`/usr/local/include`
14、gcc搜索链接库(编译期 + 运行期)的顺序
gcc在编译时按照如下顺序寻找所需要的库文件:
1. gcc会去找`-L`指定的目录
2. 再找gcc的环境变量`LIBRARY_PATH`
3. 再找内定目录
- /lib和/lib64
- /usr/lib 和/usr/lib64
- /usr/local/lib和/usr/local/lib64
这是当初 compile gcc 时写在程序内的。
这里有两个问题:
- 默认情况下,gcc编译时只会查找相应的头文件,而不会连接具体的lib。也就是说只要include设置完全,就可以编译通过。它没有进一步检查include中的类和函数有没有实现,而是在运行时才开始查找。所以就会经常发生编译可以通过,但运行时却无法运行,因为在运行时它找不到相关类或者函数的实现。
这时,使用`-Wl`,`–no-undefined`参数,如果使用了 include 文件,链接器却找不到相应的实现,就会产生错误提示。
- 编译时默认不查找当前目录,需要使用`-L ./`指定,例如
运行时动态库的搜索路径的先后顺序是:
1. 编译目标代码时指定的动态库搜索路径;这是通过gcc的参数`-Wl,-rpath=`指定。当指定多个动态库搜索路径时,路径之间用冒号 :分隔
2. 环境变量`LD_LIBRARY_PATH`指定的动态库搜索路径
3. 配置文件`/etc/ld.so.conf`中指定的动态库搜索路径
4. 默认的动态库搜索路径,如:`/lib`, `/usr/lib`
注意:
1. 动态库搜寻路径并不包括当前目录,所以当即使可执行文件和其所需的so文件在同一文件夹,也会出现找不到问题
2. 一般不推荐直接修改环境变量,而是修改`/etc/ld.so.conf`,将相应的路径添加上,然后`ldconfig`一下就好
3. ldconfig做的这些东西都与运行程序时有关,跟编译时一点关系都没有,编译的时候还是该加`-L`就得加,不要混淆了
4. 往`/lib`和`/usr/lib`里面加 `lib`,是不用修改`/etc/ld.so.conf`的,但是完了之后要调一下`ldconfig`(很重要),不然这个`lib`会找不到。而往其他目录加`lib`,需要修改`/etc/ld.so.conf`,并且要`ldconfig`一下。
15、如何安装指定版本glibc
- 从官网下载,解压,如 ./glibc-2.21
- cd glibc-2.21
- mkdir build
- mkdir /opt/glibc-2.21
- cd build
- ../configure –prefix=/opt/glibc-2.21
- apt-get install gawk
- make
- 需要解决一些编译告警或错误问题
- 报错(解决):./stdlib/setenv.c +270
- 报错(未解决):
../sysdeps/x86_64/multiarch/strstr.c:47:30
- 未完待续。。。
好了,这篇文章的内容营销圈就和大家分享到这里,如果大家对网络推广引流和网络创业项目感兴趣,可以添加微信:Sum8338 备注:营销圈引流学习,我拉你进直播课程学习群,每周135晚上都是有实战的推广引流技术和网络创业项目课程分享,当然是免费学!