我有一个静态链接到一个版本的mpich的代码A.现在来到库B,由A via dlopen()使用。 B依赖于mpich,但是它与动态链接。
现在的问题是,为了让B利用mpi分配,需要访问当前由A处理的通信器。这个通信器是由静态版本的mpich创建的,当B调用MPI例程时,它会使用动态版本的MPI,不保证与附加到A的静态版本兼容。
这是整体情况。我认为唯一的解决方案是为A和B动态链接mpich。然而我不完全理解的是:
答案 0 :(得分:2)
简而言之:它取决于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
。
答案 1 :(得分:0)
您没有说明您使用的是哪种工具链(GCC,LLVM,MSC等),最有用的答案将取决于此信息。
我建议你看看&#34; GCC Exception Frames&#34; http://www.airs.com/blog/archives/166。
如果这有用,那么可用于GCC和LLVM的Gold Linker支持&#39;链接时间优化&#39;并且可以在&#34; Make&#34;使用DLLTool http://sourceware.org/binutils/docs/binutils/dlltool.html。
确实可以让静态和动态代码互相调用,计算机不关心;它将会运行&#39;它被送入的任何东西 - 是否最终以您想要的方式工作,或者HCF依赖于正确的代码和正确的链接器命令。
使用调试器不会很有趣。最好在链接之前修改名称,以便在调试时可以看到代码来自哪个模块。一旦启动并运行,您可以取消断言并具有相同名称的功能链接(以确保它仍然起作用)。
编译器/链接器错误不会是你的朋友。
这种情况(静态和动态链接)更常发生在MinGW和Cygwin中,其中一些库是静态的,但是从Internet下载的库只能以动态形式(没有源)提供。
如果库来自两个不同的编译器工具链,则会出现其他问题,请参阅此StackOverflow线程:&#34; linking dilemma (undefined reference) between MinGW and MSVC. MinGW fails MSVC works&#34;。
最好从源代码中简单地获取最新版本的库并自己编译整个文件,而不是依赖于尝试拼凑不同来源的碎片(尽管可以这样做)。
您甚至可以加载动态库并静态调用它,然后再重新加载部分动态库。
你对内存有多紧张以及你想要多快运行函数,如果一切都在内存中你的程序可以立即将执行转移到被调用函数,如果你将一部分代码交换到VM你的执行时间将会真的很受欢迎。
在您的代码上运行Profiler将有助于确定要加载的库的哪些部分,如果您想要动态动态链接&#39; (通过加载动态库完全控制你的dyna链接,以便静态使用它)。这是令人头疼和噩梦的东西。 GL。