微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从另一个共享对象dynamic加载共享对象时的约束?

我从maindynamic加载(whith dlopen() )共享对象(名为libprofile1.so )。

在libprofile1.so我定义了工厂函数CreateProfile和class Profile 。 CreateProfile函数创build一个Profile类的实例并返回一个指向它的指针。 Class Profile有一个方法pMethod 。

主要是在加载libprofile1.so ,我调用了CreateProfile方法,它返回指向Profile类对象的指针(称为p )。

之后,我调用pMethod方法对象p ( p->pMethod )。 在这方法中,我dynamic加载其他共享对象( libdatasources.so )。

在这个共享对象中,我有一个工厂函数CreateDataSource和类DataSource 。

CreateDataSource函数创build一个DataSource类的实例并返回一个指向它的指针。 DataSource类有方法dsMethod 。

如何在共享库内的链接时间(不加载时间)解决弱符号

LSB AppChecker:GCC与未使用的库链接

一些关于GCC链接器search顺序的问题

Linux共享库的init和deinit也使用c ++静态初始化

如何使用waf来构build共享库?

你可以注意到,这两个共享对象的结构是相似的。

从pMethod加载pMethod之后,我调用CreateDataSource方法,它返回一个指向DataSource类的实例的指针,称之为ds 。 然后我打电话dsMethod ds对象的dsMethod

( ds->dsMethod )。

现在,问题在于。

当我尝试调用ds对象的dsMethod时,我第一次加载的共享对象( libprofile1.so )不会加载。 其实dlopen()返回NULL 。 当我在dlopen之后读取dlerror ,我得到:

./libprofile1.so: undefined symbol: _ZN18DataSource13dsMethod

所以,如果我有一个调用ds->Method ,比第一个共享对象不加载!

如果我从源代码注释掉ds->dsMethod ,那么我的libprofile1.so和libdatasources.so加载没有任何问题。

我没有看到第二个SO的方法调用间的连接,加载第一个SO ???

也许我不知道,但dynamic加载共享对象,还有dynamic加载的共享对象时是否有任何约束?

顺便说一下, dlopen与RTLD_Now|RTLD_GLOBAL 。 我尝试了RTLD_LAZY ,但仍然是同样的问题。

更新:

Eclipse中构build了库。 G ++编译器和链接器的选项对于这两个库都是相同的。

这里是G ++编译器:

-O0 -g3 -Wall -c -fmessage-length=0

和G ++连接器:

-shared

选项,从Project Properties -> Settings -> Tool Settings粘贴

提前致谢。

链接到应用程序时共享库的variables存储在哪里?

如果没有root访问权限,当与参考BLAS链接时,运行具有调谐BLAS的R

nm报告符号被定义,但ldd报告符号是未定义的

强制二进制文件使用共享库(.so)的特定(较新)版本

用main()创build一个共享库

如果动态加载DLL,则必须确保它没有未解析的符号。

最简单的方法是将其链接到所需的其他DLL,以便自动加载,而不必手动加载和解析所有依赖关系。

所以如果libprofile1总是使用libdatasources确保它们彼此链接

如果您必须手动执行,则反转加载库的顺序。 所以,当你加载libprofile1它所需要的功能已经被加载。

正如马丁·约克指出的,这是它在Linux中的工作方式。 链接到库时,也必须链接到所有依赖关系。 这在Windows中是不一样的,DLL本身也会自行处理它们的依赖关系。 在动态加载具有另一个库作为依赖项的库时,需要先使用RTLD_GLOBAL标志加载该库。 这是非常麻烦的,因为您可能无法知道其他共享对象需要哪些依赖关系,或者依赖关系可能会更改为与二进制兼容的较新版本。 从我所知道的(从阅读g ++和ld手册页),不可能创建类似于Windows的DLL的行为。 这是一个小测试用例:

two.cpp:

#include <iostream> extern "C" { void bar() { std::cout << "bar()n"; } }

one.cpp:

#include <iostream> extern "C" { void bar(); void foo() { std::cout << "foo()n"; bar (); } }

TEST.CPP:

#include <dlfcn.h> #include <iostream> int main (int argc,char *argv[]) { using namespace std; // void *libtwo = dlopen("./libtwo.so",RTLD_Now | RTLD_GLOBAL); void *libone = dlopen("./libone.so",RTLD_Now); if (!libone) { cout << "dlopen(libone.so) Failed: " << dlerror() << "n"; return 1; } typedef void (*foo_t)(); foo_t foo = reinterpret_cast<foo_t>(dlsym(libone,"foo")); if (!foo) { cout << "dlsym(libone.so,foo) Failedn"; return 2; } }

one.cpp被编译成libone.so和two.cpp,test.cpp被编译成test二进制文件。 这将失败,只有当注释行被取消注释时才会成功。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