动态链接库.so

  • 格式:pdf
  • 大小:139.97 KB
  • 文档页数:4

动态链接库.so

⽤来才真正理解什么是动态链接库!⽤C++做法做接⼝,提供flash⽤;开始到做法是每次build⽣成.so,然后做链接⽣成可执⾏⽂件,引进程序过⼤,每次要花费10分钟左右。后来⾼⼿指点,.so是动态链接库。Linux下的.so是基于Linux下的动态链接,其功能和作⽤类似与windows下.dll⽂件。

下⾯是关于.so的介绍:

⼀、引⾔

通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象⽂件(object file)与牵涉到的函数库(library)被链接合成⼀个可执⾏⽂件(executable file)。程序在运⾏时,与函数库再⽆⽠葛,因为所有需要的函数已拷贝到⾃⼰门下。所以这些函数库被成为静态库(static libaray),通常⽂件名为“libxxx.a”的形式。

其实,我们也可以把对⼀些库函数的链接载⼊推迟到程序运⾏的时期(runtime)。这就是如雷贯⽿的动态链接库(dynamic link library)技术。

⼆、动态链接库的特点与优势

⾸先让我们来看⼀下,把库函数推迟到程序运⾏时期载⼊的好处:1. 可以实现进程之间的资源共享。

什么概念呢?就是说,某个程序的在运⾏中要调⽤某个动态链接库函数的时候,操作系统⾸先会查看所有正在运⾏的程序,看在内存⾥是否已有此库函数的拷 贝了。如果有,则让其共享那⼀个拷贝;只有没有才链接载⼊。这样的模式虽然会带来⼀些“动态链接”额外的开销,却⼤⼤的节省了系统的内存资源。C的标准库 就是动态链接库,也就是说系统中所有运⾏的程序共享着同⼀个C标准库的代码段。2. 将⼀些程序升级变得简单。⽤户只需要升级动态链接库,⽽⽆需重新编译链接其他原有的代码就可以完成整个程序的升级。Windows 就是⼀个很好的例⼦。3. 甚⾄可以真正坐到链接载⼊完全由程序员在程序代码中控制。

程序员在编写程序的时候,可以明确的指明什么时候或者什么情况下,链接载⼊哪个动态链接库函数。你可以有⼀个相当⼤的软件,但每次运⾏的时候,由于 不同的操作需求,只有⼀⼩部分程序被载⼊内存。所有的函数本着“有需求才调⼊”的原则,于是⼤⼤节省了系统资源。⽐如现在的软件通常都能打开若⼲种不同类 型的⽂件,这些读写操作通常都⽤动态链接库来实现。在⼀次运⾏当中,⼀般只有⼀种类型的⽂件将会被打开。所以直到程序知道⽂件的类型以后再载⼊相应的读写 函数,⽽不是⼀开始就将所有的读写函数都载⼊,然后才发觉在整个程序中根本没有⽤到它们。

三、动态链接库的创建

由于动态链接库函数的共享特性,它们不会被拷贝到可执⾏⽂件中。在编译的时候,编译器只会做⼀些函数名之类的检查。在程序运⾏的时候,被调⽤的动态 链接库函数被安置在内存的某个地⽅,所有调⽤它的程序将指向这个代码段。因此,这些代码必须实⽤相对地址,⽽不是绝对地址。在编译的时候,我们需要告诉编 译器,这些对象⽂件是⽤来做动态链接库的,所以要⽤地址不⽆关代码(Position Independent Code (PIC))。

对gcc编译器,只需添加上 -fPIC 标签,如:gcc -fPIC -c file1.cgcc -fPIC -c file2.cgcc -shared libxxx.so file1.o file2.o

注意到最后⼀⾏,-shared 标签告诉编译器这是要建⽴动态链接库。这与静态链接库的建⽴很不⼀样,后者⽤的是 ar 命令。也注意到,动态链接库的名字形式为 “libxxx.so” 后缀名为 “.so”

四、动态链接库的使⽤使⽤动态链接库,⾸先需要在编译期间让编译器检查⼀些语法与定义。

