首页 文章

API和ABI之间的区别

提问于
浏览
151

我是linux系统编程的新手,我在阅读 Linux System Programming 时遇到了API和ABI .

Definition of API :

API定义了一个软件在源级别与另一个软件进行通信的接口 .

Definition of ABI :

API定义源接口,而ABI定义特定体系结构上两个或多个软件之间的低级二进制接口 . 它定义了应用程序如何与自身交互,应用程序如何与内核交互以及应用程序如何与库交互 .

程序如何在源级别进行通信?什么是源级别?它无论如何都与源代码有关?或者库的源代码包含在主程序中?

我所知道的唯一区别是API主要由程序员使用,而ABI主要由编译器使用 .

7 回答

  • 2

    这是我的外行解释:

    • api - 想想 include 文件 . 他们提供编程接口

    • abi - 想想内核模块 . 当你在某个内核上运行它时,它们必须同意如何在没有包含文件的情况下进行通信,即作为低级二进制接口

  • 5

    API是人类使用的 . 我们编写源代码 . 当我们编写程序并想要使用某些库函数时,我们编写如下代码:

    long howManyDecibels = 123L;
     int ok = livenMyHills( howManyDecibels);
    

    我们需要知道有一个方法 livenMyHills() ,它采用一个长整数参数 . 因此,作为一个编程接口,我们通常不会看到很多二进制级别的动作 .

  • 252

    您的程序(源代码)可以使用提供正确 API 的模块进行编译 .

    您的程序(二进制)可以在提供正确 ABI 的平台上运行 .

    API限制类型定义,函数定义,宏,有时是库应公开的全局变量 .

    ABI限制“平台”应该为您运行的程序提供什么 . 我想在3个级别考虑它:

    • 处理器级别 - 指令集,调用约定

    • 内核级别 - 系统调用约定,特殊文件路径约定(例如Linux中的 /proc/sys 文件)等 .

    • 操作系统级别 - 对象格式,运行时库等 .

    考虑一个名为 arm-linux-gnueabi-gcc 的交叉编译器 . "arm"表示处理器体系结构,"linux"表示内核,"gnu"表示其目标程序使用GNU的libc作为运行时库,不同于使用Android的libc实现的 arm-linux-androideabi-gcc .

  • 5

    API:应用程序接口

    这是您从应用程序/库中公开的一组公共类型/变量/函数 .

    在C / C中,这是您在应用程序附带的头文件中公开的内容 .

    ABI:应用程序二进制接口

    这是编译器构建应用程序的方式 .
    它定义的东西(但不限于):

    • 如何将参数传递给函数(寄存器/堆栈) .

    • 谁清除堆栈中的参数(调用者/被调用者) .

    • 返回值的返回值 .

    • 例外如何传播 .

  • 19

    我主要是在API不兼容的更改或ABI不兼容的更改的意义上遇到这些术语 .

    API更改本质上是使用以前版本编译的代码将不再起作用的地方 . 这可能是因为您向函数添加了参数,或者更改了本地代码之外可访问的名称 . 每次更改 Headers 时,它都会强制您更改.c / .cpp文件中的某些内容,您已经进行了API更改 .

    ABI更改是已针对版本1编译的代码将不再适用于代码库的版本2(通常是库) . 与API不兼容的更改相比,这通常更难以跟踪,因为向类添加虚拟方法这样简单的操作可能与ABI不兼容 .

    我发现了两个非常有用的资源,用于确定ABI的兼容性以及如何保留它:

  • 39

    A pplication B inary I nterface)与操作系统结合的特定硬件平台的规范 . 它超越了API( A pplication P rogram I nterface),它定义了从应用程序到操作系统的调用 . ABI定义了API以及特定CPU系列的机器语言 . API不能确保运行时兼容性,但ABI确实如此,因为它定义了机器语言或运行时格式 .

    Courtesy

  • 39

    让我举一个具体的例子,说明ABI和API在Java方面有何不同 .

    ABI不兼容的更改是,如果我将方法A#m()更改为将 String 作为参数更改为 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,这是固定的,一切都在重新运行 .

相关问题