目录
一.动静态库的原理
二.静态库
2.1制作静态库
2.2使用静态库
三.动态库
3.1制作动态库
3.2动态库的使用
一.动静态库的原理
首先要知道可执行程序的生成过程:1,预处理 2,编译 3,汇编 4 ,链接
1.预处理
头文件include的包含,删注释,#define定义符号的替换,条件编译等..形成XXX.i文件
2.编译
编译: 完成词法分析、语法分析、语义分析、符号汇总等,形成XXX.x文件
3.汇编
将汇编指令转换成二进制指令,形成符号表,最终形成XXX.o文件
4.链接
合并段表,符号表的合并和重定位, 将生成的各个xxx.o文件进行链接,最终形成可执行程序。
看下面很简单的代码:
add.cpp
#include"add.h"
int add(int a,int b)
{
int sum=a+b;
return sum;
}
add.h
#pragma once
#include<iostream>
using namespace std;
extern int add(int a,int b);
test.cpp
#include"add.h"
int main()
{
int a=10;
int b=10;
int sum=add(a,b);
cout<<sum<<endl;
return 0;
}
结果:
包头文件用"",是在当前路径上找,<>是在系统目录下找。
test.cpp形成test.o时,之前只是将该头文件展开,只找到函数的声明,add 的符号表中的地址是无效的,链接时与add.o重定位后才有效,合并段表,形成可执行程序。
我们可以将函数的实现变为XXX.o文件,放在一起,并将该函数的声明(头文件)放入系统头文件中,就可以认为形成了一个库。后面要使用这个函数就可以配合那个库去使用。
1.静态库:Linux下静态库是以.a为后缀的文件。程序在编译链接时会将库里面的代码拷贝一份放入我们的可执行程序里面,程序运行的时候将不再需要静态库。
2.动态库:在Linux下动态库是以.so为后缀的文件。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。
3.静态链接:将库里的代码拷贝到可执行程序的过程。
4.动态链接:在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)。
5.库名称的识别:例如:libc.so,只需要去掉前缀lib和后缀.so
6.链接的本质:链接.lib文件和.o文件
二.静态库
2.1制作静态库
例如:我们来实现一个加法函数与打印时间的函数,将它的方法打包成库。
add.h头文件:
#pragma once
#include<iostream>
using namespace std;
extern int add(int a,int b);
add.cpp文件:
#include"add.h"
int add(int a,int b)
{
int sum=0;
for(int i=a;i<=b;i++)
sum+=i;
return sum;
}
Print.h头文件:
#pragma once
#include<iostream>
#include<time.h>
using namespace std;
extern void Print();
print.cpp文件:
#include"Print.h"
void Print()
{
cout<<time(nullptr)<<endl;
}
步骤:
1.让所有源文件生成对应的目标文件
2.使用ar命令将所有目标文件打包为静态库
-r
(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件。-c
(create):建立静态库文件。
3.将头文件和生成的动态库组织起来
编写makefile:
libshow.a:add.o print.o
ar -rc libshow.a add.o print.o
add.o:add.cpp
g++ -c add.cpp -std=c++11
print.o:print.cpp
g++ -c print.cpp -std=c++11
.PHONY:lib
lib:
mkdir -p lib-static/lib
mkdir -p lib-static/include
cp *.a lib-static/lib //将形成的静态库放入lib-static/lib目录下
cp *.h lib-static/include //将对应的头文件放入lib-static/include目录下
.PHONY:clean
clean:
rm -rf *.o *.a lib-static
结果:
此外,我们可以用ar
命令的-t
选项和-v
选项查看静态库当中的文件。
-t
:列出静态库中的文件。-v
(verbose):显示详细的信息。
例如:
2.2使用静态库
方法1:推荐使用
使用gcc编译main.c生成可执行程序时需要携带三个选项:
-I
:指定头文件搜索路径。-L
:指定库文件搜索路径。-l
:指明需要链接库文件路径下的哪一个库。
例如:
test.cpp文件调用那两个方法:
#include"add.h"
#include"Print.h"
int main()
{
int a=1;
int b=10;
int sum=add(a,b);
cout<<sum<<endl;
Print();
}
结果:
注意:上面的路径用绝对与相对路径都可以,-I
,-L
,-l
这三个选项后面可以加空格,也可以不加空格。库的名称是去掉前缀与后缀。
补充:
- 因为编译器不知道你所包含的头文件add.h在哪里,所以需要指定头文件的搜索路径。
- 因为头文件add.h当中只有my_add函数的声明,并没有该函数的定义,所以还需要指定所要链接库文件的搜索路径。
方法2:把头文件和库文件拷贝到系统路径下
头文件路径:/usr/include/
库的路径:/lib64/
例如:
补充:使用g++编译的是.cpp,而g++就是用来编译C++程序的,所以g++编译的时候默认就找的是C++库,但此时我们要链接的是哪一个库编译器是不知道的,因此我们还是需要使用-l
选项,指明需要链接库文件路径下的哪一个库.
三.动态库
3.1制作动态库
1.让所有源文件生成对应的目标文件
用源文件生成目标文件时需要携带-fPIC
选项:产生与位置无关码。-fPIC
作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
2.使用-shared选项将所有目标文件打包为动态库
3.将头文件和生成的动态库组织起来
编写makefile:
libshow.so:add.o print.o
g++ -o libshow.so -shared add.o print.o -std=c++11
add.o:add.cpp
g++ -c add.cpp -fPIC -std=c++11
print.o:print.cpp
g++ -c print.cpp -fPIC -std=c++11
.PHONY:lib
lib:
mkdir -p lib-dyl/lib
mkdir -p lib-dyl/include
cp *.so lib-dyl/lib
cp *.h lib-dyl/include
.PHONY:clean
clean:
rm -rf *.o *.a libshow.a libshow.so lib-static lib-dyl
结果:
3.2动态库的使用
使用该动态库的方法与使用静态库的方法一样,可以使用 -I
,-L
,-l
这三个选项来生成可执行程序,也可以先将头文件和库文件拷贝到系统目录下,然后再使用-l
选项指明需要链接的库名字来生成可执行程序。
例如:生成的可执行程序的路径下不含要使用的库,发现该程序运行不起来。
方法1:拷贝.so文件到系统共享库路径下
方法二:更改LD_LIBRARY_PATH
LD_LIBRARY_PATH
是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH
环境变量当中即可。export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/LF/linux-l/lesson3/lib-dyl/lib
方法三:配置/etc/ld.so.conf.d/
/etc/ld.so.conf.d/
路径下存放的是以.conf为后缀的配置文件,这些配置文件当中存放的都是路径,系统会自动在/etc/ld.so.conf.d/
路径下找所有配置文件里面的路径,之后就会在每个路径下找你所需要的库。若将自己库文件的路径也放到该路径下,那么当可执行程序运行时,系统就能够找到我们的库文件了。再使用ldconfig
命令将配置文件更新一下,更新之后系统就可以找到该可执行程序所依赖的动态库了。
例如:
[LF@ecs-100710 lesson3]$ echo /home/LF?linux-l/lesson3/lib-dyl/lib > xx.conf
[LF@ecs-100710 lesson3]$ sudo cp xx.conf /etc/ld.so.conf.d/
[LF@ecs-100710 lesson3]$ sudo ldconfig
[LF@ecs-100710 lesson3]$ ./test
55
1669019703