这与静态库的实⽤基本⼀样,⽤的是 -Lpath 和 -lxxx 标签。如:gcc file1.o file2.o -Lpath -lxxx -o program.exe

编译器会先在path⽂件夹下搜索libxxx.so⽂件,如果没有找到,继续搜索libxxx.a(静态库)。

在程序运⾏期间,也需要告诉系统去哪⾥找你的动态链接库⽂件。在UNIX下是通过定义名为LD_LIBRARY_PATH 的环境变量来实现的。只需将path赋值给此变量即可。csh 命令为:

setenv LD_LIBRARY_PATH your/full/path/to/dll

⼀切安排妥当后,你可以⽤ ldd 命令检查是否连接正常。ldd program.exe

动态链接库*.so的编译与使⽤动态库*.so在linux下⽤c和c++编程时经常会碰到,最近在⽹站找了⼏篇⽂章介绍动态库的编译和链接,总算搞懂了这个之前⼀直不太了解得东东,这⾥做个笔记,也为其它正为动态库链接库⽽苦恼的兄弟们提供⼀点帮助。1、动态库的编译

下⾯通过⼀个例⼦来介绍如何⽣成⼀个动态库。这⾥有⼀个头⽂件:so_test.h,三个.c⽂件:test_a.c、test_b.c、test_c.c,我们将这⼏个⽂件编译成⼀个动态库:libtest.so。

so_test.h:

#include "stdio.h"

void test_a();

void test_b();

void test_c();

test_a.c:

#include "so_test.h"

void test_a()

{

printf("this is in test_a...\n");

}

test_b.c:

#include "so_test.h"

void test_b()

{

printf("this is in test_b...\n");

}

test_a.c:

#include "so_test.h"

void test_c()

{printf("this is in test_c...\n");

}

将这⼏个⽂件编译成⼀个动态库:libtest.so$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

2、动态库的链接

在1、中,我们已经成功⽣成了⼀个⾃⼰的动态链接库libtest.so,下⾯我们通过⼀个程序来调⽤这个库⾥的函数。程序的源⽂件为:test.c。test.c:

#include "so_test.h"

int main()

{

test_a();

test_b();

test_c();

return 0;

}

l 将test.c与动态库libtest.so链接⽣成执⾏⽂件test:

$ gcc test.c -L. -ltest -o test

l 测试是否动态连接,如果列出libtest.so,那么应该是连接正常了

$ ldd test

l 执⾏test,可以看到它是如何调⽤动态库中的函数的。3、编译参数解析最主要的是GCC命令⾏的⼀个选项:-shared 该选项指定⽣成动态连接库(让连接器⽣成T类型的导出符号表,有时候也⽣成弱连接W类型的导出符号),不⽤该标志外部程序⽆法连接。相当于⼀个可执⾏⽂件

l -fPIC:表⽰编译为位置独⽴的代码,不⽤此选项的话编译后的代码是位置相关的所以动态载⼊时是通过代码拷贝的⽅式来满⾜不同进程的需要,⽽不能达到真正代码段共享的⽬的。l -L.:表⽰要连接的库在当前⽬录中

l -ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前⾯加上lib,后⾯加上.so来确定库的名称l LD_LIBRARY_PATH:这个环境变量指⽰动态连接器可以装载动态库的路径。

l 当然如果有root权限的话,可以修改/etc/ld.so.conf⽂件,然后调⽤ /sbin/ldconfig来达到同样的⽬的,不过如果没有root权限,那么只能采⽤输出LD_LIBRARY_PATH的⽅法了。4、注意

调⽤动态库的时候有⼏个问题会经常碰到,有时,明明已经将库的头⽂件所在⽬录 通过 “-I”include进来了,库所在⽂件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so⽂件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf⽂件来指定动态库的⽬录。通常这样做就可以解决库⽆法链接的问题了。

最后要注意的问题是,该test程序时,可能会提⽰ error while loading shared libraries: libtest.so:cannot open shared object file: No such file or directory这时候,只需要把已经编译好的libtest.so拷贝到/usr/lib⾥⾯就OK了,也就是说,在编译的时候,要注意可执⾏程序的路径!