Perbedaan antara API dan ABI


194

Saya baru mengenal pemrograman sistem linux dan saya menemukan API dan ABI saat membaca Pemrograman Sistem Linux .

Definisi API:

API mendefinisikan antarmuka tempat satu perangkat lunak berkomunikasi satu sama lain di tingkat sumber.

Definisi ABI:

Sedangkan API mendefinisikan antarmuka sumber, ABI mendefinisikan antarmuka biner tingkat rendah antara dua atau lebih perangkat lunak pada arsitektur tertentu. Ini mendefinisikan bagaimana suatu aplikasi berinteraksi dengan dirinya sendiri, bagaimana suatu aplikasi berinteraksi dengan kernel, dan bagaimana suatu aplikasi berinteraksi dengan perpustakaan.

Bagaimana suatu program berkomunikasi pada tingkat sumber? Apa itu level sumber? Apakah ini terkait dengan kode sumber? Atau sumber perpustakaan disertakan dalam program utama?

Satu-satunya perbedaan yang saya tahu adalah API sebagian besar digunakan oleh programmer dan ABI sebagian besar digunakan oleh kompiler.


2
menurut tingkat sumber mereka berarti sesuatu seperti menyertakan file untuk mengekspos definisi fungsi
Anycorn

Jawaban:


49

API adalah apa yang digunakan manusia. Kami menulis kode sumber. Ketika kita menulis sebuah program dan ingin menggunakan beberapa fungsi perpustakaan kita menulis kode seperti:

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

dan kami perlu tahu bahwa ada metode livenMyHills(), yang membutuhkan parameter integer panjang. Jadi sebagai Antarmuka Pemrograman semuanya dinyatakan dalam kode sumber. Kompiler mengubah ini menjadi instruksi yang dapat dieksekusi yang sesuai dengan implementasi bahasa ini pada sistem operasi khusus ini. Dan dalam hal ini menghasilkan beberapa operasi tingkat rendah pada unit Audio. Jadi bit dan byte tertentu disemprotkan ke beberapa perangkat keras. Jadi pada saat runtime ada banyak aksi tingkat Biner terjadi yang biasanya tidak kita lihat.


310

API: Antarmuka Program Aplikasi

Ini adalah sekumpulan tipe / variabel / fungsi publik yang Anda paparkan dari aplikasi / perpustakaan Anda.

Dalam C / C ++ ini adalah apa yang Anda paparkan dalam file header yang Anda kirimkan dengan aplikasi.

ABI: Antarmuka Biner Aplikasi

Beginilah cara kompiler membangun aplikasi.
Ini mendefinisikan hal-hal (tetapi tidak terbatas pada):

  • Bagaimana parameter dilewatkan ke fungsi (register / stack).
  • Siapa yang membersihkan parameter dari stack (penelepon / callee).
  • Di mana nilai pengembalian ditempatkan untuk pengembalian.
  • Bagaimana pengecualian berkembang.

17
Ini mungkin penjelasan singkat terbaik tentang apa itu ABI, yang pernah saya lihat; gj!
TerryP

3
Kalian harus memutuskan apakah jawaban ini singkat atau rinci. :)
jrok

1
@ jrok: Hal-hal dapat singkat dan terperinci mereka tidak saling eksklusif.
Martin York

@LokiAstari, Jadi bukankah ABI sebenarnya juga API?
Pacerier

4
@Pacerier: Keduanya adalah antarmuka. Tetapi mereka berada pada tingkat abstraksi yang berbeda. API berada di level pengembang aplikasi. ABI berada pada tingkat kompiler (suatu tempat pengembang aplikasi tidak pernah pergi)
Martin York

47

Saya kebanyakan menemukan istilah-istilah ini dalam arti perubahan yang tidak kompatibel dengan API, atau perubahan yang tidak kompatibel ABI.

Perubahan API pada dasarnya adalah tempat kode yang dikompilasi dengan versi sebelumnya tidak akan berfungsi lagi. Ini bisa terjadi karena Anda menambahkan argumen ke suatu fungsi, atau mengubah nama sesuatu yang dapat diakses di luar kode lokal Anda. Setiap kali Anda mengubah header, dan itu memaksa Anda untuk mengubah sesuatu dalam file .c / .cpp, Anda telah membuat perubahan API.

Perubahan ABI adalah tempat kode yang telah dikompilasi dengan versi 1 tidak akan lagi berfungsi dengan versi 2 dari basis kode (biasanya perpustakaan). Ini umumnya lebih sulit untuk melacak daripada perubahan yang tidak kompatibel dengan API karena sesuatu yang sederhana seperti menambahkan metode virtual ke kelas dapat ABI tidak kompatibel.

Saya telah menemukan dua sumber yang sangat berguna untuk mencari tahu apa kompatibilitas ABI itu dan bagaimana cara melestarikannya:


