标签:des style blog http ar io color os 使用
插件技术的目的是为了更好的扩展性.动态链接库是其中 一种实现方式.
这里主要论述几个问题.
1)linux上关于这些api的描述.看完linux上关于dlopen等函数的描述基本就可以写出简单的动态链接库使用.
2)关于c++使用动态链接库的一些问题和注意事项.
3)扩展,编译器的各选项,动态链接库和静态链接库.
摘自ubuntu kylin 14.04,内核3.13.0-32generic
#include<dlfcn.h> void *dlopen(const char *filename,int flag); char *dlerror(void); void *dlsym(void *handle,const char *symbol); int dlclose(void *handle);链接时后面加 -ldl 选项.//这里注意,-ldl一定放在编译的最后,之前写程序时如果不加在最后会报错的.
描述:
这四个函数实现动态链接库加载接口.
返回可读字符串,返回dlopen,dlsym或dlclose的错误.dlerror只是保存最近一次调用时返回的错误信息.
dlopen通过filename加载动态链接库文件,返回void*类型的handle指向该动态链接库.如果filename是NULL,在返回handle指向的该主程序.如果filename包含"/",则解释为绝对或相对路径.否则,动态链接器按照以下方式搜索库.
//ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西.//目前自己没涉及这么深的东西,只是简单的应用.可以暂时略过关于ELF的内容
1)(ELF ONLY)如果可执行文件包含DT_RPATH标签,但不包含DT_RPATH标签,则会在DT_RPATH标签列出的目录里面搜索.
2)如果环境变量LD_LIBRARY_PATH已定义且包含了冒号分割的目录列表,则搜索目录列表.
3)(ELF only)如果可执行程序包含DT_RUNPATH标签,则搜索标签中列出的目录
4)检查缓存文件/etc/ld.so.cache是否包含filename的库
5)按顺序搜索目录/lib/ 和/usr/lib
如果filename库依赖于其他共享库,这么库也会动态加载进来,按照上述搜索方式查找.
flag参数:
RTLD_LAZY:执行懒惰式绑定,只有当指向符号的代码执行时,才会解析符号.如果符号一直没有指向,则一直不会被解析.lazy binding只是针对函数引用时才生效,当加载库时,指向变量的引用经常立即受限制.
RTLD_NOW:如果该值指定,或环境变量LD_BIND_NOW是非空值,所有在库中未定义的符号在dlopen返回前都会被解析.如果执行未完成,则返回错误.
下面的参数可以通过or在flag中 指定.
RTLD_GLOBAL:动态库中定义的符号可被其后打开的其它库解析.
RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其它库重定位。如果没有指明是RTLD_GLOBAL还是RTLD_LOCAL,则缺省为RTLD_LOCAL。
RTLD_NODELETE(glibc2.2以后): 在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量。这个flag不是POSIX-2001标准。
RTLD_NOLOAD(glibc2.2以后): 不加载库。可用于测试库是否已加载(dlopen()返回NULL说明未加载,否则说明已加载),也可用于改变已加载库的flag,如:先前加载库的flag为RTLD_LOCAL,dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL。这个flag不是POSIX-2001标准。
RTLD_DEEPBIND(glibc2.3.4以后):在搜索全局符号前先搜索库内的符号,避免同名符号的冲突。这个flag不是POSIX-2001标准。
如果filename是一个NULL指针,返回主程序的handle.当传递给dlsym函数调用时,handle将会查找主程序中的符号,查找程序启动时的所有共享库,以及查找dlopen加载的带RTLD_GLOBAL的库.
库中的外部引用使用库以及库依赖的列表以及其他之前带有RTLD_GLOBAL标示打开的库解析.如果可行执行文件连接时使用-rdynamic或--export-dynamic,则可执行文件中的全局符号可以用来解析动态加载的库.意味着动态加载的库,可以引用可执行文件中的符号.后文会再涉及这个-rdynamic参数.
如果相同的库,使用dlopen再次加载,相同的handle会返回.dl库维护handle的计数引用,一个动态库不会解除,直到dlclose函数被调用.如果存在_init()流程,只调用一次.但随后RTLD_NOW调用可能强制早些使用RTLD_LAZY加载的库进行符号解析.
如果dlopen失败,返回NULL.
#define _GNU_SOURCE /* See feature_test_macros(7) */ #include <dlfcn.h> int dladdr(void *addr, Dl_info *info); void *dlvsym(void *handle, char *symbol, char *version); The function dladdr() takes a function pointer and tries to resolve name and file where it is located. Information is stored in the Dl_info structure: typedef struct { const char *dli_fname; /* Pathname of shared object that contains address */ void *dli_fbase; /* Address at which shared object is loaded */ const char *dli_sname; /* Name of nearest symbol with address lower than addr */ void *dli_saddr; /* Exact address of symbol named in dli_sname */ } Dl_info;如果符号地址addr没有找到,则dli_sname和dli_saddr设置为NULL.
Load the math library, and print the cosine of 2.0: #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main(int argc, char **argv) { void *handle; double (*cosine)(double); char *error; handle = dlopen("libm.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } dlerror(); /* Clear any existing error */ <span style="color:#ff0000;">/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos"); would seem more natural, but the C99 standard leaves casting from "void *" to a function pointer undefined. The assignment used below is the POSIX.1-2003 (Technical Corrigendum 1) workaround; see the Rationale for the POSIX specification of dlsym(). */ *(void **) (&cosine) = dlsym(handle, "cos");</span> if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(EXIT_FAILURE); } printf("%f\n", (*cosine)(2.0)); dlclose(handle); exit(EXIT_SUCCESS); }
//---------- //main.cpp: //---------- #include "polygon.hpp" #include <iostream> #include <dlfcn.h> int main() { using std::cout; using std::cerr; // load the triangle library void* triangle = dlopen("./triangle.so", RTLD_LAZY); if (!triangle) { cerr << "Cannot load library: " << dlerror() << '\n'; return 1; } // reset errors dlerror(); // load the symbols create_t* create_triangle = (create_t*) dlsym(triangle, "create"); const char* dlsym_error = dlerror(); if (dlsym_error) { cerr << "Cannot load symbol create: " << dlsym_error << '\n'; return 1; } destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, "destroy"); dlsym_error = dlerror(); if (dlsym_error) { cerr << "Cannot load symbol destroy: " << dlsym_error << '\n'; return 1; } // create an instance of the class polygon* poly = create_triangle(); // use the class poly->set_side_length(7); cout << "The area is: " << poly->area() << '\n'; // destroy the class destroy_triangle(poly); // unload the triangle library dlclose(triangle); } //---------- //polygon.hpp: //---------- #ifndef POLYGON_HPP #define POLYGON_HPP class polygon { protected: double side_length_; public: polygon() : side_length_(0) {} virtual ~polygon() {} void set_side_length(double side_length) { side_length_ = side_length; } virtual double area() const = 0; }; // the types of the class factories typedef polygon* create_t(); typedef void destroy_t(polygon*); #endif //---------- //triangle.cpp: //---------- #include "polygon.hpp" #include <cmath> class triangle : public polygon { public: virtual double area() const { return side_length_ * side_length_ * sqrt(3) / 2; } }; // the class factories extern "C" polygon* create() { return new triangle; } extern "C" void destroy(polygon* p) { delete p; }
标签:des style blog http ar io color os 使用
原文地址:http://blog.csdn.net/cdhql/article/details/42001927