Soy nuevo en la programación de sistemas Linux y me encontré con API y ABI mientras leía la programación del sistema Linux .
Definición de API:
Una API define las interfaces mediante las cuales una pieza de software se comunica con otra en el nivel fuente.
Definición de ABI:
Mientras que una API define una interfaz fuente, una ABI define la interfaz binaria de bajo nivel entre dos o más piezas de software en una arquitectura particular. Define cómo una aplicación interactúa consigo misma, cómo interactúa una aplicación con el núcleo y cómo interactúa una aplicación con las bibliotecas.
¿Cómo se puede comunicar un programa a nivel fuente? ¿Qué es un nivel fuente? ¿Está relacionado con el código fuente de todos modos? ¿O la fuente de la biblioteca se incluye en el programa principal?
La única diferencia que sé es que la API es utilizada principalmente por los programadores y ABI es utilizada principalmente por el compilador.
Respuestas:
La API es lo que usan los humanos. Escribimos el código fuente. Cuando escribimos un programa y queremos usar alguna función de biblioteca, escribimos código como:
y necesitábamos saber que hay un método
livenMyHills()
, que toma un parámetro entero largo. Entonces, como interfaz de programación, todo se expresa en código fuente. El compilador convierte esto en instrucciones ejecutables que se ajustan a la implementación de este lenguaje en este sistema operativo en particular. Y en este caso resultan en algunas operaciones de bajo nivel en una unidad de audio. Entonces, bits y bytes particulares se arrojan a chorros en algún hardware. Entonces, en tiempo de ejecución, hay muchas acciones de nivel binario que generalmente no vemos.fuente
API: interfaz del programa de aplicación
Este es el conjunto de tipos / variables / funciones públicas que expone de su aplicación / biblioteca.
En C / C ++, esto es lo que expone en los archivos de encabezado que envía con la aplicación.
ABI: interfaz binaria de aplicación
Así es como el compilador construye una aplicación.
Define cosas (pero no se limita a):
fuente
Principalmente encuentro estos términos en el sentido de un cambio incompatible con API, o un cambio incompatible con ABI.
Un cambio de API es esencialmente donde el código que se habría compilado con la versión anterior ya no funcionará. Esto puede suceder porque agregó un argumento a una función o cambió el nombre de algo accesible fuera de su código local. Cada vez que cambia un encabezado y lo obliga a cambiar algo en un archivo .c / .cpp, ha realizado un cambio de API.
Un cambio ABI es donde el código que ya se ha compilado contra la versión 1 ya no funcionará con la versión 2 de una base de código (generalmente una biblioteca). En general, es más difícil realizar un seguimiento que los cambios incompatibles con la API, ya que algo tan simple como agregar un método virtual a una clase puede ser incompatible con ABI.
He encontrado dos recursos extremadamente útiles para descubrir qué es la compatibilidad ABI y cómo preservarla:
fuente
Esta es mi explicación laica:
include
archivos. Proporcionan interfaces de programación.fuente
Ejemplo de API mínima ejecutable de biblioteca compartida de Linux vs ABI
Esta respuesta se ha extraído de mi otra respuesta: ¿Qué es una interfaz binaria de aplicación (ABI)? pero sentí que también responde directamente a esta, y que las preguntas no son duplicados.
En el contexto de las bibliotecas compartidas, la implicación más importante de "tener un ABI estable" es que no necesita volver a compilar sus programas después de que la biblioteca cambie.
Como veremos en el ejemplo a continuación, es posible modificar la ABI, interrumpiendo los programas, aunque la API no haya cambiado.
C Principal
mylib.c
mylib.h
Compila y funciona bien con:
Ahora, supongamos que para v2 de la biblioteca, queremos agregar un nuevo campo al
mylib_mystrict
llamadonew_field
.Si agregamos el campo antes
old_field
como en:y reconstruyó la biblioteca pero no
main.out
, ¡entonces la afirmación falla!Esto se debe a que la línea:
había generado un ensamblado que intenta acceder al primero
int
de la estructura, que ahora es ennew_field
lugar del esperadoold_field
.Por lo tanto, este cambio rompió el ABI.
Sin embargo, si agregamos
new_field
despuésold_field
:entonces el antiguo ensamblado generado aún accede al primero
int
de la estructura, y el programa aún funciona, porque mantuvimos el ABI estable.Aquí hay una versión completamente automatizada de este ejemplo en GitHub .
Otra forma de mantener esta ABI estable habría sido tratarla
mylib_mystruct
como una estructura opaca , y solo acceder a sus campos a través de métodos auxiliares. Esto hace que sea más fácil mantener estable la ABI, pero incurriría en una sobrecarga de rendimiento ya que haríamos más llamadas a funciones.API vs ABI
En el ejemplo anterior, es interesante notar que agregar el
new_field
anteriorold_field
solo rompió la ABI, pero no la API.Lo que esto significa es que si hubiéramos compilado nuestro
main.c
programa contra la biblioteca, habría funcionado de todos modos.Sin embargo, también habríamos roto la API si hubiéramos cambiado, por ejemplo, la firma de la función:
ya que en ese caso,
main.c
dejaría de compilarse por completo.API semántica vs API de programación vs ABI
También podemos clasificar los cambios de API en un tercer tipo: cambios semánticos.
Por ejemplo, si hubiéramos modificado
a:
entonces esto no habría roto ni API ni ABI, ¡pero
main.c
aún así se rompería!Esto se debe a que cambiamos la "descripción humana" de lo que se supone que debe hacer la función en lugar de un aspecto programáticamente notable.
Acabo de tener la idea filosófica de que la verificación formal del software en cierto sentido mueve más de la "API semántica" a una "API verificable programáticamente".
API semántica vs API de programación
También podemos clasificar los cambios de API en un tercer tipo: cambios semánticos.
La API semántica, por lo general, es una descripción en lenguaje natural de lo que se supone que debe hacer la API, generalmente incluida en la documentación de la API.
Por lo tanto, es posible romper la API semántica sin romper la compilación del programa.
Por ejemplo, si hubiéramos modificado
a:
entonces esto no habría roto ni la API de programación ni la ABI, pero
main.c
la API semántica se rompería.Hay dos formas de verificar mediante programación la API del contrato:
Probado en Ubuntu 18.10, GCC 8.2.0.
fuente
( A plicación B de ciertas piezas I nterface) una especificación para una plataforma de hardware específica combinada con el sistema operativo. Es un paso más allá de la API ( A plicación P rograma I nterface), que define las llamadas desde la aplicación al sistema operativo. El ABI define la API más el lenguaje de máquina para una familia de CPU en particular. Una API no garantiza la compatibilidad del tiempo de ejecución, pero una ABI sí, porque define el lenguaje de la máquina, o el formato del tiempo de ejecución.
Cortesía
fuente
Permítanme dar un ejemplo específico de cómo ABI y API difieren en Java.
Un cambio incompatible con ABI es si cambio un método A # m () de tomar
String
un argumento aString...
argumento. Esto no es compatible con ABI porque debe volver a compilar el código que lo está llamando, pero es compatible con API, ya que puede resolverlo volviendo a compilar sin ningún cambio de código en la persona que llama.Aquí está el ejemplo explicado. Tengo mi biblioteca Java con clase A
Y tengo una clase que usa esta biblioteca
Ahora, el autor de la biblioteca compiló su clase A, compilé mi clase Main y todo funciona bien. Imagina que viene una nueva versión de A
Si solo tomo la nueva clase A compilada y la dejo caer junto con la clase principal compilada anteriormente, obtengo una excepción al intentar invocar el método
Si recompilo Main, esto se arregla y todo vuelve a funcionar.
fuente
Su programa (código fuente) puede compilarse con módulos que proporcionan la API adecuada .
Su programa (binario) puede ejecutarse en plataformas que proporcionan una ABI adecuada .
La API restringe las definiciones de tipo, definiciones de función, macros, a veces variables globales que una biblioteca debe exponer.
ABI restringe lo que debe proporcionar una "plataforma" para que se ejecute su programa. Me gusta considerarlo en 3 niveles:
nivel de procesador: el conjunto de instrucciones, la convención de llamada
nivel de kernel: la convención de llamada del sistema, la convención especial de ruta de archivo (por ejemplo, los archivos
/proc
y/sys
en Linux), etc.Nivel del sistema operativo: el formato del objeto, las bibliotecas de tiempo de ejecución, etc.
Considere un compilador cruzado llamado
arm-linux-gnueabi-gcc
. "arm" indica la arquitectura del procesador, "linux" indica el kernel, "gnu" indica que sus programas de destino usan la libc de GNU como biblioteca de tiempo de ejecución, diferente de laarm-linux-androideabi-gcc
que usa la implementación de la libc de Android.fuente
API
-Application Programming Interface
es una interfaz de tiempo de compilación que el desarrollador puede usar para usar funciones que no son del proyecto, como la biblioteca, el sistema operativo, las llamadas principales en el código fuenteABI
[Acerca de] :Application Binary Interface
es unainterfaz de tiempo de ejecución que utiliza un programa durante la ejecución para la comunicación entre componentes en el código de máquinafuente