问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

解决动态库链接过程中的符号冲突问题

发布网友 发布时间:2024-09-30 03:49

我来回答

1个回答

热心网友 时间:2024-12-02 09:32

动态库中函数调用

环境:

clangversion12.0.1

cmakeversion3.21.2

g++(GCC)11.1.0

包含两个相同函数的库链接冲突

试想一下,在你的主函数中调用了一个函数,但是这个函数可以在不同的库中都有实现,那主函数中调用的应该是哪一个呢?

我们来试验一下,构建测试代码:

.├──CMakeLists.txt├──include│├──second.h│└──work.h├──main.cc└──src├──CMakeLists.txt├──second.cc└──work.cc

./CMakeLists.txt文件内容:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)

./include/second.h

#pragmaonce#include<iostream>voidSoFunction();voidDoFunction();

./include/work.h

#pragmaonce#include<iostream>voidSoFunction();

src/CMakeLists.txt内容:

include_directories(${CMAKE_PROJECT_PATH}/include)add_library(secondSHAREDsecond.cc)add_library(workSHAREDwork.cc)

src/second.cc

#include"second.h"voidSoFunction(){std::cout<<"conflictfunctioncall\n";}voidDoFunction(){std::cout<<"DoFunction\n";SoFunction();}

src/work.cc

#include"work.h"voidSoFunction(){std::cout<<"CallSofunctiuon\n";}

./main.cc

#include<iostream>voidSoFunction();intmain(){std::cout<<"1.Mainstart...\n";SoFunction();std::cout<<"SoFunctioncallfinished\n";return0;}

构建运行:mkdirbuild&&pushdbuild&&cmake..&&make&&./symbol&&popd&&rm-rfbuild执行结果如下:

conflictfunctioncallSoFunctioncallfinished

可以看到主函数调用了second.cc里面的SoFunction,因为我们先link的时libsecond.so的动态库,自然后link的libwork.so会被覆盖,如果我们在./CMakeLists.txt中调整link顺序,你将能得到不同的结果.

包含两个相同函数的动态库调用覆盖问题

如果我们在主函数中调用second/DoFunction其会调用SoFunction,那么这时会调用second.cc的SoFunction还是调用work.cc的SoFunction?修改main函数进行测试:

#include<iostream>#include"second.h"#include"work.h"intmain(){std::cout<<"1.Mainstart...\n";DoFunction();std::cout<<"DoFunctioncallfinished\n";SoFunction();return0;}

这时候我们不修改link顺序,保持second先link,我们得到下面的结果:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)0

不出意外,函数调用顺序为:main.cc/DoFunction->second.cc/DoFunction->second.cc/SoFunction->work.cc/SoFunction现在我们修改./CMakeLists.txt以调整link顺序target_link_libraries(${PROJECT_NAME}worksecond),重新运行代码,我们将得到下面的结果:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)1

函数的调用顺序为:main.cc/DoFunction->second.cc/DoFunction->work.cc/SoFunction->work.cc/SoFunction,这时因为函数SoFunction因为libwork.so先link,函数使用其的.那如何link先后顺序发生变化的情况下仍然实现同一个库的函数相互调用?

我们先看看两个库中的符号信息:nm-CDsrc/libwork.so,内容如下:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)2

libsecond.so里面的内容:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)3解决符号冲突导致的错误调用隐藏符号

我们可以通过设置invisiable让动态库的符号是否对外可见,例如我们可以让libwork.so的符号对外不可见,那么我们就可以无论怎样都能调用到second的函数.你可以设置src/CMakeLists.txt的内容如下:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)4

上面的编译过程会自动将两个库的符号隐藏(CXX_FLAG在当前CMakeLists.txt一直生效,不能直接设置一个加参数,一个不加),这时候我们看到libwork.so的符号信息,执行上面的编译运行命令的时候会出错,因为找不到符号表DoFunction和SoFunction,从而出现未定义的引用.

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)5

这里我们使用手动link生成最后的二进制文件:clang++main.cc-Iinclude-L.-lsecond-lwork-osymbol这时候我们执行的时候将屏蔽libwork.so里面的符号,从而实现只调用second.cc里面的SoFunction.结果如下:

1.Mainstart...SecondDoFunctionconflictfunctioncallSoFunctioncallfinishedconflictfunctioncall函数代码中禁用

