-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Gabriel Schulhof
committed
Oct 2, 2018
1 parent
97f1e94
commit f9e2295
Showing
1 changed file
with
107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# ABI Stability | ||
|
||
## Introduction | ||
An Application Binary Interface (ABI) is the compiled version of an Application | ||
Programming Interface (API). That is, the headers files describing the classes, | ||
functions, data structures, enumerations, and constants used to enable an | ||
application to perform a desired task correspond by way of compilation to a set | ||
of addresses and expected parameter values and memory structure sizes and | ||
layouts with which the provider of the ABI was compiled. | ||
|
||
The application using the ABI must be compiled such that the available | ||
addresses, expected parameter values, and memory structure sizes and layouts | ||
agree with those with which the ABI provider was compiled. This is usually | ||
accomplished by compiling against the headers provided by the ABI provider. | ||
|
||
Since the ABI provider and the ABI user may be compiled at different times with | ||
different versions of the compiler, a portion of the responsibility for | ||
ensuring ABI compatibility lies with the compiler. Different versions of the | ||
compiler, perhaps provided by different vendors, must all produce the same ABI | ||
from a header file with a certain content, and must produce code for the | ||
application using the ABI that accesses the API described in a given header | ||
according to the conventions of the ABI resulting from the description in the | ||
header. Modern compilers have a fairly good track record of not breaking the | ||
ABI compatibility of the applications they compile. | ||
|
||
The remaining responsibility for ensuring ABI compatibility lies with the team | ||
maintaining the header files which provide the API that results, upon | ||
compilation, in the ABI that is to remain stable. Changes to the header files | ||
can be made, but the nature of the changes has to be closely tracked to ensure | ||
that, upon compilation, the ABI does not change in a way that will render | ||
existing users of the ABI incompatible with the new version. | ||
|
||
## ABI Stability in Node.js | ||
Node.js provides header files maintained by several independent teams. For | ||
example, header files such as `node.h` and `node_buffer.h` are maintained by | ||
the Node.js team. `v8.h` is maintained by the V8 team, which, although in close | ||
co-operation with the Node.js team, is independent, and with its own schedule | ||
and priorities. Thus, the Node.js team has only partial control over the | ||
changes that are introduced in the headers the project provides. As a result, | ||
the Node.js project has adopted [semantic versioning](https://semver.org/). | ||
This ensures that the APIs provided by the project will result in a stable ABI | ||
for all minor and patch versions of Node.js released within one major version. | ||
In practice, this means that a Node.js native addon compiled against a given | ||
major version of Node.js will load successfully when loaded by any Node.js | ||
minor or patch version within the major version against which it was compiled. | ||
|
||
## N-API | ||
Demand has arisen for equipping Node.js with an API that results in an ABI that | ||
remains stable across multiple Node.js versions. The motivation for creating | ||
such an API is as follows: | ||
* The JavaScript language has remained compatible with itself since its very | ||
early days, whereas the ABI of the engine executing the JavaScript changes with | ||
every major version of Node.js. This means that applications consisting of | ||
Node.js packages written entirely in JavaScript need not be recompiled, | ||
reinstalled, or redeployed as a new major version of Node.js is dropped into | ||
the production environment in which such applications run. In contrast, if an | ||
application depends on a package that contains a native addon, the application | ||
has to be recompiled, reinstalled, and redeployed whenever a new major version | ||
of Node.js is introduced into the production environment. This disparity | ||
between Node.js packages containing native addons and those that are written | ||
entirely in JavaScript has added to the maintenance burden of production | ||
systems which rely on native addons. | ||
|
||
* Other projects have started to produce JavaScript interfaces that are | ||
essentially alternative implementations of Node.js. Since these projects are | ||
usually built on a different JavaScript engine than V8, their native addons | ||
necessarily take on a different structure and use a different API. Nevertheless, | ||
using a single API for a native addon across different implementations of the | ||
Node.js JavaScript API would allow these projects to take advantage of the | ||
ecosystem of JavaScript packages that has accrued around Node.js. | ||
|
||
* Node.js may contain a different JavaScript engine in the future. This means | ||
that, externally, all Node.js interfaces would remain the same, but the V8 | ||
header file would be absent. Such a step would cause the disruption of the | ||
Node.js ecosystem in general, and that of the native addons in particular, if | ||
an API that is JavaScript engine agnostic is not first provided by Node.js and | ||
adopted by native addons. | ||
|
||
To these ends Node.js has introduced N-API in version 8.6.0 and marked it as a | ||
stable component of the project as of Node.js 8.12.0. The API is defined in the | ||
headers [`node_api.h`](https://github.com/nodejs/node/blob/master/src/node_api.h) | ||
and [`node_api_types.h`](https://github.com/nodejs/node/blob/master/src/node_api_types.h), | ||
and provides a forward-compatibility guarantee that crosses the Node.js major | ||
version boundary. The guarantee can be stated as follows: | ||
|
||
**A given version *n* of N-API will be available in the major version of | ||
Node.js in which it was published, and in all subsequent versions of Node.js, | ||
including subsequent major versions.** | ||
|
||
A native addon author can take advantage of the N-API forward compatibility | ||
guarantee by ensuring that the addon makes use only of APIs defined in | ||
`node_api.h` and data structures and constants defined in `node_api_types.h`. | ||
By doing so, the author facilitates adoption of their addon by indicating to | ||
production users that the maintenance burden for their application will increase | ||
no more by the addition of the native addon to their project than it would by | ||
the addition of a package written purely in JavaScript. | ||
|
||
N-API is versioned because new APIs are added from time to time. Unlike | ||
semantic versioning, N-API versioning is cumulative. That is, each version of | ||
N-API conveys the same meaning as a minor version in the semver system. | ||
Additionally, new N-APIs are added under an experimental flag. This means that, | ||
although care has been taken to ensure that the new API will not have to be | ||
modified in an ABI-incompatible way in the future, it has not yet been proven in | ||
production to be correct and useful as designed and, as such, may undergo | ||
ABI-incompatible changes before it is finally incorporated into a forthcoming | ||
version of N-API. That is, an experimental N-API is not covered by the forward | ||
compatibility guarantee. |