我一直致力于跨平台窗口库,旨在专门用于OpenGL,目前专注于Linux。我正在利用glload来管理OpenGL扩展,并且正在将这个以及稍后将使用的其他库编译成.so
。这个`.so正如你所期望的那样动态加载,但在运行时程序提供以下输出(手动包装,以便更容易阅读):
_dist/x64-linux-debug/bin/test: Symbol `glXCreateContextAttribsARB' has \
different size in shared object, consider re-linking
现在,显然我已经尝试过重新连接,甚至多次重建整个项目(测试一下,而不是盲目地希望它会神奇地使它变得更好)。该程序似乎确实愿意运行,因为它会产生一些日志输出,正如我所期望的那样。我已使用nm
确认“符号”位于.so
nm _dist/x64-linux-debug/lib64/libvendor.so | grep glXCreateContextAttribsARB
00000000009e0e78 B glXCreateContextAttribsARB
如果我使用readelf
来查看正在定义的符号,我会得到以下内容(同样,为了格式化,我手动包装了前三行):
readelf -Ws _dist/x64-linux-debug/bin/test \
_dist/x64-linux-debug/lib64/libvendor.so | \
grep glXCreateContextAttribsARB
348: 000000000062b318 8 OBJECT GLOBAL DEFAULT 26 glXCreateContextAttribsARB
421: 000000000062b318 8 OBJECT GLOBAL DEFAULT 26 glXCreateContextAttribsARB
1370: 00000000009e0e78 8 OBJECT GLOBAL DEFAULT 25 glXCreateContextAttribsARB
17464: 00000000009e0e78 8 OBJECT GLOBAL DEFAULT 25 glXCreateContextAttribsARB
我担心这是我可以提供的所有帮助,因为我真的不知道该尝试或研究什么。就像我说的那样,我相信会有更多的信息需要,所以请说一下我会尽我所能。我从我的项目根运行这些命令,包括你想知道。
答案 0 :(得分:6)
wilsonmichaelpatrick的回答大多是正确的,但是使用gdb
可能不是找到问题的最快方法,如果你有非调试版本,它可能根本不起作用。
首先,您应该确认实际上存在问题:
readelf -Ws _dist/x64-linux-debug/bin/test _dist/x64-linux-debug/lib64/libvendor.so |
grep glXCreateContextAttribsARB
这应该显示在test
和libvendor.so
中定义的符号,大小不同。
其次,将test
和libvendor.so
与-Wl,-y,glXCreateContextAttribsARB
标记重新关联。这将告诉您哪些目标文件(或库)提供(不同的)定义。
最后,使用-E
和-dD
标记预处理生成上述目标文件的源,并查看它们之间的不同之处。
<强>更新强>
我需要帮助消化它的含义
不要无助。阅读man readelf
,或者手动运行。你会看到这样的事情:
readelf -Ws /bin/date | head -5
Symbol table '.dynsym' contains 75 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __ctype_toupper_loc@GLIBC_2.3 (2)
这会告诉您所获数据的含义。特别是,这告诉您test
和libvendor.so
中的符号大小相同(8
)。因此,问题是不这两个ELF文件,而是其他地方。在其他库上运行readelf
,并查找具有不同大小的glXCreateContextAttribsARB
的定义。然后按照剩下的步骤进行操作。
答案 1 :(得分:3)
运行时注意到在共享对象中编译的glXCreateContextAttribsARB,以及在主程序中编译的glXCreateContextAttribsARB(或者甚至可能是之前链接的其他一些共享对象)具有不同的大小。这意味着,在共享对象的单独构建中以及引用该对象的任何其他内容时,它们必须查看定义此对象的不同代码(可能在共享对象中)。有时会发生这种情况是因为它们正在查看不同的文件,有时这是因为不同的#defines导致对同一文件的不同解释。无论是什么原因,您绝对需要确保在运行时链接在一起的所有内容中以相同的方式(即具有相同的成员变量和大小)定义相同的符号(例如结构)。
它拒绝运行实际上是一件非常好的事情,因为当代码的两个部分在运行时以不同的方式解释相同的内存时,这是一个灾难。 (如果允许继续,可以发生任何事情,这并不夸张。)
您可能想尝试在gdb中加载可执行文件(不运行它)并输入
info types
查看它的定义位置,然后在gdb中加载共享对象(不运行它)并在那里执行另一个info types
以查看每个人认为它正在查看的内容。如果是相同的,请检查预处理程序指令。
答案 2 :(得分:1)
我遇到了一个与不同尺寸的物体有关的繁琐问题,所以我想分享我的经验 - 尽管我很清楚,这只是解释不同物体尺寸的唯一原因 - 而不是强制性的OP。 / p>
症状是调试模式下不同大小的对象,在发布模式下没有。链接器产生了相应的警告。符号名称很难破译,但与类模板实例中的一些未命名的静态变量有关。
原因是调试日志记录功能àlaLOG("Do something.");
。 LOG宏使用C ANSI宏__FILE__
,它扩展到另一个路径,具体取决于应用程序或共享库是否包含标头。这个字符串就是上面提到的未命名的静态变量。
由于我们的make环境,__FILE__
宏有时会扩展到C:\temp\file.h
,有时会扩展到C:\other\..\temp\file.h
,以便构建应用程序和库,这更加乏味。从同一个地方也没有解决问题。
我希望这段经历可以为你们中的一些人留出一些时间。
答案 3 :(得分:0)
在大多数情况下,您可能只是链接到错误的库(其他版本)。例如,您安装了libfoo
两次,并将可执行文件与-L /path/to/version1 -lfoo
链接,但是在运行时,您与/path/to/version2
链接(您可以通过ldd yourprogram
看到该链接)。
一个原因可能是可执行文件与-rpath,/path/to/version1
链接,但是(如最新版本所做的那样)这在动态部分中设置了RUNPATH
条目;而您拥有LD_LIBRARY_PATH=/path/to/version2
。设置RUNPATH
时,LD_LIBRARY_PATH
优先。在这种情况下,请从/path/to/version2
中删除该库(或从LD_LIBRARY_PATH
中删除该路径)。
示例
$ minimal
/home/carlo/minimal: Symbol `_ZN6libcwd8libcw_doE' has different size in shared object, consider re-linking
COREDUMP : /home/carlo/projects/libcwd/libcwd/elfxx.cc:2381: void libcwd::elfxx::objfile_ct::load_dwarf(): Assertion `size == sizeof(address)' failed.
(libcwd足够聪明,也可以看到它;也就是问题在于libcwd):
$ ldd minimal | grep libcwd_r
libcwd_r.so.5 => /usr/local/install/6.0.0-1ubuntu2/lib/libcwd_r.so.5 (0x00007f0b69840000)
$ echo $LD_LIBRARY_PATH
/usr/local/install/6.0.0-1ubuntu2/lib
$ objdump -a -x minimal | grep PATH
RUNPATH /opt/gitache/libcwd_r/888f62c44fd64f1486176bf9e35b36f79612790017c31f95e117fc59743a54ca/lib
取消设置LD_LIBRARY_PATH
或从该路径中删除libcwd都会导致
$ unset LD_LIBRARY_PATH
$ ldd minimal | grep libcwd_r
libcwd_r.so.5 => /opt/gitache/libcwd_r/888f62c44fd64f1486176bf9e35b36f79612790017c31f95e117fc59743a54ca/lib/libcwd_r.so.5 (0x00007f11d7298000)
,事情又恢复了。或者,我可以将其添加到项目的CMakeLists.txt中:
$ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-new-dtags")
之后我们得到
$ objdump -a -x minimal | grep PATH
RPATH /opt/gitache/libcwd_r/888f62c44fd64f1486176bf9e35b36f79612790017c31f95e117fc59743a54ca/lib
现在优先于LD_LIBRARY_PATH
,因此也解决了该问题。但是,这不是推荐的方法:如果设置LD_LIBRARY_PATH
,您应该知道自己在做什么。如果这不起作用,则应修复LD_LIBRARY_PATH
或删除有问题的库。