g++编译陷阱

近日在编译ACE库时,依赖库总会产生“undefined reference to XXX”错误,通常这个问题是所引用的函数没有定义导致的,但是这个库中这些函数确实定义了的,排除了这种可能性。

 

那么接下来看一下这个库中这些函数的情况。

初看之下,似乎一切正常,函数也是存在的,

但是仔细观察bind的值,似乎有些不对了,这些函数是动态库导出函数,但是bind显示的值却是local。

linux环境下动态库中的函数默认都是全局可见的,是什么改变了函数的这种属性呢?

首先看一下编译过程的输出信息,编译每一份文件时都设置了-fvisibility=hidden属性,

如果这个设置成hidden,函数确实不会导出。

接着向上追溯,从makefile中寻找问题根源,发现如下逻辑。

结合注释很容易理解,g++高版本支持了visibility属性,当g++版本大于4就会开启此属性,也就是默认的话动态库符号就是local。

在linux下,源文件中的所有函数都有一个默认的visibility属性为public,在编译命令中加入-fvisibility=hidden参数,会将所有默认的public的属性变为hidden。此时,如果对函数设置__attribute__ ((visibility("default")))参数,使特定的函数仍然按默认的public属性处理,则-fvisibility=hidden参数不会对该函数起作用。所以,设置了-fvisibility=hidden参数之后,只有设置了__attribute__ ((visibility("default")))的函数才是对外可见的,如此则效果等同于Visual Studio下的__declspec(dllexport)定义。

问题本来到这里就可以结束了,我们再深入思考几个问题:

1.用c++写的(准确来说是g++编译)导出库供c或其他语言调用时,有时也会出现“undefined reference to XXX”

这是c++为实现函数重载而采用了name mangling方案,把命名空间、函数名和参数组合在一起重新命名,编译器处理之后的函数名称实际上已经不是你调用的那个函数命了。要解决这种问题,可以在导出函数用extern “C”声明解决。

2.如何指定linux中哪些符号可见,哪些不可见呢

__attribute__((visibility("default"))) void Function(){};    
__attribute__((visibility("hidden"))) void Function(){};

设置为default时,没有显式标识为hidden的符号都处理为可见;设置为hidden时,没有显式标识为可见的符号都处理为隐藏。如果您在编译中没有指定-fvisibility选项,编译器会自行处理为缺省的可见性。
    编译器还支持-fvisibility-inlines-hidden选项,用于强制隐藏所有的嵌入函数。当希望对大多数项目使用缺省的可见性,但又希望隐藏所有的嵌入函数时,您可能会用到这个选项。

仿造windows下导出dll的做法,利用宏定义

#if defined SO_EXPORT_VISI
#define SO_EXPORT_VISI_ __attribute__((visibility("default")))
#else
#define SO_EXPORT_VISI_
#endif

3.常见的链接器的含义

-Wl,-Bdynamic/-Bstatic 这两个分别指定了链接是采用动态库还是静态库,也可以用来把静态库编译成动态库。

示例如下:

-Bstatic -la -lb -lc -lm -Bdynamic -lrt -lstdc++

这样就可以把静态库liba、libb、libc合并成一个库,避免了常规的解压再合并的繁琐操作

-Wl,-R 连接时指定运行时依赖的路径,其他调用者就不用再指定依赖库路径了。

-Wl,soname 向so库中写入库名,可以用来做版本控制。

4.更快速的定位问题的方法

nm -D soname

直接用来查看库的导出函数名。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值