gcc链接选项--export-dynamic的一次问题记录
背景:
BS进程cli动态获取与修改需要用到延迟加载库的一组dlopen API,主要用到这三组API:dlopen()、dlerror()、dlclose。详细的接口说明参考man手册或者《Linux/Unix系统编程手册》。
bs进程调用了上面介绍的这三组API,为了实现在调用libaccBalConfigEscapes.so.1.0.0处理cli命令的时候能回调bs主程序的UpdatAccBalInfo与GetAccBalInfo函数:
void UpdatAccBalInfo(const BS::OperAccBal &operType, const BS::AccCfgMsg &msg)
{
InfoLog("cll", " UpdatAccBalInfo");
g_BSApp.AccBalChangedHandler(operType, msg);
}
void GetAccBalInfo(std::map<std::string, BS::SubInfo> &m_subInfoMap)
{
InfoLog("cll", " GetAccBalInfo");
g_BSApp.GetAccBal(m_subInfoMap);
}
将这两个函数声明为全局函数:
extern void UpdatAccBalInfo(const BS::OperAccBal &operType, const BS::AccCfgMsg &msg);
extern void GetAccBalInfo(std::map<std::string, BS::SubInfo> &m_subInfoMap);
在libaccBalConfigEscapes.so.1.0.0源文件里面用,引用包含以上两个函数声明的头文件。
简而言之:就是在库文件里面仅仅是声明某个函数,该函数的具体实现在调用库的主程序里面完成,这样当调用库中的某个函数的时候,实际上这个被调用函数的实现是用户自己实现的,实现类似于回调的机制。
问题:
这里存在的问题是,用bjam编译出来的bs进程在运行时候会报错:
./bs: symbol lookup error: /usr/local/escapes/libaccBalConfigEscapes.so.1.0.0: undefined symbol: _Z15UpdatAccBalInfoRKN2BS10OperAccBalERKNS_9AccCfgMsgE
./bs: symbol lookup error: /usr/local/escapes/libaccBalConfigEscapes.so.1.0.0: undefined symbol: _Z13GetAccBalInfoRSt3mapISsN2BS7SubInfoESt4lessISsESaISt4pairIKSsS1_EEE
提示找不到这两个符号,c++为了实现函数重载、名称空间等机制函数符号是不可读的。可以用c++filter转换成可读格式:
可见这两个符号指向的函数就是我们声明的全局函数!为什么找不到呢?
解决:
换编译环境,用基于makefile的gb编译,运行时候没有报错。因为编译器版本都是libgcc-4.4.7-4.el6.i686,怀疑应该是gb的makefile和bjam的jamroot在gcc选项设置上有区别导致的找不到全局符号。
查看gb的makefile有如下内容:
关键的不同是:-Wl,--export-dynamic –pthread
-Wl:指示后面的选项是给链接器的
-pthread: 链接程序的时包含libpthread.so
--export-dynamic:就是这个选项让主程序内定义的全局函数对库函数可见。
找到原因,修改jamroot增加如下几行:
也可以这么加:
<linkflags>-export-dynamic或
<linkflags>-Wl,-export-dynamic或
<linkflags>-Wl,--export-dynamic 或
但不能这么加:
<linkflags>--export-dynamic
<cxxflags>--export-dynamic
<cxxflags>-export-dynamic
<cxxflags>-Wl,--export-dynamic
<cxxflags>-Wl,-export-dynamic
重新编译bs进程,运行,找到符号。问题解决。
小结:
没看明白?举个栗子:
prog.cpp:
foo.h:
注:这里extern “C”是必须得,否则c++特有的函数符号规则不是dlsym的参数“fun2”
foo.cpp:
编译测试:
失败:
[cll@localhost sharedlib]$ g++ -g -fPIC foo.cpp -shared -o libfoo.so
[cll@localhost sharedlib]$ g++ -ldl prog.cpp -o prog
[cll@localhost sharedlib]$ ./prog
./prog: symbol lookup error: ./libfoo.so: undefined symbol: _Z4fun1v
成功:
[cll@localhost sharedlib]$ g++ -g -fPIC foo.cpp -shared -o libfoo.so
[cll@localhost sharedlib]$ g++ -Wl,--export-dynamic -ldl prog.cpp -o prog
[cll@localhost sharedlib]$ ./prog
INFO: i am fun1
结果显而易见。--export-dynamic参数如果不知道什么意思,很容易被忽略,也只有在这种类似回调的机制里才会显示出不可缺少的价值。
我的所有文章都在公众号 「后端技术学堂」 ,一起来学编程吧。
精彩文章推荐:
我用大数据分析了一线城市1000多份岗位招聘需求,告诉你如何科学找工作
腾讯后台开发面试笔试C++知识点参考笔记
还能这么玩?我用VsCode画类图、流程图、时序图、状态图不要太爽!
面试官:你会几种redis分布式锁?我会三种!
最详细的个人博客教程搭建教程GithubPages+Jekyll 简约风格博客
更多推荐
所有评论(0)