linux 库全局变量_跟我学c++中级篇——Linux下的动态库之二

28777a91683c42b44a5859562ca08a58.png

一、动态库的设计

动态库接口的设计也就是ABI的接口设计,这和大家经常遇到的API设计其实原则没有啥根本的不同。只是应用的方向不同而已。保持二进制的兼容,也即保持ABI的稳定性是基本准则。这个要求从理论上讲其实并不难,但涉及到c++具体的情况发生了一些变化。C++编译器有一套完整的复杂的改名机制,而且没有形成标准;另外前面提到的静态和全局变量的互相调用初始化问题也需要重点保持关注;最后一个不好解决的就是c++相比C语言,引入了模板机制。
这样就对c++的ABI设计提出了比较高的要求,当然,很多同学可能在实际工程中也没有注意到这个问题,也把工作搞定了,但搞定了,不代表就完成工作了。考验一个设计的优劣,不再于简单的能运行完成指定的任务(当然,现在的国内的公司普遍把这个当成“真理”)。那么怎么能做好一个二进制的接口设计呢?可以考虑下面的基本方式:
1、强制使用C的命名方式,不使用c++的改名机制,这个在编译器都提供了支持。extern "C"
2、提供完整的ABI声明头文件
3、只使用标准的C关键字,这个非常重要,否则在跨平台或者跨编译器时会很痛苦
4、将全局和静态变量集中使用和命名,使用工厂或者专门的模块来控制ABI接口的访问。可以参考COM,虽然COM太复杂,被淘汰了,但是方向是好的。
5、不使用抽象类做为ABI的接口,这个网上有专门的大牛讨论,有兴趣可以查找一下分析分析。
6、广泛使用命名空间来控制符号冲突,这个非常重要,而且如无必要,不建议使用匿名空间。
7、在必要的情况下,通过指定 --no-undefined选项来强行限制链接的符号解析行为

二、动态库之间的互相调用

重点说一下动态库之间的互相调用,在实际工程的例子中,象前面那样的例子是非常少见的,通常是一大堆动态库供你调用,而且动态库之间也会互相调用,这就引申出来动态库中一个非常有名的问题“DLL HELL”,只不过这个问题在Windows上表现更抢眼,所以人们都忽略在Linux上的类似问题。这个问题其实总结起来就是两点:
1、版本问题
2、重名问题
在实际工作中,经常可能遇到一些类似的行为大家起名一样,而在升级库的时候儿,不小时就把同名的文件替换掉,这个问题还挺不好找;另外一个就是版本,其实又回到了ABI兼容的问题。
如果仅仅是库依赖缺少,可以使用ldd 命令查看一下依赖的关系,看一下例子:

ldd libcompare.so
       linux-vdso.so.1 (0x00007ffc411d5000)
       libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f07942b1000)
       libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0793f13000)
       libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f0793cfb000)
       libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f079390a000)
       /lib64/ld-linux-x86-64.so.2 (0x00007f0794841000)

看上面的命令执行完成后,就可以看到libcompare.so依赖了哪些文件,如果找不到,就会报出来。这时候儿就可以有的放矢的去查找原因了,不过,如果是版本的问题或者重名覆盖的问题,还是比较头疼的。所以,对动态的管理要有一套比较好的机制,比如版本的命名,库的命名等,避免上述这种比较低级的错误发生。
在实际工作中还会遇到下面这种问题,就是A库依赖另外的B库,但是B库挨过来又依赖A库,怎么解决呢?
首先,要弄清楚这两个库是自己的库还是第三的库。如果是自己的库,说明自己的设计有问题,要改。把相关的代码不断的抽象,解耦,去除依赖;如果确实无法解耦或者说水平有限,就干脆把它们放到一个库中;但对于第三方的库,就不好这么做了,因为没有源码。那么方法也是有的,就是复用前面的例子,使用动态库的动态加载技术。

三、应用与例程

下面看一个互相调用的例子:

//display.c

先编译C库:

gcc 

然后再编译C++库

g++ 

这个没有什么变化,然后看编译执行:

g++ 

最后执行:

LD_LIBRARY_PATH=. ./dtest
cur data is:200
max is :200

这里需要提醒的是,有些情况下,编译时,库的顺序是有要求的,遇到这种情况,解决方法有有两种,一种是上面的去除循环依赖,第二是,越是依赖的基础库,越放到后面。这类问题在后面会详细的分析,不用着急。

四、总结

动态库的使用过程中,有几个命令比较好用,一个是前面提到过的nm,ldd,还有一个就是strip,这些命令会在后面的文件分析和加载分析中,逐步示例使用。动态库技术是一个基础的开发技术,希望引起重视,从基础上明白动态库(共享库)到底是如何编写、加载和运行的,就会在实际工程中更好的解决出现的各种问题。

6f6a8fb64ee5a9da7e5091f88790045d.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值