Linux下库文件加载时有重名函数问题

我有两个QT工程,A是个应用程序工程,B是个动态库,A在运行时调用B,在Windows平台运行正常,但同样代码在Linux下运行崩溃。

上午折腾半天愣是不能定位到崩溃的地方,因为调试时打的断点使程序停在莫名其妙的地方,然后放弃断点,程序里加qDebug,最后定位到B工程里调用CProject::loadProject()函数时崩溃,程序结构类似下面代码,输出一个“1”之后就崩了,然而在CProject::loadProject()函数内加的qDebug语句竟然没有执行,然后蒙了,按理说输出“1”之后,紧接着函数调用,然后应该输出“2”,但是只输出“1”,难道简单的函数调用还能崩溃???以我的经验,不可能。于是想到这个CProject类在工程A和工程B里都有,同名的类,但是在B里我改了些具体细节,难道系统分不出来哪个是哪个了?于是在A的CProject::loadProject()函数中加qDebug()<<"4",果然,输出了“1”,然后输出“4”。

void fun1()

{

  ...

  qDebug()<<"1";

  CProject::loadProject()

  qDebug()<<"2"

  ...

}

void CProject::loadProject()

{

  qDebug()<<"3";

  ...

}

问题找到了离解决就不远了,百度之后得到以下解决方案:

在B工程的工程文件中加一行:QMAKE_CXXFLAGS += -fvisibility=hidden

原理是

1编译器默认把所有符号在加载或运行时定位,库文件编译完后,CProject::loadProject()这个符号调用的地方只是标记了此处需调用此符号,但此符号在哪里交由系统函数决定。

2程序加载时维护一张符号表,表中不能有同名符号,后加载的同名符号被舍弃,加载时先加载主程序,然后加载依赖的库,于是B中的CProject::loadProject()被A中的CProject::loadProject()覆盖。

3程序运行到B中调用CProject::loadProject()处,系统函数查找符号表,找到的是A中的CProject::loadProject(),于是调用了A中的CProject::loadProject()。

4-fvisibility=hidden 这个编译选项让编译器把所有符号隐藏,不对外可见,所以编译器在编译时默认调用本地符号,将本地的CProject::loadProject()函数地址放在了函数调用处,运行时,直接调用本地的CProject::loadProject()。

5有人要问:符号隐藏后那A调用B时岂不找不到接口函数了?创建工程时选的是库,QT默认把接口加上了修饰符:__attribute__((visibility("default"))),所以接口不会被隐藏

posted @ 2021-05-26 16:16  有没有的有  阅读(436)  评论(0)    收藏  举报