背景:

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 简约风格博客
 

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