我正在向系统添加两个类和库,parent.so
和child.so
从中派生出来。
问题是当程序加载child.so
时,它无法从parent.so
找到父虚拟函数的定义。
会发生什么,
nm -D child.so
会给出类似的内容(我只是更改了名称)
U _ZN12PARENT15virtualFunctionEv
程序将崩溃
_handle = dlopen(filename, RTLD_NOW|RTLD_GLOBAL); //filename is child.so
它会在LD_DEBUG = libs
symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv (fatal)
我无法解释的是,我尝试LD_DEBUG = symbols
使用GDB,在运行dlopen
时,日志显示它试图在系统中除parent.so
以外的所有库中查找,符号定义的位置。但是从libs中已经加载了日志parent.so
并运行了代码,它与所有其他库的路径相同。
......
27510: symbol=_ZN12PARENT15virtualFunctionEv; lookup in file=/lib/tls/libm.so.6
27510: symbol=_ZN12PARENT15virtualFunctionEv; lookup in file=/lib/tls/libc.so.6
27510: symbol=_ZN12PARENT15virtualFunctionEv; lookup in file=/lib/ld-linux.so.2
27510: child.so: error: symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv(fatal)
程序或系统如何管理哪个库来查找符号的定义?
我是Linux的新手,有人可以指点我的工作方向吗?
感谢。
修改
用于生成parent.so
文件的命令是
c++ -shared -o parent.so parent.o
类似于child.so
。在这里链接是否缺少任何信息?看起来孩子只包含父母的头文件。
EDIT2
经过另一次测试,请致电
_handle = dlopen("parent.so", RTLD_NOW|RTLD_GLOBAL);
崩溃线之前的将解决问题,我认为最初意味着parent.so
未加载。但我仍然不清楚原因。
答案 0 :(得分:4)
您需要告诉链接器您的库libchild.so
使用libparent.so
中的功能。您在创建子库时执行此操作:
g++ -shared -o libchild.so child_file1.o child_file2.o -Lparent_directory -lparent
请注意,订单很重要。在所有目标文件之后指定-lparent
。您可能还需要通过g ++的-Wl
选项将其他选项传递给链接器。
这仍然可能不够好。您可能需要将包含libparent.so
的库添加到LD_LIBRARY_PATH
环境变量。
一些问题:如果您没有使用lib
前缀命名这些库,则会使链接器大大混淆。如果您没有使用-fPIC
或-fpic
编译源文件,则不会有可重定位目标文件。
<强>附录强>
依赖于其他库的库存在很大的潜在问题。假设在编译子库源文件时使用父包的1.5版。您设法克服了所有库依赖项问题。您已指定libchild.so
取决于libparent.so
。你的东西才有效。这是在父包的2.0版出来之前。现在你的东西在任何地方都会被破坏,你没有改变过一行代码。
解决此问题的方法是在构建子库时指定生成的共享库特别依赖于libparent.so`的1.5版。
要执行此操作,您需要通过-Wl
选项将选项从g ++ / gcc传递到链接器。使用-Wl,<linker_option>,<linker_option>,...
如果这些链接器选项需要空格,则需要在g ++命令中对它们进行反斜杠转义。一些关键选项是-rpath
和-soname
。例如,-rpath=/path/to/lib,-soname=libparent.so.1.5
。
请注意:构建libparent.so时需要使用-soname=libparent.so.1.5
选项。这就是系统表示你的libchild.so(版本1.0)依赖于libparent.so(版本1.5)的原因。而且你没有构建libparent.so。您构建libparent.so.1.5。 libparent.so怎么样?这需要存在,但它应该是libparent.so的某些编号编号版本(最好是最新版本)的符号链接。
现在假设编译了非向后兼容的父版本2.0并将其内置到一个闪亮的新libparent.so.2.0中,libparent.so象征性地链接到这个闪亮的新版本。使用笨重的旧libchild.so(版本1.0)的应用程序将很乐意使用笨重的旧版libparent.so而不是破坏一切的闪亮新版本。
答案 1 :(得分:1)
看起来你没有告诉链接器child.so需要parent.so,使用如下内容:
g++ -shared -o libparent.so parent.o
g++ -shared -o libchild.so -lparent child.o
答案 2 :(得分:-1)
构建主程序时,必须告诉编译器它与这些库链接;这样,当它启动时,linux将为它加载它们。
将其名称更改为libparent.so和libchild.so。
然后用这样的东西编译:
g++ <your files and flags> -L<folder where the .so's are> -lparent -lchild
编辑:
在child.so之前尝试加载parent.so可能是一个较小的更改。你有没试过?