【先上例子再说】[cite 1]
/*
** tools.h
*/
#include "stdio.h"
#include "stdlib.h"
void draw();
void write();
void sign();
void show();
/*
**tools.c
*/
#include "tools.h"
void draw()
{
printf("draw some graphics./n");
}
void write()
{
printf("write some characters./n");
}
void sign()
{
printf("sign your name./n");
}
void show()
{
printf("A picture by xufeng./n");
draw();
write();
printf("A picture is finished./n");
}
按照如下编译:
$ g++ -fPIC -shared -o libmytools.so tools.c
执行生成一个libmytools.so文件,按照Linux标准对象的命名惯例,应该在库名称之前加上"lib"前缀, 尽管不是必须的。编译开关-fPIC代表函数符号可以重定向[更多介绍请参考 cite 7 结尾部分],-shared代表编译结果是一个标准对象。
不同于Win32DLL,Linux标准对象中的所有函数都是直接导出的,都可以被调用程序 所访问。下面我们编写调用程序:
/*
** test.c
*/
#include "tools.h"
main()
{
show();
printf("success!/n");
}
按照如下gcc编译:
$ g++ -o test test.c ./libmytools.so
或者 :
$ g++ -o test test.c -L./ -lmytools
-L选项表示用户指定的库函数的搜索位置,-lmytools表示加载libmytools.so这个共享库[cite 5,6]。
【工作原理说明】
1 为什么要使用库?
我们用C/C++语言编译、链接生成可执行文件,有一些常用的函数(例如:打印到屏幕printf,开根号sqrt,求幂pow),我们不想每次写程序的时候都把这些函数自己重写一遍,而是利用别人现成的结果[cite 3]。
2 库的工作原理是怎样的?
库分成两种[cite 4]:静态库和共享库。
静态库文件名为 如果你使用静态库,那么你所使用到的库会被整合到你生成的可执行文件中。使用静态库的好处是,即使你所使用的库升级了、或者被误删除了,你生成的这个可执行文件仍然可以使用。缺点是,这样生成的可执行文件比较大,而且占用更多的内存[cite 4]。
如果你的可执行文件使用共享库,它会包含一个叫做import directory的表,该表包含可执行文件所使用的所有库的名字。根据表中记录,操作系统在硬盘上——[lab File_Place] 默认位置(\lib,\usr\lib等)、LD_LIBRARY_PATH[cite 2,3]、可执行文件所在的目录(本人测试结论)——搜索需要的库,然后将它们加载到内存中,之后将它们在内存中的地址更新到可执行程序中。可执行程序根据库在内存中的地址调用库中的函数或引用库中的数据[cite 4]。可以使用ldd [filename]来查看[filename]所对应的文件所用到的库的名称、操作系统在磁盘上哪里找到了这些库文件、它们在内存中对应什么地址[cite 3]。这样做的好处是,多个可执行文件、多个进程可以共享一个库,不论是磁盘还是内存上都节约了空间。缺点是,库文件升级以后可能会导致错误;如果没有安装相应的库,某些应用程序无法使用(找不到库文件)[cite 4]。
【实际操作】
1 如何生成我们自己的库?
按照编写一般C语言的方法去写一个源程序,唯一不同的是不需要main函数。
a. 生成静态库
略 有精力再看吧。
提示:
创建一个静态库是相当简单的。通常使用 ar 程序把一些目标文件(.o)组合在一起,
成为一个单独的库,然后运行 ranlib,以给库加入一些索引信息。
[cite 3 search "ar"]
b. 生成动态库
假设你编写的源文件为[sourcename].c和[sourcename].h
g++ -fPIC -shared -o lib[libname].so [sourcename].c ([sourcename]表示你用来生成库的源文件的文件名,[libname]表示你希望声称的库的文件名)
2 如何使用我们创建的、别人创建的库?
要做到以下三点[cite 6]:
a 在我们的源程序中include相应的头文件(#include "[sourcename].h")
b 编译时指定[sourcename].h的位置(如果在当前目录下可以不指定) -I目录位置(如-I./) 注意没有空格
c 编译时指定lib[libname].so的位置(如果在当前目录下可以不指定) -L目录位置(如-L./) 注意没有空格
d 编译时加载lib[libname].so -l[libname] (如-lm,加载libm.so) 注意没有空格
e 运行时保证所需要的so文件在指定位置(见上文 [cite File_Place])
转载时请注明原始链接: http://blog.renren.com/blog/bp/Q7sbEoWez5
参考文献
[1][转]在linux下编写动态链接库的步骤 httpp://blog.csdn.net/dfman1978/article/details/5921166
[2]学习 linux下如何编写动态链接库 http://blog.sina.com.cn/s/blog_67eb1f2f0100mgnd.html
[3]静态、共享和动态库的使用 http://ruikai.blog.hexun.com/3498786_d.html
[4]wiki 库 http://zh.wikipedia.org/wiki/%E5%BA%93_(%E8%AE%A1%E7%AE%97%E6%9C%BA)
[5]《嵌入式Linux应用程序开发详解》3.4.2 Gcc编译选项分析
[6]gcc中的-I -L -l选项http://blog.sina.com.cn/s/blog_68b1a51b01012j13.html
[7]gcc编译流程及编译选项分析 http://blog.sina.com.cn/s/blog_498a6eeb0100tyx4.html
[8]百度百科LD_LIBRARY_PATH http://baike.baidu.com/view/1270749.htm