往返徒劳——劳而无功——功成不居——居官守法——法外施仁——仁浆义粟——粟红贯朽——朽木死灰——灰飞烟灭——灭绝人性
作为一名程序员,写代码是家常便饭,所以对于代码的管理非常重要,在以后的团队项目开发中,都是队员分工合作,每个人负责一部分代码,实现各自的功能,最后整合起来,那么,这么多的代码文件,要怎么编译呢?显然,全部一起编译不太现实,编写一个Makefile也不现实,因为不好修改。那么我们可以通过制作库文件来灵活管理我们的代码,上篇文章已经提到过链接库生成可执行文件,那么,我们就谈一谈什么是库。
库文件将所有的“.o”文件打包整合到一起,分为静态库和动态库(共享库) |
静态库:代码的归档,每次使用时都会直接复制代码段到目标文件中。
动态库:代码的集合,每次使用时都不用复制代码段,而是提供代码的地址,即使用我们的函数指针。
从他们的特点不难发现,静态库的优点是速度快,因为直接复制嘛,而且链接成功后会与库文件完全脱离,但是由于每次都复制代码段,会造成占用空间非常大,不利于我们的修改和维护。而动态库每次链接成功以后目标文件和动态库文件必须存在才可以运行代码,所以速度比较慢,但是占用空间小,修改和维护比较便利,好比每次要用到动态库,他都要去寻找。
那么,动静态库各有优点和缺点,我们应该用哪个呢?两害取其轻嘛,虽然动态库时间稍慢,但是对于我们嵌入式的开发而言,速度稍慢没关系,要是内存空间不足那可是致命的,因此,我们开发项目时绝大多数情况使用动态库,而我们C程序员只需要提供两样东西,即动态库和头文件。
下面就谈一谈他们的制作步骤以及调用方式吧:
静态库的创建和使用:
创建步骤:
1、写源程序,保存退出:
add.c
int add(int a, int b)
{
return a + b;
}
add1.c
double add1(double c, double d)
{
return c + d;
}
add.h
#ifndef ADD_H_
#define ADD_H_
int add(int, int);
double add1(double, double);
#endif
2、将源程序编译为.o文件(头文件不用管)
gcc -c add.c
gcc -c add1.c
这里也许有人会问,add.c和add1.c文件为什么不需要任何头文件,这是因为只有在调用函数的时候才会使用到头文件,在add.c和add1.c里面只有函数的声明,并没有调用,所以不需要加头文件,而此时编译只是单纯的找语法错误,我们写的东西没有语法错误,就能生成.o文件:
3、将所有的.o文件打包成静态库文件(lib库名.a)
ar -r libmyku.a add.o add1.o
调用步骤:
1、写调用的代码,保存退出
main.c
#include <stdio.h>
#include "add.h"
int main(int argc, char **argv)
{
printf("add is %d\n", add(1 ,2));
printf("add1 is %f\n", add1(1.1, 2.2));
return 0;
}
2、编译调用代码为.o文件
3、链接调用程序和静态库文件,有三种方法:
<1>直接链接法
gcc main.o libmyku.a
<2> 双L链接法(直接用库名,不要前缀和后缀)
gcc main.o -l库名 -L库所在目录 |
gcc main.o -lmyku -L. //我的源程序名为main.c,然后库名为myku,库文件在当前路径,所以用“.”
<3>单l链接法,首先配置环境变量LIBRARY_PATH,将库所在的目录配置进去:
export LIBRARY_PATH=. //我的库就在当前目录
动态库的创建和使用(记得将上面的静态库删除)
创建步骤:
1、写源程序,保存退出
(这里我们用上面静态库的源程序add.c,add1.c)
2、编译生成动态库文件 (lib库名.so)
gcc -fpic -shared add.c add1.c -olibmyku.so //这几个选项是基本格式。
调用步骤:
与静态库的步骤完全一样。
从图中可以看见,动态库我们不能直接这样做,虽然能够生成“a.out”文件,但是却执行不了,因为找不到我们的库文件
我们可以使用ldd来查看我们的文件所关联的共享库
我们可以发现确实缺少了我们的库文件。这是因为动态库在运行期间需要配置环境变量,因为动态库是在用的时候去寻找的
好了,链接库的创建以及使用就在这里了。