一. 静态库与动态库
1. 静态库:程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库。
静态库命名格式是libxxx.a
2. 动态库:程序在运行的时候才去链接动态库的代码多个程序共享使用库的代码。一个与动态链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
动态库命名格式是libxxx.so
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
二. 那么我们该怎么生成静态库、动态库呢?又该怎么使用它们呢?
我们先写一段代码,做测试用
//add.h
#ifndef _ADD_H_
#define _ADD_H_
int add(int a, int b);
#endif
//sub.h
#ifndef _SUB_H_
#define _SUB_H_
int sub(int a, int b);
#endif
//add.c
#include "add.h"
int add(int a, int b)
{
return a+b;
}
//sub.c
#include "add.h"
int sub(int a, int b)
{
return a-b;
}
//main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
int a=0;
int b=0;
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, add(a, b));
return 0;
}
1. 静态库
其中:
1. ar是gnu归档工具,rc表示replace and create
2. 可以使用ar -tv libsem.a来查看静态库中的目录列表,其中t:列出静态库中的文件,v:verbose详细信息
3. 生成静态库,接下来是生成我们的主程序了-L 指定库路径, -l指定库名
4. 可以发现,我们把静态库删除了,程序仍然是可以运行的,这正说明了程序把库的代码链接到了可执行文件中。
2. 动态库
其中:
1. shared:表示生成共享库格式; fPIC:产生位置无关码
什么是与位置无关?
我们知道,每一个进程都有自己独立的地址空间。在动态库链接的时候,可执行文件调用动态库的符号实际上是就是需要引用其他运行模块的符号了。对于可执行文件而言,将其加载到哪个地址并不关键,反正每个进程都有自己独一无二的地址空间,但是如果我们不将动态库编译成与位置无关的代码,那么在编译的时候,一定会把动态库加载到某个特定的地址上,如果动态库很多的话,就很有可能出现地址冲突。因此,建议大家还是加上-fPIC生成与位置无关的代码。
2. -l 链接动态库; L 链接库所在的路径
但是我们发现程序并没有运行成功。这是因为程序按照默认共享库路径找不到共享库文件。
有三种方式可以解决这一问题:
- 将.so文件拷贝到系统共享库路径下,一般是指/usr/lib
- 通过更改环境变量LD_LIBRARY_PATH
将动态库所在的路径设置为环境变量。 - 通过ldcinfig配置/etc/ld.so.conf.d/,ldconfig更新
将动态库所在的位置放到/etc/ld.so.conf.d/下的文件中,通过ldconfig更新,就可以运行成功了。
3.如果我们将动态库删了,那么代码也将不能运行了
4.动态库也是可执行程序的一种。
5.我们可以对比发现,用静态库生成的可执行文件的大小要比使用动态库生成的文件大。
6.共享库的调用方式有两种:显示调用和隐式调用。隐式调用是指在我们的程序代码中没有明确指定调用了哪些共享库,只是包含了对应的头文件,在编译的时候需要具体指明调用了哪个库。至于显示调用,我还没有了解到,有兴趣的可以参考这篇博客。
通常,我们编写的程序默认使用的都是动态库,之前在写线程的相关程序时,就用到了线程库这一动态库。
最后,再介绍一个Linux中的命令strip塑身,一般用于对静态库或动态库使用,删掉一些不必要的东西,使其变小。