4
+1 untuk menunjukkan keeksklusifan timbal balik mereka. Sebagai contoh, pengenalan Java terhadap kata kunci yang menegaskan adalah perubahan API yang tidak kompatibel namun kompatibel ABI.oracle.com/javase/7/docs/technotes/guides/language/… .
Pacerier

Anda dapat menambahkan ke bagian sumber daya Anda "3.6. Perpustakaan Tidak Kompatibel" dari tldp.org/HOWTO/Program-Library-HOWTO/share-libraries.html , yang berisi daftar apa yang dapat menyebabkan perubahan ABI.
Demi-Lune

20

Ini adalah penjelasan awam saya:

  • API - pikirkan includefile. Mereka menyediakan antarmuka pemrograman.
  • ABI - pikirkan modul kernel. Ketika Anda menjalankannya pada beberapa kernel, ia harus menyetujui cara berkomunikasi tanpa menyertakan file, yaitu sebagai antarmuka biner tingkat rendah.

13

Linux shared library minimal runnable API vs contoh ABI

Jawaban ini telah diekstraksi dari jawaban saya yang lain: Apa itu antarmuka biner aplikasi (ABI)? tetapi saya merasa bahwa itu langsung menjawab yang satu ini juga, dan bahwa pertanyaan itu bukan duplikat.

Dalam konteks perpustakaan bersama, implikasi paling penting dari "memiliki ABI stabil" adalah bahwa Anda tidak perlu mengkompilasi ulang program Anda setelah perpustakaan berubah.

Seperti yang akan kita lihat dalam contoh di bawah ini, adalah mungkin untuk memodifikasi ABI, program yang rusak, meskipun API tidak berubah.

main.c

#include <assert.h>
#include <stdlib.h>

#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 <stdlib.h>

#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

Kompilasi dan berjalan dengan baik dengan:

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

Sekarang, misalkan untuk v2 perpustakaan, kami ingin menambahkan bidang baru untuk mylib_mystrictdipanggil new_field.

Jika kami menambahkan bidang sebelumnya old_fieldseperti pada:

typedef struct {
    int new_field;
    int old_field;
} mylib_mystruct;

dan membangun kembali perpustakaan tetapi tidak main.out, maka pernyataan itu gagal!

Ini karena baris:

myobject->old_field == 1

telah menghasilkan perakitan yang mencoba mengakses yang pertama intdari struct, yang sekarang new_fieldbukan yang diharapkan old_field.

Karenanya perubahan ini mematahkan ABI.

Namun, jika kami tambahkan new_fieldsetelah old_field:

typedef struct {
    int old_field;
    int new_field;
} mylib_mystruct;

kemudian perakitan lama yang dihasilkan masih mengakses yang pertama intdari struct, dan program masih bekerja, karena kami menjaga ABI stabil.

Ini adalah versi yang sepenuhnya otomatis dari contoh ini di GitHub .

Cara lain untuk menjaga ABI ini stabil adalah memperlakukannya mylib_mystructsebagai struct buram , dan hanya mengakses ladangnya melalui metode helpers. Ini membuatnya lebih mudah untuk menjaga ABI stabil, tetapi akan menimbulkan overhead kinerja karena kami akan melakukan lebih banyak panggilan fungsi.

API vs ABI

Dalam contoh sebelumnya, menarik untuk dicatat bahwa menambahkan new_fieldsebelumnya old_field, hanya merusak ABI, tetapi bukan API.

Apa artinya ini, adalah bahwa jika kita telah mengkompilasi ulang main.cprogram kita melawan perpustakaan, itu akan berhasil.

Namun kami juga telah merusak API jika kami mengubah misalnya tanda tangan fungsi:

mylib_mystruct* mylib_init(int old_field, int new_field);

karena dalam kasus itu, main.cakan berhenti kompilasi sama sekali.

Semantic API vs programming API vs ABI

Kami juga dapat mengklasifikasikan perubahan API dalam tipe ketiga: perubahan semantik.

Sebagai contoh, jika kita telah memodifikasi

myobject->old_field = old_field;

untuk:

myobject->old_field = old_field + 1;

maka ini tidak akan merusak baik API maupun ABI, tetapi main.cakan tetap rusak!

Ini karena kami mengubah "deskripsi manusia" dari apa fungsi yang seharusnya dilakukan daripada aspek yang terlihat secara program.

Saya hanya memiliki wawasan filosofis bahwa verifikasi formal perangkat lunak dalam arti memindahkan lebih dari "API semantik" ke lebih "API yang dapat diverifikasi secara terprogram".

API Semantik vs API Pemrograman

Kami juga dapat mengklasifikasikan perubahan API dalam tipe ketiga: perubahan semantik.

API semantik, biasanya merupakan deskripsi bahasa alami dari apa yang seharusnya dilakukan oleh API, biasanya termasuk dalam dokumentasi API.

Karena itu dimungkinkan untuk memecah API semantik tanpa merusak program itu sendiri.

