之前在gcc/g++了解过动静态库,此次对其进一步理解并且自己制作动静态库。另外,库的名称要去掉前缀和后缀,如:libc.so -> c库,要去掉前缀lib,去掉后缀.so,.a
动态库和静态库
补充内容:
- 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
- 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。一般默认生成的可执行程序都是动态的,动态库体积小,运行时加载,只有一份。
- 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
动态库的代码,通过映射关系使物理内存中的C库映射到虚拟地址空间,所以多个进程只需要使用一个动态库就可以。
静态库是把硬盘上的可执行程序拷贝到代码区去运行,所以每个可执行程序都要有各自的静态库代码,因此可执行程序也更大。
生成静态库
一个库包括以下内容:
- 头文件:有什么方法可以使用,接口参数是什么意思
- 一个或多个库文件:头文件的具体的实现,供我们动静态链接。
链接的本质:链接.o
文件和lib
文件。
所以静态库的本质是将代码生成的.o
文件进行打包。
以实现一个加法和减法的静态库为例:
- 头文件
myadd.h
#ifndef __MYADD_H__
#define __MYADD_H__
#include<stdio.h>
int MyAdd(int x,int y);
#endif
- 源文件
myadd.c
#include"myadd.h"
int MyAdd(int x,int y)
{
return x+y;
}
- 头文件
mysub.h
#ifndef __MYSUB_H__
#define __MYSUB_H__
#include<stdio.h>
int MySub(int x,int y);
#endif
- 源文件
mysub.c
#include"mysub.h"
int MySub(int x,int y)
{
return x-y;
}
将这两个方法生成静态库:
-
gcc -c myadd.c
和gcc -c mysub.c
生成各自的.o
文件 -
将两个
.o
目标文件打包生成静态库:ar -rc libmymath.a add.o sub.o
(ar是gnu归档工具,rc表示(replace and create))
-
将静态库打包成mylib目录,交付时只需要交付mylib目录即可:
使用ar -tv libmymath.a
(t:列出静态库中的文件,v:详细信息)查看静态库中的内容:
打包好后,在编译的时候使用下面的选项即可使用静态库gcc $^ -o $@ -I ./mylib/include -L./mylib/mylib.a -l mymath -static
(-I告诉编译器头文件在哪,-L告诉编译器动态库在哪,-l(小L)告诉编译器库的名称(去掉前缀和后缀))即可生成使用静态库的可执行文件:
这三个选项的含义:
- -I(大i) 在指定的路径查找头文件
- -L 自定义库的搜索路径
- -l(小L) 指定库的名字,库的名字要去掉前缀lib,后缀.a
如果想不带这三个选项,可以将库文件和头文件放在系统默认的头文件和库文件下面,不过-l(小L)选项依然要带。但是不建议这样做,因为会污染系统的库。
生成动态库
仍是以上面的sub和add为例:
- 用下面的代码生成
.o
文件gcc -fPIC -c mysub.c
,gcc -fPIC -c myadd.c
,因为动态库需要随时别加载到内存,所以地址信息不能写死。fPIC:产生位置无关码,使库文件可以在内存的任意位置加载,并且不影响与其他程序的关联性。 gcc -shared -o libmymath.so *.o
将.o
文件打包成动态库,其中shared: 表示生成共享库格式。- 然后将文件打包到一个目录下。
一键生成和发布的Makefile:
要使用动态库,要更改环境变量LD_LIBRARY_PATH
,因为操作系统找不到这个动态库。我们使用的动态库都在系统的默认路径下,所以操作系统能够找到,但是我们自己写的找不到。
export LD_LIBRARY_PATH=/home/hjl/10.17_test/mylibso/lib
这个路径是动态库.so
的绝对路径。
在编译的时候使用以下命令:
gcc $^ -o $@ -I ./mylibso/include -L./mylibso/lib -l mymath