|
Packit |
1470ea |
|
|
Packit |
1470ea |
xmlns:its="http://www.w3.org/2005/11/its"
|
|
Packit |
1470ea |
type="topic"
|
|
Packit |
1470ea |
id="api-stability">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<link type="guide" xref="index#maintainer-guidelines"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<credit type="author copyright">
|
|
Packit |
1470ea |
<name>Philip Withnall</name>
|
|
Packit |
1470ea |
<email its:translate="no">philip.withnall@collabora.co.uk</email>
|
|
Packit |
1470ea |
<years>2015</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<include href="cc-by-sa-3-0.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>Backwards compatibility in APIs</desc>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>API stability</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
<title>Summary</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Define API stability guarantees for your project.
|
|
Packit |
1470ea |
(<link xref="#stability"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Ensure version numbers are changed as appropriate when API changes.
|
|
Packit |
1470ea |
(<link xref="#versioning"/>)
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="api-and-abi">
|
|
Packit |
1470ea |
<title>API and ABI</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
At a high level, an API – Application Programming Interface – is
|
|
Packit |
1470ea |
the boundary between two components when developing against them. It is
|
|
Packit |
1470ea |
closely related to an ABI – Application Binary Interface – which
|
|
Packit |
1470ea |
is the boundary at runtime. It defines the possible ways in which other
|
|
Packit |
1470ea |
components can interact with a component. More concretely, this normally
|
|
Packit |
1470ea |
means the C headers of a library form its API, and compiled library
|
|
Packit |
1470ea |
symbols its ABI. The difference between an API and ABI is given by
|
|
Packit |
1470ea |
compilation of the code: there are certain things in a C header, such as
|
|
Packit |
1470ea |
#define s, which can cause a library’s API to change without
|
|
Packit |
1470ea |
changing its ABI. But these differences are mostly academic, and for all
|
|
Packit |
1470ea |
practical purposes, API and ABI can be treated interchangeably.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Examples of API-incompatible changes to a C function would be to add a
|
|
Packit |
1470ea |
new parameter, change the function’s return type, or remove a parameter.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
However, many other parts of a project can form an API. If a daemon
|
|
Packit |
1470ea |
exposes itself on D-Bus, the interfaces exported there form an API.
|
|
Packit |
1470ea |
Similarly, if a C API is exposed in higher level languages by use of
|
|
Packit |
1470ea |
GIR, the GIR file forms another API — if it changes, any higher level
|
|
Packit |
1470ea |
code using it must also change.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Other examples of more unusual APIs are configuration file locations and
|
|
Packit |
1470ea |
formats, and GSettings schemas. Any changes to these could require code
|
|
Packit |
1470ea |
using your library to change.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="stability">
|
|
Packit |
1470ea |
<title>Stability</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
API stability refers to some level of guarantee from a project that its
|
|
Packit |
1470ea |
API will only change in defined ways in the future, or will not change at
|
|
Packit |
1470ea |
all. Generally, an API is considered ‘stable’ if it commits to
|
|
Packit |
1470ea |
backwards-compatibility (defined below); but APIs could also commit to
|
|
Packit |
1470ea |
being unstable or even forwards-compatible. The purpose of API stability
|
|
Packit |
1470ea |
guarantees is to allow people to use your project from their own code
|
|
Packit |
1470ea |
without worrying about constantly updating their code to keep up with
|
|
Packit |
1470ea |
API changes. Typical API stability guarantees mean that code which is
|
|
Packit |
1470ea |
compiled against one version of a library will run without problems
|
|
Packit |
1470ea |
against all future versions of that library with the same major version
|
|
Packit |
1470ea |
number — or similarly that code which runs against a daemon will
|
|
Packit |
1470ea |
continue to run against all future versions of that daemon with the same
|
|
Packit |
1470ea |
major version number.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
It is possible to apply different levels of API stability to components
|
|
Packit |
1470ea |
within a project. For example, the core functions in a library could be
|
|
Packit |
1470ea |
stable, and hence their API left unchanged in future; while the newer,
|
|
Packit |
1470ea |
less core functions could be left unstable and allowed to change wildly
|
|
Packit |
1470ea |
until the right design is found, at which point they could be marked as
|
|
Packit |
1470ea |
stable.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Several types of stability commonly considered:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<terms>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>Unstable</title>
|
|
Packit |
1470ea |
The API could change or be removed in future.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>Backwards compatible</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Only changes which permit code compiled against the unmodified API
|
|
Packit |
1470ea |
to continue running against the modified API are allowed (for
|
|
Packit |
1470ea |
example, functions cannot be removed).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>Forwards compatible</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Only changes which permit code compiled against the modified API to
|
|
Packit |
1470ea |
run against the unmodified API are allowed (for example, functions
|
|
Packit |
1470ea |
cannot be added).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>Totally stable</title>
|
|
Packit |
1470ea |
No changes are allowed to the API, only to the implementation.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</terms>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Typically, projects commit to backwards-compatibility when they say an
|
|
Packit |
1470ea |
API is ‘stable’. Very few projects commit to total stability because it
|
|
Packit |
1470ea |
would prevent almost all further development of the project.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="versioning">
|
|
Packit |
1470ea |
<title>Versioning</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
API stability guarantees are strongly linked to project versioning; both
|
|
Packit |
1470ea |
package versioning and libtool versioning. Libtool versioning exists
|
|
Packit |
1470ea |
entirely for the purpose of tracking ABI stability, and is explained in
|
|
Packit |
1470ea |
detail on the
|
|
Packit |
1470ea |
<link href="https://autotools.io/libtool/version.html">Autotools
|
|
Packit |
1470ea |
Mythbuster</link> or <link xref="versioning"/>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Package versioning (major.minor.micro) is strongly linked to API
|
|
Packit |
1470ea |
stability: typically, the major version number is incremented when
|
|
Packit |
1470ea |
backwards-incompatible changes are made (for example, when functions are
|
|
Packit |
1470ea |
renamed, parameters are changed, or functions are removed). The minor
|
|
Packit |
1470ea |
version number is incremented when forwards-incompatible changes are
|
|
Packit |
1470ea |
made (for example, when new public API is added). The micro version
|
|
Packit |
1470ea |
number is incremented when code changes are made without modifying API.
|
|
Packit |
1470ea |
See <link xref="versioning"/> for more information.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
API versioning is just as important for D-Bus APIs and GSettings schemas
|
|
Packit |
1470ea |
(if they are likely to change) as for C APIs. See the
|
|
Packit |
1470ea |
<link href="http://dbus.freedesktop.org/doc/dbus-api-design.html#api-versioning">documentation
|
|
Packit |
1470ea |
on D-Bus API versioning</link> for details.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
For GIR APIs, their stability typically follows the C API stability, as
|
|
Packit |
1470ea |
they are generated from the C API. One complexity is that their stability
|
|
Packit |
1470ea |
additionally depends on the version of gobject-introspection used in
|
|
Packit |
1470ea |
generating the GIR, but recent versions have not changed much so this is
|
|
Packit |
1470ea |
not a major concern.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="external-links">
|
|
Packit |
1470ea |
<title>External Links</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The topic of API stability is covered in the following articles:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<link href="http://en.wikipedia.org/wiki/Application_programming_interface">Wikipedia
|
|
Packit |
1470ea |
page on APIs</link>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<link href="http://en.wikipedia.org/wiki/Application_binary_interface">Wikipedia
|
|
Packit |
1470ea |
page on ABIs</link>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<link href="http://dbus.freedesktop.org/doc/dbus-api-design.html#api-versioning">D-Bus
|
|
Packit |
1470ea |
API versioning documentation</link>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</page>
|