本文已参与「新人创作礼」活动,一起开启掘金创作之路。
GCC编译选项
| GCC编译选项 | 说明 |
|---|---|
| -E | 预处理指定源文件,不进行编译 :.i文件 |
| -S | 编译指定的源文件,不进行汇编 :.s文件 |
| -c | 编译、汇编指定源文件,但不进行链接:.o文件 |
| -o [file1] [file2] / [file2] -o [file1] | 将文件file2 编译成可执行文件file1:.exe/.out文件 |
| -I [directory] (大写i) | 指定include包含文件的搜索目录 |
| -g | 在编译的时候,生成调试信息,该程序可以被调试器调试、 |
| -D | 在程序编译的时候,指定一个宏 |
| -w | 不生成任何警告 |
| -Wall | 生成所有警告 |
| -On | n取值范围:0-3.编译器的优先选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3为优化级别最高 |
| -l (小写L) | 在程序编译的时候,指定使用的库 |
| -L | 指定编译的时候,搜索的库的路径 |
| -fPIC/fpic | 生成与位置无关的代码 |
| -shared | 生成共享目标文件,通常用在建立共享库时 |
| -std | 指定C方言:如-std=c99,gcc默认方言为GNU C |
静态库的制作和使用
命名规则
- Linux: libxxx.a
- Windows: libxxx.lib 其中xxx为指定名称
制作过程
- gcc获得 .o 文件
gcc -c xxx.c xxx.c //生成对应的.o文件
- 将.o文件打包,使用ar工具(archive)
ar rcs libxxx.a xxx.o xxx.o //生成静态库 libxxx.a
1. r - 将文件插入备存文件中
2. c - 建立备存文件
3. s - 索引
使用静态库
gcc main.c -o app -I ./include/ -l calc -L ./lib/
//main.c 为需要编译的函数 app为最终生成可执行文件名称 -I表示头文件搜索目录 -l表示指定库名称 -L表示搜索库路径
//命名规则: calc 会去查找 libcalc.a
动态库的制作和使用
命名规则
- Linux:libxxx.so,其在Linux下是一个可执行文件
- Windows:libxxx.dll
制作过程
- gcc得到 .o 文件,得到和位置无关的代码
gcc -c -fpic a.c b.c //将a和b两个源文件进行编译、汇编,且生成与位置无关的代码
- gcc得到动态库
gcc -shared a.o b.o -o libcalc.so //将对应的.o文件生成目标动态库
使用动态库
- 程序启动后,动态库会被动态加载到内存中,通过 ldd 命令检查动态依赖关系
- 如何定位共享库文件:
- 当系统加载可执行代码的时候,能够知道其所依赖库的名字,但还需要知道其绝对路径。此时就需要系统的动态载入器来获取该绝对路径。
- 对于elf格式的可执行文件,是由ld-linux.so来完成的,他先后搜索elf文件的 DT_RPATH段→ 环境变量 LD_LIBRARY_PATH → /etc/ld.so.cache文件列表 → /lib/, /user/lib目录 找到库文件后将其载入内存。
对于如下的存储,其中include存储头文件,lib存储动态库,main.c为主函数,src存放其他源函数
gcc main.c -o app -I include/ -l calc -L lib/ //生成app可执行文件
ldd app //检查动态依赖关系
linux-vdso.so.1 (0x00007ffffd7fc000)
libcalc.so => not found //内存中没找到动态库
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007effdbc92000)
/lib64/ld-linux-x86-64.so.2 (0x00007effdbe9b000) //动态载入器
在生成目标可执行程序后,无法运行,因为动态库需要在运行时,加载进内存中。
一、配置到本地环境变量
- 临时的,切换终端就会失效:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/moens/xxx/lib //添加动态库绝对路径进环境变量
echo $LD_LIBRART_PATH //查找动态库环境变量
ldd app
linux-vdso.so.1 (0x00007ffebd74e000)
libcalc.so => /home/moens/Linux/xxx/lib/libcalc.so (0x00007fa75a97f000) //找到
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa75a77d000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa75a98b000)
./app //运行成功
其中$LD_LIBRARY_PATH表示保持之前环境变量 :后面加入后面的变量
- 永久的,用户级别配置:
cd ~ //进入home目录
vim .bashrc (shift + G 切换到最后一行, o 在下一行 进行输入)
//最后一行输入 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/moens/xxx/lib //目标动态库的绝对路径
. .bashrc //使得修改生效 等价于 source .bashrc
- 永久的,系统级别配置:
sudo vim /etc/profile
//最后一行输入 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/moens/xxx/lib
source /etc/profile //更新修改
(如果之前进行过用户级别的配置,建议重新打开一个终端进行系统级别配置,不然会出错)
二、配置/etc/ld.so.cache文件列表
sudo vim /etc/ld.so.conf //直接在最后一行写入绝对路径 /home/moens/xxx/lib
sudo ldconfig //更新
ldd app
linux-vdso.so.1 (0x00007ffc0e9a1000)
libcalc.so => /home/moens/Linux/lesson06/library/lib/libcalc.so (0x00007fdf6cc0d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdf6ca1b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdf6cc29000)
三、动态库放入/lib/, /user/lib目录
不建议使用(本身包含系统库文件,可能会发生替换)
静态库与动态库的对比
两者制作过程
-
静态库制作过程
-
动态库制作过程
静态库的优缺点
- 优点
- 静态库被打包到应用程序中,加载速度快
- 发布程序无需提供静态库,移植方便
- 缺点
- 消耗系统资源,浪费内存
- 更新、部署、发布麻烦 (当某个库修改了,需要重新编译)
动态库优缺点
- 优点
- 可以实现进程间资源共享(共享库)
- 更新、部署、发布简单
- 可以控制何时加载动态库
- 缺点
- 加载速度比静态库慢
- 发布程序时需要提供依赖的动态库