
文章目录
- 前言
- 静态库
- 静态库制作
- 静态库的生成
- 发布静态库
- 使用静态库
- 安装静态库
- 卸载静态库
 
- 动态库
- 动态库的制作
- 动态库的生成
- 动态库的发布
- 使用动态库
 
- 动态库VS静态库
前言
在C、C++中我们使用过标准库,比如在使用strerror、vector、string等时,都只是调用了这些函数接口,这些都是需要具体的实现。
让我们来看看C语言库:

 将来运行程序,需要二进制文件和库文件
看下C++标准库:

在Linux系统中,.so结尾是动态库,以.a结尾是静态库;
 在Windows中,.dll结尾是动态库,lib结尾是静态库。
静态库
静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
.c文件可形成一个.o文件,将这些.o文件链接形成可执行文件,头文件是一个手册,提供函数声明,告诉用户如何使用,.o文件提供实现,我们只需要补充一个main文件,调用头文件提供的方法,然后和.o文件进行连接,就能形成可执行文件。
静态库制作
简单制作一个静态库
// add.h
#pragma onceint add(int x, int y);// add.c
#include "add.h"int add(int x, int y)
{return x + y;
}// sub.h
#pragma onceint sub(int x, int y);// sub.c
#include "sub.h"int sub(int x, int y)
{return x - y;
}
静态库的生成
静态库生成指令:ar -rc lib静态库名.a 需要形成静态库的文件,ar是gnu归档工具,rc表示replace and create
静态库的形成本质上是将所有的.o文件打包,因此需要先生成.o文件


发布静态库
发布静态库就是自己的lib拷贝给比人

例如上图是我自己制作的一个简单静态库,只需要将mylib拷贝给别人即可。
使用静态库
将自己的mylib拷贝到一个test文件夹中,然后写一个main.c文件,用于测试静态库的使用
mian.c:
#include "add.h"    
#include "sub.h"                                                                      
#include <stdio.h>           int main()                   {                            printf("1 + 2 = %d\n", add(1, 2));    printf("1 - 2 = %d\n", sub(1, 2));    return 0;                                                        } 
编译:

这里报错了,说找不到对应的头文件
 头文件一般有以下两种方式来包含头文件:
- 使用<>来包含头文件,表示到系统指定目录下去查找头文件
- 使用" "来包含头文件,这种方式一般用于包含自己所写的头文件中,表示在当前源文件的统计目录下查找头文件,找到了就用,没找到再去系统指定目录下进行查找,所以对于库提供的头文件我们也可以使用" "进行包含。
在main.c文件中,就是使用" "来包含我所写的头文件,但是还是会报错,理由:使用" "所包含的头文件,会告诉编译器在main.c同级目录下(即test目录下)查找对应的头文件,但是add.h、sub.h文件在test文件中的mylib文件中,因此无法找到。
解决上述有三种方式:
- 将头文件直接拷贝到当前目录下
- 在代码中头文件的路劲补全,如:#include " /mylib/include/add.h "
- 在执行 gcc 指令编译的时候加上 -I选项,指定编译器搜索头文件的路径
 系统默认的指定路劲:/usr/include
  
使用方法3:gcc main.c -I ./mylib/include
 
 此时依然没有编译成功,此时不是找不到头文件,而是链接错误。gcc在编译的时候,只会去默认路径下查找打包的头文件,不会去/mylib/include中查找,编译器在gcc是就找不到我的酷libmyc.a,也就是编译链接失败。
 
此时可以形成main.o文件:
 
 解决此错误有两种方法:
- 将我们的库拷贝到系统的指定路径下,并不能完全解决,还需要指定库的名称
- 在使用 gcc的时候添加对应的选项
- -L指定库路径
- -l指定库名

为什么在搜索头文件的时候仅需指定路径呢?当你编译程序时,编译器会首先在这些默认路径下搜索所需的头文件。
 在代码中已经写了头文件的具体名称,所以仅需指定头文件的路径即可。而一个路径下可以有多个库,如果只指定路劲,编译器还是不知道该去链接哪个库,因此还要在后面使用 -l 选项指定待链接的库的具体名称。
注意:去掉前缀 lib 和 后缀 .a 才是一个库的名称,建议 -l 后面紧跟库的名称。一般在使用第三方库的时候,可能不需要带 -I 或者 -L,但是 -l 指定库的名称是一定需要到,因为 gcc 默认只能找到系统调用和语言层面的库。
安装静态库

静态库的安装本质上就拷贝到系统的特定目录下。
卸载静态库
卸载静态库本质是将.h文件和自己的静态库从默认的路劲中删除,此时就无法通过静态库来运行程序。

 
动态库
动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
动态库的制作
简单制作一个动态库
// add.h
#pragma onceint add(int x, int y);// add.c
#include "add.h"int add(int x, int y)
{return x + y;
}// sub.h
#pragma onceint sub(int x, int y);// sub.c
#include "sub.h"int sub(int x, int y)
{return x - y;
}
动态库的生成
- fPIC:产生位置无关码(position independent code)
- shared: 表示生成共享库格式
- 库名规则:libxxx.so

 
libmyc.so就是生成的动态库
动态库的发布
将动态库拷贝到刚刚我们静态库的位置

使用动态库
mian.c:
#include "add.h"    
#include "sub.h"                                                                      
#include <stdio.h>           int main()                   {                            printf("1 + 2 = %d\n", add(1, 2));    printf("1 - 2 = %d\n", sub(1, 2));    return 0;                                                        } 
按照静态库的使用方法,来使用静态库:

 虽然生成了可执行文件,但是可执行文件出错了
使用ldd a.out时,发现libmyc.so => not found,动态库没有被找到,编译期间已经告诉系统对应的头文件以及库的位置,但是这是告诉编译器,没有告诉操作系统,因此编译通过,但是无法运行。
 动态库要在程序运行的时候要找到动态库加载运行。静态库为什么没有这个问题?因为静态库在编译期间已经将库中的代码拷贝到可执行程序内部了,加载和库就没有关系了。
解决该问题,有以下四种方法:
- 将库文件拷贝到系统默认的库路(/lib64、/usr/lib64),不推荐使用这种方法,因为修改了系统规定的库,降低了系统的健康指数
- 在系统默认的库路径(/lib64、/usr/lib64)下建立软链接
  
- 将自己库所在的路径,添加到系统的环境变量 LD_LIBRARY_PATH中,该环境变量就是专门用来搜索动态库的
  
 但是重新启动系统后,就找不到该环境变量,如果想让系统启动时自动添加该路径到LD_LIBRARY_PATH环境变量中,可以通过修改~/.bash_profile中的配置去实现,但是不推荐这么写,不建议修改环境变量。
- 如果想让我们的库和系统、语言自带的库一样,在程序运行的时候可以自动被找到,那我们可以/etc/ld.so.conf.d路径下添加一个.conf结尾的配置文件
  
 该配置文件里面的内容就是我们自己动态库所在的路径。添加完后执行ldconfig指令,将所有的配置文件重现加载一下,然后程序就能够正常运行。
  
  
 此时程序就可以正常运行:

动态库VS静态库
动静态库同时存在时,默认连接的是动态库:

 此时对应的可执行程序的体积很小:

那么如何使用静态库?
 只需在后面加一个-static

 此时对应的可执行文件体积很大:

如果你没有使用-static并且只提供.a,只能静态库连接当前的.a库,其他库正常动态连接。
-static的意义是什么呢?
 必须强制的将程序进行静态连接,这就要求连接的任何库都必须提供对应的静态库版本。
