android abi和api,API和ABI之间的区别

Linux共享库最小可运行API与ABI示例

在共享库的上下文中,“具有稳定的ABI”最重要的含义是,在更改库后,您无需重新编译程序。

如下面的示例所示,即使API不变,也可以修改ABI,破坏程序。

main.c

#include

#include

#include "mylib.h"

int main(void) {

mylib_mystrict *myobject = mylib_init(1);

assert(myobject->old_field == 1);

free(myobject);

return EXIT_SUCCESS;

}

mylib.c

#include

#include "mylib.h"

mylib_mystruct* mylib_init(int old_field) {

mylib_mystruct *myobject;

myobject = malloc(sizeof(mylib_mystruct));

myobject->old_field = old_field;

return myobject;

}

mylib.h

#ifndef MYLIB_H

#define MYLIB_H

typedef struct {

int old_field;

} mylib_mystruct;

mylib_mystruct* mylib_init(int old_field);

#endif

编译并运行良好:

cc='gcc -pedantic-errors -std=c89 -Wall -Wextra'

$cc -fPIC -c -o mylib.o mylib.c

$cc -L . -shared -o libmylib.so mylib.o

$cc -L . -o main.out main.c -lmylib

LD_LIBRARY_PATH=. ./main.out

现在,假设对于库的v2,我们想向mylib_mystrict添加一个名为new_field的新字段。

如果我们将字段添加到old_field之前,如下所示:

typedef struct {

int new_field;

int old_field;

} mylib_mystruct;

并重建了库,但没有重建main.out,则断言失败!

这是因为该行:

myobject->old_field == 1

生成了试图访问结构的第一个int的程序集,该程序集现在是new_field而不是预期的old_field。

因此,此更改破坏了ABI。

但是,如果我们在new_field之后添加old_field:

typedef struct {

int old_field;

int new_field;

} mylib_mystruct;

然后,旧生成的程序集仍然会访问该结构的第一个int,并且该程序仍然可以运行,因为我们保持了ABI的稳定。

保持此ABI稳定的另一种方法是将mylib_mystruct视为opaque struct,并且只能通过方法助手来访问其字段。这样可以更轻松地保持ABI的稳定,但是会增加性能开销,因为我们需要执行更多的函数调用。

API与ABI

在前面的示例中,有趣的是注意到在new_field之前添加old_field只会破坏ABI,而不会破坏API。

这意味着,如果我们针对库重新编译main.c程序,则无论如何它都可以工作。

我们也会破坏API,但是如果我们更改了例如函数签名:

mylib_mystruct* mylib_init(int old_field, int new_field);

因为在这种情况下,main.c将完全停止编译。

语义API与编程API与ABI

我们还可以将API更改分类为第三种类型:语义更改。

例如,如果我们已经修改

myobject->old_field = old_field;

收件人:

myobject->old_field = old_field + 1;

这将不会破坏API或ABI,但是main.c仍然会破坏!

这是因为我们更改了该功能应该执行的“人工描述”,而不是程序上引人注目的方面。

我只是有一种哲学上的见解,即formal verification of software在某种意义上将更多的“语义API”转移到了一个“可程序验证的API”中。

语义API与编程API

我们还可以将API更改分类为第三种类型:语义更改。

语义API通常是API应该执行的自然语言描述,通常包含在API文档中。

因此可以在不破坏程序本身的情况下破坏语义API。

例如,如果我们已经修改

myobject->old_field = old_field;

收件人:

myobject->old_field = old_field + 1;

这将不会破坏编程API或ABI,但是main.c语义API会破坏。

有两种方法可以以编程方式检查合同API:

测试一些极端情况。容易做到,但您可能总是会错过一个。

formal verification。难度较大,但会产生正确性的数学证明,从本质上将文档和测试统一为“人工” /机器可验证的方式!只要您对课程的形式描述中没有错误;-)

在Ubuntu 18.10,GCC 8.2.0中进行了测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值