gcc 编译
GCC
gcc 编译选项 | 说明 |
---|---|
-E | 预处理,但不进行编译 |
-S | 编译指定的源文件,但不进行汇编 |
-c | 编译、汇编生成目标代码,但不进行链接 |
-o file1 file2 或 file2 -o file1 | 将文件 file2 编译成文件 file1 |
-I directory | 指定头文件的搜索目录 |
-L | 编译的时候指定搜索库的路径 |
-l | 编译的时候指定使用的库 |
-g | 在编译的时候,生成调试信息,该程序可以被调试器调试 |
-D | 在程序编译的时候,指定一个宏 |
-w | 不生成任何警告信息 |
-Wall | 生成所有警告信息 |
-On | n 为 0~3,优化选项,3 级别最高 |
-fPIC/fpic | 生成与位置无关的代码 |
-shared | 生成共享目标文件,通常用在建立共享库时 |
-std | 指定 c 版本,如 -std=c99 |
预处理
1 | gcc -E main.cpp # 不会生成 .i 文件 |
编译
1 | gcc -S main.cpp # 生成 main.s |
汇编
1 | gcc -c main.cpp # 生成 main.o |
生成可执行文件
1 | gcc main.cpp |
库
- 静态库,在程序的链接阶段被复制到程序中,gcc 链接时,会把静态库中代码打包到可执行程序中
- 动态库,在程序运行时由系统动态加载到内存中供程序使用,gcc 链接时,动态库的代码不会被打包到可执行程序中
好处:代码保密,方便部署和分发
静态库
命名规则
- Linux, libxxx.a
- Windows, libxxx.lib
生成静态库
gcc -c xxx.c
获得.o
文件- 将
.o
文件打包,使用 ar 工具(archive)
1 | ar rcs libxxx.a xxx.o xxx.o |
r
将文件插入备存文件中 c
建立备存文件(库文件) s
索引
1 | 编译得到目标代码 |
动态库
命名规则
- Linux, libxxx.so
- Windows, libxxx.dll
生成动态库
1 | gcc 得到 .o 文件,得到和位置无关的代码 |
按照静态库里的程序目录生成动态库
1 | 编译得到 .o 文件 |
为什么动态库加载失败?
ldd
命令检查动态库依赖关系
1 | ldd main |
可以发现没有找到 libcal.so
所在位置
那么如何定位共享库文件呢?
当系统加载可执行代码时,能够知道其所依赖库的名字,但还需要知道绝对路径,此时需要系统的
动态载入器具 来获取该绝对路径,也就是上面
ldd
输出的 /lib64/ld-linux-x86-64.so.2
,对于
elf 格式的可执行程序,是由 ld-linux.so
来完成的,它先后搜索
elf 文件的 DT_RPATH 段,环境变量
LD_LIBRARY_PATH, /etc/ld.so.cache 文件列表,
/lib/, /usr/lib 目录 找到库文件后将其载入内存
该解决动态库加载失败?
设置
LD_LIBRARY_PATH
环境变量1
2
3
4
5
6
7
8
91. 设置临时环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/qwt/CPP/lesson07/lib
2. 设置永久环境变量
vim ~/.bashrc
在 .bashrc 文件中添加环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/qwt/CPP/lesson07/lib
使环境变量生效
source ~/.bashrc设置
/etc/ld.so.cache
文件列表1
2
3
4ld.so.cache 不能直接修改
sudo vim /etc/ld.so.conf
直接将路径粘贴到该文件中,然后更新该文件
sudo ldconfig直接将动态库文件放在
/lib/
或/usr/lib
目录下(不建议这么做)
优缺点
库小的话用静态库,大的话用动态库
静态库优点:
- 静态库被打包到应用程序中加载速度快
- 发布程序无序提供静态库,移植方便
静态库缺点:
- 消耗系统资源,浪费内存
- 更新、部署、发布麻烦
动态库优点:
- 可以实现进程间资源共享(共享库)
- 更新、部署、发布简单
- 可以控制何时加载动态库
动态库缺点:
- 加载速度比静态库慢
- 发布程序时需要提供依赖的动态库