红联Linux门户
Linux帮助

linux下的动态链接库笔记

发布时间:2008-09-27 15:55:06来源:红联作者:Mwany
  加载动态链接库需要的头文件是 ldfcn.h

  主要的函数有 : dlopen dlsym dlerror dlclose

  编译动态库源文件时要带 -fPIC 参数

  gcc -fPIC -c test.c

  链接出so文件时要用 -shared 参数

  gcc -shared -o test.so test.o

  要使用的动态库被链接时一般会用-dynamic参数

  gcc -rdynamic -o main main.cpp -ldl

  dlsym只能找到函数和变量,不能找到类的定义,在动态库中使用类有些小技巧。

  首先c++编译时会把函数名字变得很怪,当使用dlsym时就会找不到这个函数,这就要extern "C"来发挥作用。

  把c++的文件中需要导出的函数都用extern "C"来修饰,函数名在编译时就不会被毁坏了,但同时,由于加了修饰,也就意味着这个函数是不能重载的。(所有需要用dlsym寻找的函数名,要用extern "C"来修饰,其他的就不用管)。

  其次,既然dlsym不能找到类定义,就想个新的产生类,并能使类可以被正常使用的方法。这个就要用多态来实现了。在库的头文件中,定义一个虚拟的基类,同时定义下所有的操作,在cpp文件中,开始定义这个类的所有子类和子类的实现(子类的定义当然也可以放到其他的头文件中)。为了能得到具体类,而dlsym又只能去找到函数,就有必要在头文件中定义2个工厂函数,一个用来按参数产生具体类,另一个则负责销毁具体类。动态库的这种定义方式很适合做插件。类中的函数不用extern "C"来修饰,因为你不会用dlsym去找它们。那两个工厂函数是要导出的,并且是产生和销毁对象的唯一方式,它们需要extern "C"来修饰。

  在动态库源文件中可以使用一些自身没有定义的函数和变量,这些东西就是未决定的符号。当一个使用动态库的程序dlopen打开了动态库时,这些函数中使用的未决定的符号就会被重新解析。解析的时间由dlopen的参数来决定

  RTLD_NOW是说现在就开始解析,如果发现有些符号仍然是找不到的,那么就会解析失败,dlopen返回空指针。

  RTLD_LAZY是说现在先不解析那些未决符号,等到使用dlsym来找某个函数时对那个函数作解析。

  RTLD_LOCAL 和 RTLD_GLOABL可以用或操作加在上面两个参数上。它们决定了自己使用的符号对于外部的其他动态库是否可见。

  如果动态库a.so里面定义了一个函数hello。

  在动态库b.so中的world函数使用了名为hello的函数,而b本身没有定义hello。b中的hello就是未决的符号。

  有个程序main要同时使用动态库a.so和b.so时,并且main没有定义过名字是hello的函数,它先装载a库

  dlopen("a.so", RTLD_LAZY | RTLD_GLOBAL)

  因为使用了RTLD_GLOBAL参数,其他任何在后面load的动态库都能看到a库中定义的hello函数,接下来如果载入b库,并且要求立刻解析所有符号,也不会有问题

  dlopen("a.so", RTLD_NOW)

  但如果在装载a库时没有使用RTLD_GLOBAL,在装载b库时,它就认为外面没有叫hello的函数,由于符号解析失败,dlopen就会立刻返回一个NULL。

  多使用impl idiom,可以有效降低头文件依赖。这个idiom中的指针需要在生成新对象时也新分配一个,如果不想简单的去new一个,就用一个fixedAllocator吧,使用库还是自己写都不是很麻烦,又能有效地提高效率。
文章评论

共有 1 条评论

  1. cwqing1973 于 2008-09-28 13:04:50发表:

    努力吧,说得好。