我是Linux系统编程的新手,在阅读时遇到了API和ABI
Linux系统编程。
API的定义:
API定义了接口
一个软件进行通信
与另一个在源级。
ABI的定义:
而API定义了一个源
接口时,ABI定义了
两个之间的低级二进制接口
或者更多的软件
特定的体系结构。它定义了
应用程序如何与
本身,应用程序如何交互
与内核,以及如何一个
应用程序与库交互。
程序如何在源级进行通信?什么是源级别?它是否与源代码有关?或者库的源代码包含在主程序中?
我所知道的唯一区别是API主要由程序员使用,而ABI主要由编译器使用。
API是人类使用的。我们编写源代码。当我们编写程序并想要使用一些库函数时,我们编写如下代码:
long howManyDecibels = 123L;
int ok = livenMyHills(howManyDecibels);
and we needed to know that there is a method livenMyHills(), which takes a long integer parameter. So as a Programming Interface it's all expressed in source code. The compiler turns this into executable instructions which conform to the implementation of this language on this particular operating system. And in this case result in some low level operations on an Audio unit. So particular bits and bytes are squirted at some hardware. So at runtime there's lots of Binary level action going on which we don't usually see.
在二进制级别,必须对在二进制级别传递的字节有一个精确的定义,例如4字节整数中的字节顺序,或者复杂数据结构的布局——是否有填充字节来对齐一些值。这个定义就是ABI。
让我举一个具体的例子,说明在Java中ABI和API是如何不同的。
ABI不兼容的更改是如果我将方法a# m()从将字符串作为参数更改为String…论点。这不是ABI兼容的,因为您必须重新编译调用它的代码,但它是API兼容的,因为您可以通过重新编译来解析它,而无需在调用方中更改任何代码。
这里有一个例子。我的Java库有类A
// Version 1.0.0
public class A {
public void m(String string) {
System.out.println(string);
}
}
我有一个类使用这个库
public class Main {
public static void main(String[] args) {
(new A()).m("string");
}
}
现在,库作者编译了他们的类A,我编译了我的类Main,一切都运行得很好。想象一个新版本的a出现了
// Version 2.0.0
public class A {
public void m(String... string) {
System.out.println(string[0]);
}
}
如果我只是使用新编译的类A,并将其与之前编译的类Main一起删除,那么在试图调用该方法时就会得到异常
Exception in thread "main" java.lang.NoSuchMethodError: A.m(Ljava/lang/String;)V
at Main.main(Main.java:5)
如果我重新编译Main,这是固定的,所有工作再次。
您的程序(源代码)可以使用提供适当API的模块进行编译。
您的程序(二进制)可以在提供适当ABI的平台上运行。
API限制了类型定义、函数定义、宏,有时还有库应该公开的全局变量。
ABI限制了一个“平台”应该为您的程序运行提供什么。我喜欢从三个层面来考虑:
处理器级——指令集,调用约定
内核级——系统调用约定,特殊的文件路径约定(例如Linux中的/proc和/sys文件),等等。
操作系统级别——对象格式、运行时库等。
考虑一个名为arm-linux-gnueabi-gcc的交叉编译器。“arm”表示处理器架构,“linux”表示内核,“gnu”表示其目标程序使用gnu的libc作为运行时库,不同于arm-linux-androideabi-gcc使用Android的libc实现。