库是代码共享的主要方式,动态库和静态库的主要区别在于他们链接形式的不同(静态和动态链接),它们都是目标文件的集合,再加上一些索引表项来表征各文件的信息。通常,linux里目标文件是ELF格式,而win则为PE
linux下静态库是以.a为后缀,而win下静态库是以lib为后缀。
静态链接是由链接器将一个或多个目标文件及静态库中所被引用的目标文件完全链接到一个可执行文件中,由链接器完成所有的工作,包括符号解析和重定位。
该可执行文件直接由驻留在内存里的加载器加载执行即可。
用一个小的静态库作为例子:
queue.h
#ifndef _QUEUE_H_
#define _QUEUE_H_
int queue[16] = {0};
int head = 0;
int rear = 0;
#endif
append.c
extern int queue[16];
extern int head;
extern int rear;
int append(int ele)
{
if ((rear + 1) % 16 == head)
return 0;
else
{
rear = (rear+1) % 16;
queue[rear] = ele;
return 1;
}
}
serve.c
extern int queue[16];
extern int head;
extern int rear;
int serve()
{
if (head != rear )
{
head = (head + 1) % 16;
return queue[head];
}
else
return -1;
}
main.c
#include
#include"queue.h"
extern int head;
extern int rear;
int main()
{
int i;
for (i = 1; i <= 20; i++)
{
if (!append(i))
{
printf("%d ",serve());
i--;
}
}
while (head != rear)
printf("%d ",serve());
return 0;
}
首先,我们把两个实现的函数编译为目标文件:
gcc -c append.c
gcc -c serve.c
然后用ar工具打包为
ar rcs libqueue.a append.o serve.o
静态库选项r 表示将后面的文件列表添加到文件包,如果文件包不存在就创建它,如果文件包中已有同名文件就替换成新的。c表示创建一个库,s 是专用于生成静态库的,表示为静态库创建索引,这个索引被链接器使用。ranlib 命令也可以为静态库创建索引,以上命令等价于:
ar rc libqueue.a append.o serve.o
ranlib libqueue.a
最后即可生存我们的主程序:
gcc -o queue main.c ./libqueue.a
linux里动态库以so作为后缀,而win里则是dll
动态链接从某个角度说,可以说是把静态链接的过程进行了拆分。当创建可执行文件时,静态执行一些链接,然后在程序加载时,动态完成链接过程。gcc -shared -fPIC libqueue.so append.c serve.c
编译时链接上该库
gcc -o queue main.c ./libqueue.so
于是,上面的例子也可以实现为:main2.c
#include
#include
#include"queue.h"
extern int head;
extern int rear;
int main()
{
void *handle;
int (*serve)();
int (*append)(int);
char *error;
int i;
if ((handle = dlopen("./libqueue.so",RTLD_LAZY))== NULL)
{
printf("Fail to load dynamic lib!\n");
return 1;
}
serve = dlsym(handle, "serve");
if ((error = dlerror()) != NULL)
{
printf("symbol serve not found!\n");
return 1;
}
append = dlsym(handle, "append");
if ((error = dlerror()) != NULL)
{
printf("symbol append not found!\n");
return 1;
}
for (i = 1; i <= 20; i++)
{
if (!append(i))
{
printf("%d ", serve());
i--;
}
}
while (head != rear)
printf("%d ", serve());
dlclose(handle);
return 0;
}
注意编译时带上-rdynamic参数并且链接libdl.so:
gcc -rdynamic -o queue main.c -ldl