在libsecond.so中人为开启SoFunction和DoFunction两个函数对外可见,修改second.cc(单独编译second.cc为libsecond.soclang++-fvisibility=hidden-Iincludesrc/second.cc-fPIC-shared-olibsecond.so)

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)7

然后在src/CMakeLists.txt开启visibility,编译即可正常运行,因为work.cc里面的符号没有对外暴露,所以我们不会调到work.cc里面的SoFunction.

通过文件设置导出函数表

在include/export.symb文件中添加下面信息:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)8

global:对应的是你想导出的函数

local区域代表不想导出的符号,*号表示除了global中的符号全部不导出

手动编译动态库实现只保留SoFunctionclang++-Wl,--version-script=include/export.symb-s-Iincludesrc/second.cc-fPIC-shared-olibsecond.so,此时libsecond.so的内容如下:

cmake_minimum_required(VERSION3.14)project(symbol)include_directories(include)add_subdirectory(src)add_executable(${PROJECT_NAME}main.cc)target_link_libraries(${PROJECT_NAME}secondwork)9

输出如下:

#pragmaonce#include<iostream>voidSoFunction();voidDoFunction();0

这里的输出有点不一样(我们屏蔽了second.cc里面的SoFunction)

参考

部分内容参考了:编译链接时如何解决符号冲突问题

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
四川省综合素质a级证书? 华为手机怎么还原微信聊天记录 华为手机微信内容恢复方法 股权转让的主要方式有哪些 股权转让有哪几种方式 股东转让的几种形式是 股东转让的几种形式 高考多少分能上衡阳师范学院南岳学院 你们被玖富金融骗,后期有还款吗? 玖富悟空理财2022年最新消息还有希望吗?悟空理财最新情况(悟空理财可信... 同等责任交通事故致人死亡是否追究刑事责任 CMake构建多个源文件,包含路径,以及第三方库 梦见好几条颜色不同的蛇在家里,我想打死它可是它们钻进一个洞里,出来... 梦见看到两条蛇一条在家里一条在家外面,去找棍子打蛇,找到合适的棍子后... 我梦见一条青蛇,我和弟弟准备把它装到袋子里,结果弟弟被它咬死,我吓... 谭松韵凭“袁今夏”获华鼎奖古装题材最佳女主角,这是实至名归吗? 罗汉松可以开花吗? 解放J6和JH6,500和460的马力哪个更省油,潍柴和锡柴哪个好,建议买... 污水处理厂的避雷塔和污水管线属于固定资产里的建筑物还是专用设备... 为什么我电脑放DVD盘的时候,会很卡,然后就蓝屏了别人的机子可以用_百度... 益脉迪半导体激光治疗仪照射穴位 益脉迪半导体激光治疗仪治疗机理 益脉迪半导体激光治疗仪产品介绍 益脉迪半导体激光治疗仪产品特点 益脉迪效果怎么样 益脉迪净血仪的原理是什么?激光怎么治病? 出国留学的条件和要求英国 英国留学的申请条件有哪些? 电信机顶盒看不了怎么办? 出国英国留学需要哪些条件 留学英国需要哪些要求 什么是catkin? CAD中Defpoints图层有什么用 英雄联盟单机手机版下载,安卓v2.1角色扮演手游介绍_英雄联盟单机手机版... ...Mothur扩增子基因序列处理_物种注释及发育分析 秦岭的哪些景区适合拍绝美风景照? 秦岭最适合看星空的地方,秦岭日出旅游景点 秦岭有哪些景区很值得一去 32岁宋轶为“好嫁风”道歉,被围观吐槽:我看到了对女人的侮辱_百度... Co., Ltd和ltd有什么区别?Inc.呢?又使什么? 我小时候晒太阳太多,头发变得有点软,细.又有点黄.我想把头发变得... CT能不能查出前列腺炎 前列腺炎做CT可以检查出来吗 CT可以检查前列腺炎吗 老舍集内容简介 新编老舍文集3图书信息 老舍散文集书籍信息 新编老舍文集4内容简介 ...提现1万, 最低还款额是多少, 每个月还最低还款额, 到最后是要还多少... 如果信用卡信用额度是1万,第一个月刷了5000,还了最低还款额,那下... 热固性丙烯酸树脂简介