Makefile学习⑦:编译动态库和静态库
编译链接动态库
动态链接库名词解释:
动态:运行时才去加载,动态加载
链接:指库文件和二进制程序分离,用某种特殊手段维护两者之间的关系
库 :库文件(window下为.dll文件,Linux下为.so文件)
使用动态链接库的好处是程序可以和库文件分离,可以分别发版,然后库文件可以被多处共享
动态链接库:不会把代码编译到二进制文件中,而是运行时才去加载,所以只需要维护一个地址
-fPIC 产生位置无关的代码
-share 编译成共享库
-l(小写L) 指定动态库
-I(大写I) 指定头文件目录,默认为当前目录
-L(大写L) 手动指定库文件搜索目录,默认只链接共享目录
随便写个加法函数,将其编译成动态库
add.h
#ifndef _ADD_H_
#define _ADD_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
#include <stdlib.h>
int add(int num1,int num2);
#ifdef __cplusplus
}
#endif
#endif
add.c
#include <stdio.h>
#include <stdlib.h>
#include "add.h"
int add(int num1,int num2)
{
int ret = 0;
ret = num1 + num2 ;
return ret;
}
使用如下编译命令将add.c编译为libadd.so动态库文件
gcc -shared -fPIC add.c -o libadd.so
随后再通过链接动态库的方式编译main函数
main.c
#include <stdio.h>
#include <stdlib.h>
#include "add.h"
int main(void)
{
int a = 1;
int b = 2;
int addRet = 0;
addRet = add(a, b);
printf("a + b = %d\n",addRet);
return 0;
}
编译命令
gcc -o main main.c -L./ -ladd
执行完编译命令后会生成可执行文件main,但是在执行该文件的时候可能会出现报错。
原因是因为该默认链接的动态库路径未找到libadd.so文件
解决办法有2种
一:将libadd.so拷贝到默认链接的动态库路径下(Linux系统下路径一般为/usr/lib或者)
sudo cp libadd.so /usr/lib/
拷贝完毕后再次执行该文件则成功
二:运行时手动指定动态库的目录
具体命令如下:
export LD_LIBRARY_PATH=(你的动态库所在的路径)
若无法确定完整路径可直接在动态库当前目录输入pwd命令查看当前路径,直接复制即可
此方法仅限于当前shell命令窗口和当前用户使用,若退出或者新建shell窗口则无效,属于临时的方法。
编写Makefile实现编译链接动态库
注意在编写Makefile的时候不要忘记了把链接动态库的路径加上,可参考前两种方法。
此处博主采用临时环境变量的方法,因为第一种直接拷贝的方法,针对于无root权限的用户来说无法使用会报错。
编译静态库
静态链接库:会把库中的代码编译到二进制文件中,当程序编译完成后,该库文件可以删除。
Linux系统中的静态库为.a文件,Windows系统中的静态库为.lib文件
区别于动态链接库:
①动态链接库必须与程序同时部署,还要保障程序能加载的到库文件
②静态库可以不用部署(已经被加载到程序里面了),而且运行时速度更快(因为不用去加载),但是会导致程序的体积更大,并且库中的内容如果有更新,则需要重新编译生成程序。
举个例子:
你要远行,在路上走三天三夜。
动态库就相当于,你背了一袋粮食路上吃,饿的时候才拿出来吃。
静态库就相当于,你在出发前先吃饱,吃饱了在上路,不带粮食。
仍然沿用编译动态库时所创建的的.c文件,采用不同的编译方式将其编译成静态库。
编译顺序如下:
首先将add.c文件编译成add.o文件
再通过命令 ar -r libadd.a add.o
将add.o文件编译生成libadd.a静态库文件
生成静态库后,再执行编译main.c链接静态库生成main程序
使用Makefile进行整合优化
代码如下:
TARGET=main
LDFLAGS=-L./
LIBS=libadd.a
$(TARGET):
$(CC) main.c -o $(TARGET) $(LDFLAGS) -static $(LIBS)
clean:
$(RM) $(TARGET)