- 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生成所有警告-Onn取值范围: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目录
不建议使用(本身包含系统库文件,可能会发生替换)
静态库与动态库的对比
两者制作过程
-
静态库制作过程
-
动态库制作过程
静态库的优缺点
- 优点
- 静态库被打包到应用程序中,加载速度快
- 发布程序无需提供静态库,移植方便
- 缺点
- 消耗系统资源,浪费内存
- 更新、部署、发布麻烦 (当某个库修改了,需要重新编译)
动态库优缺点
- 优点
- 可以实现进程间资源共享(共享库)
- 更新、部署、发布简单
- 可以控制何时加载动态库
- 缺点
- 加载速度比静态库慢
- 发布程序时需要提供依赖的动态库