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"))),所以接口不会被隐藏

浙公网安备 33010602011771号