我一直在研究一个跨平台的窗口库,专门用于OpenGL,目前专注于Linux。 我正在使用glload来pipe理OpenGL扩展,并且正在编译以及稍后将使用的其他库,并将其编译为.so
。 这个`.so正在像你期望的那样dynamic加载,但是在运行时程序给出了下面的输出(手动包装,这样更容易阅读):
_dist/x64-linux-debug/bin/test: Symbol `glXCreateContextAttribsARB' has \ different size in shared object, consider re-linking
现在,很显然我已经尝试过重新连接,甚至重build整个项目多次(testing的东西,不只是盲目地希望它会神奇地使一切更好)。 该程序似乎是愿意运行,因为它会产生一些日志输出,如我所料。 我用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
我担心这是我所能提供的一切帮助,因为我真的不知道该怎么去尝试或调查。 就像我说的,我相信会有更多的信息需要,所以请只说我会提供我所能。 我从我的项目根目录运行这些命令,包装你想知道。
wilsonmichaelpatrick的答案大部分是正确的,但是使用gdb
可能不是找到问题的最快方法,而且如果你有一个非调试版本,可能根本不工作。
首先,您应该确认实际上存在问题:
readelf -Ws _dist/x64-linux-debug/bin/test _dist/x64-linux-debug/lib64/libvendor.so | grep glXCreateContextAttribsARB
这应该显示在test
和libvendor.so
定义的符号,具有不同的大小。
其次,用libvendor.so
-Wl,-y,glXCreateContextAttribsARB
标志重新链接test
和libvendor.so
。 这将告诉你哪些对象文件(或库)提供(不同的)定义。
最后,使用-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
定义。 然后按照程序的其余部分。
运行时注意到在共享对象中编译的glXCreateContextAttribsARB,以及在主程序中编译的glXCreateContextAttribsARB(甚至可能还有一些其他先前链接的共享对象)具有不同的大小。 这意味着,在共享对象的单独构建以及任何其他引用该对象的构建中,它们必须查看定义了这些代码的不同代码(可能在共享对象中)。 有时会发生这种情况,因为他们正在查看不同的文件,有时这是因为不同的#defines导致对同一文件的不同解释。 不管是什么原因,你绝对需要确保在运行时链接在一起的所有东西都以相同的方式(例如,具有相同的成员变量和大小)定义相同的符号(例如结构)。
它拒绝运行实际上是一件非常好的事情,因为当代码的两个部分在运行时以不同的方式解释同一位内存时,这是一场灾难。 (如果允许这样做,不要夸大其词。)
您可能想要尝试在gdb中加载可执行文件(不运行它)并键入
info types
看看它在哪里定义,然后在gdb中加载共享对象(不运行它),并在那里做另一个info types
,看看他们每个人认为它正在看什么。 如果是相同的事情,请检查预处理器指令。
我面对一个与大小不同的对象有关的单调乏味的问题,所以我想分享我的经验 – 尽管我很清楚,这只是解释不同对象大小的一个原因 – 而不是强制执行OP。
在调试模式下,症状是不同大小的对象,在释放模式下没有。 链接器产生了相应的警告。 符号名称很难破译,但与类模板实例中的一些未命名的静态变量相关。
原因是调试日志功能LOG("Do something.");
。 LOG宏使用扩展到另一个路径的C ANSI宏__FILE__
,具体取决于应用程序或共享库是否包含头。 而这个字符串正是前面提到的未命名的静态变量。
更麻烦的是,由于我们的make环境, __FILE__
宏有时会扩展到C:\temp\file.h
,有时会扩展到C:\other\..\temp\file.h
这样构建应用程序和来自同一地点的图书馆也没有解决问题。
我希望这段经历可能会让你们中的一些人有所收获。