Ich bin neu in der Linux-Systemprogrammierung und bin beim Lesen der Linux-Systemprogrammierung auf API und ABI gestoßen .
Definition der API:
Eine API definiert die Schnittstellen, über die eine Software auf Quellenebene mit einer anderen kommuniziert.
Definition von ABI:
Während eine API eine Quellschnittstelle definiert, definiert ein ABI die binäre Schnittstelle auf niedriger Ebene zwischen zwei oder mehr Softwareteilen in einer bestimmten Architektur. Es definiert, wie eine Anwendung mit sich selbst interagiert, wie eine Anwendung mit dem Kernel interagiert und wie eine Anwendung mit Bibliotheken interagiert.
Wie kann ein Programm auf Quellenebene kommunizieren? Was ist eine Quellenebene? Hat es sowieso mit Quellcode zu tun? Oder wird die Quelle der Bibliothek in das Hauptprogramm aufgenommen?
Der einzige Unterschied, den ich kenne, ist, dass API hauptsächlich von Programmierern und ABI hauptsächlich vom Compiler verwendet wird.
Antworten:
Die API wird von Menschen verwendet. Wir schreiben Quellcode. Wenn wir ein Programm schreiben und eine Bibliotheksfunktion verwenden möchten, schreiben wir Code wie:
und wir mussten wissen, dass es eine Methode gibt
livenMyHills()
, die einen langen ganzzahligen Parameter benötigt. Als Programmierschnittstelle wird alles im Quellcode ausgedrückt. Der Compiler wandelt dies in ausführbare Anweisungen um, die der Implementierung dieser Sprache auf diesem bestimmten Betriebssystem entsprechen. In diesem Fall führt dies zu einigen Operationen mit niedrigem Pegel an einer Audioeinheit. So werden bestimmte Bits und Bytes auf einige Hardware gespritzt. Zur Laufzeit gibt es also viele Aktionen auf Binärebene, die wir normalerweise nicht sehen.quelle
API: Anwendungsprogrammschnittstelle
Dies ist der Satz öffentlicher Typen / Variablen / Funktionen, die Sie aus Ihrer Anwendung / Bibliothek verfügbar machen.
In C / C ++ ist dies das, was Sie in den Header-Dateien verfügbar machen, die Sie mit der Anwendung liefern.
ABI: Application Binary Interface
So erstellt der Compiler eine Anwendung.
Es definiert Dinge (ist aber nicht darauf beschränkt):
quelle
Ich stoße meistens auf diese Begriffe im Sinne einer API-inkompatiblen Änderung oder einer ABI-inkompatiblen Änderung.
Bei einer API-Änderung funktioniert Code, der mit der vorherigen Version kompiliert worden wäre, im Wesentlichen nicht mehr. Dies kann passieren, weil Sie einer Funktion ein Argument hinzugefügt oder den Namen von etwas geändert haben, auf das außerhalb Ihres lokalen Codes zugegriffen werden kann. Jedes Mal, wenn Sie einen Header ändern und Sie gezwungen sind, etwas in einer .c / .cpp-Datei zu ändern, haben Sie eine API-Änderung vorgenommen.
Bei einer ABI-Änderung funktioniert Code, der bereits für Version 1 kompiliert wurde, nicht mehr mit Version 2 einer Codebasis (normalerweise einer Bibliothek). Dies ist im Allgemeinen schwieriger nachzuverfolgen als eine API-inkompatible Änderung, da etwas so Einfaches wie das Hinzufügen einer virtuellen Methode zu einer Klasse ABI-inkompatibel sein kann.
Ich habe zwei äußerst nützliche Ressourcen gefunden, um herauszufinden, was ABI-Kompatibilität ist und wie sie erhalten werden kann:
quelle
Dies sind meine Erklärungen für Laien:
include
Dateien. Sie bieten Programmierschnittstellen.quelle
Beispiel für eine minimal ausführbare API der gemeinsam genutzten Linux-Bibliothek im Vergleich zum ABI-Beispiel
Diese Antwort wurde aus meiner anderen Antwort extrahiert: Was ist eine Application Binary Interface (ABI)?aber ich hatte das Gefühl, dass es auch dieses direkt beantwortet und dass die Fragen keine Duplikate sind.
Im Zusammenhang mit gemeinsam genutzten Bibliotheken besteht die wichtigste Auswirkung eines "stabilen ABI" darin, dass Sie Ihre Programme nach dem Ändern der Bibliothek nicht neu kompilieren müssen.
Wie wir im folgenden Beispiel sehen werden, ist es möglich, den ABI zu ändern und Programme zu unterbrechen, obwohl die API unverändert bleibt.
Haupt c
mylib.c
mylib.h
Kompiliert und läuft gut mit:
Nun sei angenommen , dass für v2 der Bibliothek, wir ein neues Feld hinzufügen möchten
mylib_mystrict
genanntnew_field
.Wenn wir das Feld zuvor
old_field
wie folgt hinzugefügt haben :und die Bibliothek wieder aufgebaut, aber nicht
main.out
, dann schlägt die Behauptung fehl!Dies liegt daran, dass die Zeile:
hatte eine Assembly generiert, die versucht, auf die allererste
int
Struktur zuzugreifen , die jetztnew_field
anstelle der erwarteten istold_field
.Daher hat diese Änderung den ABI gebrochen.
Wenn wir jedoch
new_field
nachher hinzufügenold_field
:Dann greift die alte generierte Assembly immer noch auf die erste
int
Struktur zu, und das Programm funktioniert weiterhin, da wir den ABI stabil gehalten haben.Hier ist ein vollautomatische Version dieses Beispiels auf GitHub .
Eine andere Möglichkeit, diesen ABI stabil zu halten, wäre die Behandlung
mylib_mystruct
als undurchsichtige Struktur gewesen und nur über Methodenhelfer auf seine Felder zuzugreifen. Dies macht es einfacher, den ABI stabil zu halten, würde jedoch einen Leistungsaufwand verursachen, da wir mehr Funktionsaufrufe ausführen würden.API gegen ABI
Im vorherigen Beispiel ist es interessant, dass die Zugabe
new_field
vorold_field
, nur das ABI brach, aber nicht die API.Was dies bedeutet, ist, dass wir unsere neu kompiliert hätten
main.c
Programm gegen die Bibliothek hätten, es trotzdem funktioniert hätte.Wir hätten die API jedoch auch beschädigt, wenn wir zum Beispiel die Funktionssignatur geändert hätten:
da in diesem Fall
main.c
das Kompilieren ganz aufhören.Semantische API gegen Programmier-API gegen ABI
Wir können API-Änderungen auch in einen dritten Typ einteilen: semantische Änderungen.
Zum Beispiel, wenn wir geändert hätten
zu:
dann hätte dies weder API noch ABI kaputt gemacht,
main.c
würde aber trotzdem kaputt gehen!Dies liegt daran, dass wir die "menschliche Beschreibung" dessen, was die Funktion tun soll, geändert haben und nicht einen programmatisch wahrnehmbaren Aspekt.
Ich hatte gerade die philosophische Einsicht, dass die formale Verifizierung von Software in gewissem Sinne mehr von der "semantischen API" in eine "programmatisch überprüfbare API" verwandelt.
Semantische API vs Programmier-API
Wir können API-Änderungen auch in einen dritten Typ einteilen: semantische Änderungen.
Die semantische API ist normalerweise eine natürliche Beschreibung dessen, was die API tun soll, normalerweise in der API-Dokumentation enthalten.
Es ist daher möglich, die semantische API zu unterbrechen, ohne den Programmerstellung selbst zu unterbrechen.
Zum Beispiel, wenn wir geändert hätten
zu:
dann hätte dies weder Programmier-API noch ABI kaputt gemacht, aber
main.c
die semantische API würde beschädigt.Es gibt zwei Möglichkeiten, die Vertrags-API programmgesteuert zu überprüfen:
Getestet in Ubuntu 18.10, GCC 8.2.0.
quelle
( A pplication B inary I nterface) eine Spezifikation für eine spezifische Hardware - Plattform mit dem Betriebssystem kombiniert. Es ist ein Schritt über den API ( A pplication P rogram I nterface), welche die Anrufe von der Anwendung auf das Betriebssystem definiert. Der ABI definiert die API sowie die Maschinensprache für eine bestimmte CPU-Familie. Eine API stellt keine Laufzeitkompatibilität sicher, ein ABI jedoch, da sie die Maschinensprache oder das Laufzeitformat definiert.
Höflichkeit
quelle
Lassen Sie mich ein konkretes Beispiel geben, wie sich ABI und API in Java unterscheiden.
Eine ABI-inkompatible Änderung ist, wenn ich eine Methode A # m () von a
String
als Argument inString...
Argument ändere . Dies ist nicht ABI-kompatibel, da Sie den Code, der das aufruft, neu kompilieren müssen. Es ist jedoch API-kompatibel, da Sie es durch Neukompilieren ohne Codeänderungen im Aufrufer beheben können.Hier ist das Beispiel. Ich habe meine Java-Bibliothek mit Klasse A.
Und ich habe eine Klasse, die diese Bibliothek verwendet
Jetzt hat der Bibliotheksautor seine Klasse A zusammengestellt, ich habe meine Klasse Main zusammengestellt und alles funktioniert gut. Stellen Sie sich vor, eine neue Version von A kommt
Wenn ich nur die neue kompilierte Klasse A nehme und sie zusammen mit der zuvor kompilierten Klasse Main ablege, wird beim Versuch, die Methode aufzurufen, eine Ausnahme angezeigt
Wenn ich Main neu kompiliere, ist dies behoben und alles funktioniert wieder.
quelle
Ihr Programm (Quellcode) kann mit Modulen kompiliert werden, die die richtige API bereitstellen .
Ihr Programm (binär) kann auf Plattformen ausgeführt werden, die eine ordnungsgemäße ABI bereitstellen .
Die API beschränkt Typdefinitionen, Funktionsdefinitionen, Makros und manchmal globale Variablen, die eine Bibliothek verfügbar machen sollte.
ABI schränkt ein, was eine "Plattform" für die Ausführung Ihres Programms bereitstellen soll. Ich betrachte es gerne in 3 Ebenen:
Prozessorebene - der Befehlssatz, die Aufrufkonvention
Kernel-Ebene - die Systemaufrufkonvention, die spezielle Dateipfadkonvention (z. B.
/proc
und/sys
Dateien unter Linux) usw.Betriebssystemebene - das Objektformat, die Laufzeitbibliotheken usw.
Stellen Sie sich einen Cross-Compiler mit dem Namen vor
arm-linux-gnueabi-gcc
. "arm" gibt die Prozessorarchitektur an, "linux" gibt den Kernel an, "gnu" gibt an, dass seine Zielprogramme die libc von GNU als Laufzeitbibliothek verwenden, anders alsarm-linux-androideabi-gcc
die libc-Implementierung von Android.quelle
API
-Application Programming Interface
ist eine Schnittstelle zur Kompilierungszeit , die vom Entwickler verwendet werden kann , um nicht projektbezogene Funktionen wie Bibliothek, Betriebssystem und Kernaufrufe im Quellcode zu verwendenABI
[Info] -Application Binary Interface
ist eine Laufzeitschnittstelle , die von einem Programm während der Ausführung für die Kommunikation zwischen Komponenten im Maschinencode verwendet wirdquelle