前言
目录
1.为什么有库
2.静态库
2.1 将.c文件生成同名.o文件
2.2 制作静态库
2.3 使用静态库
3.动态库
3.1 制作动态库
3.2 使用动态库生成可执行文件
3.3 运行
4.一些细节
-
静态库(.a):程序在编译链接的时候把库的二进制代码拷贝到我的程序的可执行文件中,程序运行的时候将不再需要静态库
-
动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码
如c语言库:
- 动态库 libc.so
- 静态库 libc.a
库的命名规则是:lib打头+库名+后缀去掉前缀lib,去掉.后缀,剩下的就是库名
生成可执行程序的方式有2种:动态链接,静态链接
ldd filename # 查看链接方式
1.为什么有库
在开发的时候,我们经常使用别人写的代码,包括编译别人的源码,调用别人给的第三方库,调用别人给的网络功能接口…
为什么我们要使用别人的代码?
- 提高开发效率
- 增加程序的鲁棒性
所谓鲁棒性,就是指程序的健壮性,每一个模块之间的耦合度低。对于第三方库,我们认为是没有问题的。如果我的程序出现错误,那么此时不用去怀疑调用的库本身有问题,而是一定是自己写的代码逻辑有问题,这样就使得排查的错误范围缩小了。当然,这里的库一定是指一些有权威的库,例如STL等标准库。
好了,如何使用别人的代码,学习库的打包使用很关键
2.静态库
本次实验,我们有5个原始文件:
add.h
add.c
sub.h
sub.c
main.c
#pragma once
#include <stdio.h>
int add(int x, int y);
#include "add.h"
int add(int x, int y) {
return x+y;
}
#pragma once
#include <stdio.h>
int sub(int x, int y);
#include "sub.h"
int sub(int x, int y) {
return x-y;
}
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main() {
printf("%d\n%d\n", add(20, 10), sub(20, 10));
return 0;
}
2.1 将.c文件生成同名.o文件
调用静态库是指在程序链接的时候把静态库的二进制代码链接到可执行文件中,这样运行的时候就不需要去找静态库了
好了,既然静态库是在链接那一步去链接到可执行文件中,那么根据
预处理–编译—汇编—链接
我们需要走完汇编这一步,汇编就是把汇编代码转换成机器码,生成的文件是.o
文件
gcc -c add.c
gcc -c sub.c
2.2 制作静态库
制作静态库的本质是将若干个.o文件打包
ar -ac libmymath.a add.o sub.o
使用ar -tv 查看静态库中包含的文件:
2.3 使用静态库
我们将 add.o sub.o libmymath.a 三个文件放到slib文件夹下
1.使用-I
我们得在编译链接main.c的时候把头文件目录在哪给带上
gcc main.c -o main -I ./slib/
好像漏掉了什么
2.使用-L
把库文件所在目录给带上
gcc main.c -o main -I ./slib/ -L ./slib/
好像漏掉了什么
3.使用-l
把库的名字带上(lib与.后缀之间的部分)
gcc main.c -o main -I ./slib/ -L ./slib/ -lmymath
此时,成功生成可执行文件:
运行:
3.动态库
-
一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
-
在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
-
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
3.1 制作动态库
1.生成与位置无关码
这个动态库它本身是不随着加载到内存映射到共享区的任何区域,任何位置而会影响库当中的代码地址发生相对变化而导致库不可执行库代码映射到共享区,每一个进程都用了同一份代码,不出现内存的浪费
gcc -fPIC -c add.c sub.c
2.生成动态库文件
gcc -shared -o libmymath.so add.o sub.o
3.2 使用动态库生成可执行文件
gcc main.c -o main -I dlib/ -L dlib/ -lmymath
3.3 运行
执行main
发现报错了,怎么回事?
我们不是已经在编译
的时候指定了头文件目录、库文件目录、库文件名了吗?
哦,编译的时候是指定了,但是现在是运行阶段啊,运行阶段没有指定库文件在哪里去找啊,当然找不到了
3种解决方法:
- 将我们的
libmymath.so
拷贝到系统共享库路径下,一般是/usr/lib64
或/usr/lib
- 将dlib目录添加至LD_LIBRARY_PATH环境变量
这边引出一个环境变量:LD_LIBRARY_PATH
,存放了系统默认去找动态库文件的目录
导出环境变量:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/class101/linux/lesson18/dlib
- ldconfig配置
/etc/ld.so.conf.d
在/etc/ld.so.conf.d目录下任意创建.conf文件,.conf文件中写动态库的目录
echo "/root/class101/linux/lesson18/dlib" > /etc/ld.so.conf.d/test.conf
ldconfig
4.一些细节
细节一
为什么C语言在编译的时候,从来没有显式地使用过-I -L -l等选项呢
1.头文件和库文件在默认路径下被gcc找到
2.gcc编译C代码,默认就应该找libc
如果我们也不想使用这些选项呢?
把头文件库文件拷贝到默认路径下->库的安装
细节二
gcc默认动态链接,如果没有动态链接,就去找静态链接
Makefile
main: main.c
gcc -o $@ $^ -I ./dlib -L ./dlib -lmymath
.PHONY: clean
clean:
rm -f main