如何做到二进制兼容

如何做到二进制兼容?

什么是二进制兼容?
       二进制兼容,即某个程序(或库)有依赖其他库A,当库A升级时可以做到向后兼容,则程序(或库)功能不受影响。

为什么要做到二进制兼容?
       很明显的道理,如果库A升级没有能够做到二进制兼容,那么所有依赖它的程序(或库)都需要重新编译,否则会出现各种未知异常,其直接现象就是程序莫名其妙地挂掉。

如何做到二进制兼容?
       这是最核心的部分。最近负责的项目升级,同时该项目依赖的框架也同时升级。在实际部署之后发现,自己的项目在不断地挂掉,即挂掉->重启->挂掉。当时比较疑惑,因为这个版本我们自己进行过充分测试已经无问题,怎么可能出现问题呢?
       仔细想想,发现以前在本地测试时也有遇到过这种情况,原因便找到了。如图1-0所示

图1-0 程序调用关系图
        我们的可执行程序启动时会加载库A,库B,以及基础库Base;且库A,库B都会调用基础库Base中的函数。在上文说到的挂机场景里,我们升级了库A,并且同时升级了基础库Base,但没有重新编译库B。由于库A和库B都运行在一个进程中,库B出错的结果导致linux可执行程序的挂掉。
       既然原因找到了,问题的修改就简单了,可以采用两种方式来修改:
       1. 删除库B或不加载库B。这是由我们的运用场景决定的,因为部署的机器上不需要运行库B的功能,所以可以删除库B。
       2. 将单进程更改为多进程,即库B和库A运行在不同的进程上,则库B挂掉不会引起库整个运行程序的挂掉。这种修改方式应该说是最优的,但改动较大,而且框架部分是有专人开发,所以无法实行。
        最终我们采用了第一种处理方式。

       那么为什么会出现这个问题呢?这就是本文一直在将的二进制兼容的问题。二进制兼容,其实总体而言可以说是接口的兼容。
       1)基础库Base提供的接口,如果各个版本都保持不变,则为二进制兼容。
       2)基础库Base暴露在接口文件中的各个结构体,如果有被外部库所使用,则需要在各个版本中保持不变。为什么?很简单,因为外部库中再alloc结构体时,其大小通常是通过sizeof(结构体)来计算的。如果新版本结构体的长度发生了改动,那么旧版本在没有重新编译的情况下,会出现非法访问的情形。
       3)基础库Base暴露在接口文件中的enum,如果在新版本中有增加,只能从最后开始加,不能够在中途或前边开始加。
       4)旧接口参数,返回值需要在各版本一致。如果真的需要增加参数,请另加一个函数。

       上面我们是从库的提供方来说明二进制兼容性的条件,那么库的适用方应该如果保持良好的二进制兼容特性呢?
       1)只调用Base库接口文件的接口,不直接调用接口文件的结构体。

        我们在部署中出现的问题,就是由于Base库的结构体发生了改变,而库B里边有直接调用接口体导致的。所以归根到底,最好的方式是库中封装出一个接口,以使我们可以操作该结构体。





  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值