Tags: #API #ABI
An API is a compile time interface (e.g. using non-project functionality provided by an external library). Where as an ABI is a runtime interface (e.g. an interface used by a program during execution, where the program is internally communicating with machine code).
An ABI is just an API for two machines, expressed more strictly and at a lower level than an API would be — thus Application Binary Interface vs. Application Programing Interface.
It’s not true that every communication layer between (for example) an SDK and something else is necessarily going through an ABI.
The distinction is that ABI is only relevant to binary interactions (e.g. an SDK communicating with a separate binary program; that linking process occurs at runtime, through an ABI) rather than just interactions in a general sense (e.g. an SDK communicating with an external REST API).
An ABI incompatible change is if I change a method A#m()
from taking a String
as an argument to String...
argument.
This is not ABI compatible because you have to recompile any code that is calling that function, but it is API compatible as you can resolve the issue by recompiling the caller without any code changes in the caller.
Find more examples here: https://stackoverflow.com/questions/3784389/difference-between-api-and-abi
We had a rust crate foo
that depended on another crate bar
(i.e. foo
would interact with bar
) and so both had to be available on the user’s system.
A user would write their own rust program that consumed foo
. As part of setting up their environment we’d ensure that bar
got installed (as it was a required for foo
to work), but the user didn’t need to know about bar
(and for the most part they didn’t know about it). They only knew that foo
provided an API they wanted to use, and so the fact that foo
called bar
internally didn’t matter to the user (they just had to make sure bar
existed on their system).
Remember that the user’s program, and the foo
and bar
dependencies are all written in rust code, but ultimately for them to be used together the user has to compile their program (and the dependencies) to machine code.
So imagine we have foo
at version 1, and bar
at version 1. Both work fine together.
Now a change to bar
is released as version 2, which is incompatible with foo
version 1.
When the user installs foo
and bar
, they get foo
version 1 and bar
version 2. This means their rust program breaks because the interactions between the foo
crate and bar
are broken.
Subsequently the user would need to install an updated version of foo
which was compatible with bar
. This meant when releasing changes to bar
we had to ensure that our environment setup scripts would ensure that the correct version of foo
would be installed alongside the appropriate version of bar
. The user still knew nothing about this, as they only cared about foo
.