我有一个静态链接到一个版本的mpich的代码A. 现在来到图书馆B,由A通过dlopen()使用。 B也取决于mpich,但dynamic地与它链接。
现在的问题是,为了让B利用mpi分发,需要访问当前由A处理的通信器。这个通信器是由mpich的一个静态版本创build的,当B调用MPI例程时,它将使用dynamic版本的MPI,这是不符合附加到A的静态版本兼容。
这是整体画面。 我认为唯一的解决办法是让mpichdynamic链接到A和B.但是我不完全理解的是:
你没有说你正在使用哪个工具链(GCC,LLVM,MSC等),最有用的答案将取决于这些信息。
我可以建议你看看“GCC异常框架” http://www.airs.com/blog/archives/166 。
如果这是有用的,那么可用于GCC和LLVM的Gold Linker支持“链接时间优化”,并且可以在DLLTool http://sourceware.org/binutils/docs/binutils/dlltool.html的 “Make”中运行。
事实上,静态和动态代码都可以互相调用,计算机并不关心; 它将“运行”任何它所馈送的东西 – 不管它是否按照你想要的方式工作,或者HCF依赖于正确的代码和正确的链接器命令。
使用调试器不会很有趣。 在链接之前最好先对名称进行修改,这样在调试的时候可以看到代码来自哪个模块。 一旦启动并运行,您可以取消Mangle并使用相同名称的Functions Link(以确保它仍然可用)。
编译器/链接器错误不会是你的朋友。
这种场景(静态和动态链接)更常见于MinGW和Cygwin,其中一些库是静态的,但是从Internet上下载的库仅在动态形式(无源)下可用。
如果库来自两个不同的编译器工具链,则会出现其他问题,请参阅此StackOverflow主题:“ MinGW和MSVC之间的链接困境(未定义的引用) ” MinGW失败MSVC工作 “。
最好简单地从源文件中获取最新版本的库,然后自己编译整个库,而不是依靠拼凑来自不同来源的零碎碎片(尽管可以这样做)。
你甚至可以加载动态库并静态调用它,然后重新加载它的一部分。
内存有多紧张,你想要多快功能运行,如果一切都在内存中你的程序可以将执行转移到被调用的函数中,如果你将代码的一部分交换到虚拟机,你的执行时间将真正需要击中。
在你的代码上运行一个Profiler可以帮助你决定要加载一个库的哪些部分,如果你想做'动态链接'(通过加载动态链接库来完全控制你的dyna链接,这样可以静态使用)。 这是头痛和噩梦的东西。 GL。
总之:这取决于dlopen
选项。 默认情况下,如果所请求的库所需的符号已经存在于全局范围中,它将被重用(这是你想要的)。 但是你可以用RTLD_DEEPBIND
绕过这个行为,使用这个标志,依赖不会被全局范围重用,并且会被第二次加载。
这里有一些代码来重现你的情况,并演示这个标志的效果。
我们来创建一个共同的库,这个库将被lib A和程序B使用。这个库将有两个版本。
$ cat libcommon_v1.c int common_func(int a) { return a+1; } $ cat libcommon_v2.c int common_func(int a) { return a+2; }
现在我们来编写使用libcommon_v2的lib A:
$ cat liba.c int common_func(int a); int a_func(int a) { return common_func(a)+1; }
最后,程序B动态链接到libcommon_v1并dlopens
lib A:
$ cat progb.c #include <stdio.h> #include <dlfcn.h> int common_func(int a); int a_func(int a); int main(int argc, char *argv[]) { void *dl_handle; int (*a_ptr)(int); char c; /* just make sure common_func is registered in our global scope */ common_func(42); printf("press 1 for global scope lookup, 2 for deep bind\n"); c = getchar(); if(c == '1') { dl_handle = dlopen("./liba.so", RTLD_NOW); } else if(c == '2') { dl_handle = dlopen("./liba.so", RTLD_NOW | RTLD_DEEPBIND); } else { printf("wrong choice\n"); return 1; } if( ! dl_handle) { printf("dlopen failed: %s\n", dlerror()); return 2; } a_ptr = dlsym(dl_handle, "a_func"); if( ! a_ptr) { printf("dlsym failed: %s\n", dlerror()); return 3; } printf("calling a_func(42): %d\n", (*a_ptr)(42)); return 0; }
让我们建立和运行所有的东西:
$ export LD_LIBRARY_PATH=. $ gcc -o libcommon_v1.so -fPIC -shared libcommon_v1.c $ gcc -o libcommon_v2.so -fPIC -shared libcommon_v2.c $ gcc -Wall -g -o progb progb.c -L. -lcommon_v1 -ldl $ gcc -o liba.so -fPIC -shared liba.c -L. -lcommon_v2 $ ./progb press 1 for global scope lookup, 2 for deep bind 1 calling a_func(42): 44 $ ./progb press 1 for global scope lookup, 2 for deep bind 2 calling a_func(42): 45
我们可以清楚地看到,使用默认选项, dlopen
重用了程序B中存在的符号common_func
和RTLD_DEEPBIND
,libcommon被再次加载,库A得到了它自己的common_func
版本。