Sebagai contoh, jika kita telah memodifikasi

myobject->old_field = old_field;

untuk:

myobject->old_field = old_field + 1;

maka ini tidak akan merusak pemrograman API, maupun ABI, tetapi main.cAPI semantik akan rusak.

Ada dua cara untuk memeriksa API kontrak secara terprogram:

  • menguji banyak kasus sudut. Mudah dilakukan, tetapi Anda mungkin selalu melewatkannya.
  • verifikasi formal . Sulit dilakukan, tetapi menghasilkan bukti matematis tentang kebenaran, pada dasarnya menyatukan dokumentasi dan tes menjadi cara yang "dapat diverifikasi" oleh manusia / mesin! Selama tidak ada bug dalam deskripsi formal Anda tentu saja ;-)

Diuji di Ubuntu 18.10, GCC 8.2.0.


2
Hormat saya adalah jawaban yang cukup detail untuk membantu saya memahami perbedaan antara API dan ABI. Terima kasih!
Rakshith Ravi

9

( A plikasi B inary I nterface) Sebuah spesifikasi untuk platform perangkat keras tertentu dikombinasikan dengan sistem operasi. Ini adalah satu langkah di luar API ( A pterication P rogram I nterface), yang mendefinisikan panggilan dari aplikasi ke sistem operasi. ABI mendefinisikan API plus bahasa mesin untuk keluarga CPU tertentu. API tidak memastikan kompatibilitas runtime, tetapi ABI melakukannya, karena ia menentukan bahasa mesin, atau format runtime.

masukkan deskripsi gambar di sini

Kesopanan


9

Izinkan saya memberikan contoh spesifik bagaimana ABI dan API berbeda di Jawa.

Perubahan ABI yang tidak kompatibel adalah jika saya mengubah metode A # m () dari mengambil Stringargumen sebagai String...argumen. Ini tidak kompatibel dengan ABI karena Anda harus mengkompilasi ulang kode yang memanggilnya, tetapi ini kompatibel dengan API karena Anda dapat menyelesaikannya dengan mengkompilasi ulang tanpa perubahan kode pada pemanggil.

Berikut adalah contohnya. Saya memiliki perpustakaan Java saya dengan kelas A

// Version 1.0.0
public class A {
    public void m(String string) {
        System.out.println(string);
    }
}

Dan saya memiliki kelas yang menggunakan perpustakaan ini

public class Main {
    public static void main(String[] args) {
        (new A()).m("string");
    }
}

Sekarang, penulis perpustakaan mengkompilasi kelas A mereka, saya mengkompilasi Main class saya dan semuanya bekerja dengan baik. Bayangkan versi baru A datang

// Version 2.0.0
public class A {
    public void m(String... string) {
        System.out.println(string[0]);
    }
}

Jika saya hanya mengambil kelas A yang baru dikompilasi dan menjatuhkannya bersama-sama dengan kelas Main yang sebelumnya telah dikompilasi, saya mendapatkan pengecualian pada upaya untuk memanggil metode

Exception in thread "main" java.lang.NoSuchMethodError: A.m(Ljava/lang/String;)V
        at Main.main(Main.java:5)

Jika saya mengkompilasi ulang Main, ini sudah diperbaiki dan semua bekerja kembali.


6

Program Anda (kode sumber) dapat dikompilasi dengan modul yang menyediakan API yang tepat .

Program Anda (biner) dapat berjalan pada platform yang menyediakan ABI yang tepat .

API membatasi jenis definisi, definisi fungsi, makro, terkadang variabel global yang harus dipaparkan oleh perpustakaan.

ABI membatasi apa "platform" harus menyediakan untuk menjalankan program Anda. Saya suka mempertimbangkannya dalam 3 level:

  • tingkat prosesor - set instruksi, konvensi pemanggilan

  • tingkat kernel - konvensi pemanggilan sistem, konvensi jalur file khusus (mis. /procdan /sysfile di Linux), dll.

  • Level OS - format objek, pustaka runtime, dll.

Pertimbangkan cross-compiler bernama arm-linux-gnueabi-gcc. "arm" menunjukkan arsitektur prosesor, "linux" menunjukkan kernel, "gnu" menunjukkan program targetnya menggunakan libc GNU sebagai pustaka runtime, berbeda dengan arm-linux-androideabi-gccyang menggunakan implementasi libc Android.


1
ini adalah penjelasan yang sangat bagus tentang perbedaan di antara mereka, dan dalam perspektif yang sangat unik.
Sajuuk

1

API- Application Programming Interfaceadalah antarmuka waktu kompilasi yang dapat digunakan oleh pengembang untuk menggunakan fungsionalitas non-proyek seperti perpustakaan, OS, panggilan inti dalam kode sumber

ABI[Tentang] -Application Binary Interfaceadalahantarmuka runtime yang digunakan oleh suatu program selama mengeksekusi untuk komunikasi antara komponen dalam kode mesin

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.