Skip to content
Snippets Groups Projects
versioning.md 11.7 KiB
Newer Older
+++
date = "2019-11-15"
weight = 100

title = "Versioning"

aliases = [
    "/architecture/binary_package_versioning/",
    "/guidelines/versioning/",
    "/old-wiki/Guidelines/Versioning",
    "/old-wiki/Build_and_Integration_infrastructure_documentation"
]
+++

It is important to properly
[version](https://en.wikipedia.org/wiki/Software_versioning) software to enable
software changes and compatibility of components to be tracked, as well as to
aid with bug tracking and the application of updates. To achieve this, it is
important that we effectively version each source component, binary package and
The approach to versioning depends on the entity being versioned and in the
case of source code whether it is developed specifically for Apertis or an
existing project used by Apertis.

# Debian Versions and Revisions

The vast majority of the components from which the Apertis distribution is
derived are taken from Debian. A large percentage of the packages in Debian are
created from source code from other software projects. Each Debian package
retains the version set by its upstream (the project from which the source was
taken). Debian appends its own package revision to the end of the version.  The
revision is very important when working with software distributions as this
enables tracking of changes across security updates, backports, binary
rebuilds, etc.

As an example, imagine an upstream project producing an application called
`hello` releases version `1.0`, A Debian packager takes it and makes it’s first
release in Debian, following the standards the packager gives the package the
version `1.0-1`, the first Debian package release. After a while the packager
adds some improvements to the packaging, allowing it to cross build, but with
the package still based on the upstream `1.0` release. The package is then
released as `1.0-2`. In the meanwhile, the package is frozen and goes into
production, as a so called stable release. Now, the packager continues
development and does several Debian updates, creating up to `1.0-7`.  At this
point we’ve got `1.0-2` in a stable distribution and `1.0-7` in a development
distribution.  The convention is documented the
[Debian policy](https://www.debian.org/doc/debian-policy/#version). If we find
a security issue in stable we want to fix it, but want to keep current version,
how would that be named so that version-revision will not conflict with other
changes? What about if we want to backport the version in development, to build
against stable branch? What about us, as a downstream of the Debian package,
how should we version the package if we want to apply some changes on top of
Debian package?  The convention, when modifying the package for security
updates, backports and downstream modification, is to append to the end of the
existing Debian version number. As a result of this policy, packages in
Apertis bear the addition `coX`, where `X` is a incremented number, which
shows the number of modifications made to the package by Collabora for Apertis.
The `co0` suffix means that the only difference between the upstream package
from Debian and the package in Apertis is the metadata under `debian/apertis/`
and the changelog entry itself. This is to highlight the fact that this metadata
ends up in the generated source package, so this source package carries a
small delta against the corresponding Debian package.

Additionally, there are a number of symbols that are used to separate these
portions of the revision.  The symbol `~` is used to infer "less", and `+` for
"more". For example, `1.0-1+co1` is considered greater than `1.0-1`, but
`1.0-1~co1` is lower version than `1.0-1`. This ensures that we don’t end up
creating packages whose versioning collides with later upstream versioning and
allows us to control which package is preferred over another by the package
manager which ulitimately uses the version/revision string to decide which
package to install.

Further examples:

- `1.0-2deb9u1`:
  - Debian security update `1` for the Debian `9` distribution
  - Applied to the second revision of Debian’s packaging for the upstream `1.0`
    release.
- `1.0-2+b1`:
  - Binary rebuild of the second revision of Debian’s packaging for the
    upstream `1.0` release.
  - No changes to the source.
- `1.0-2co1`:
  - Modification `1` by Collabora
  - Applied to the second revision of Debian’s packaging for the upstream `1.0`
    release.
- `1.0-2ubuntu3co4foo5`:
  - Foo modification revision `5`
  - Using the Apertis modification revision `4`
  - Based on Ubuntu's modification revision `3`
  - Which was based on the second revision of Debian’s packaging for the
    upstream `1.0` release.
- `1.0-7~bpo9+1`:
  - First revision of a backport to Debian `9`
  - Which is based on revision `7` of Debian’s packaging for the upstream `1.0`
    release.
  - The `~` ensures that if the installation is upgraded to Debian 10, which
    uses `1.0-7`, the backport is considered less than this and the "newer"
    package (i.e. the one from Debian 10) gets installed.

If in doubt, we can check on the command line:

    $ dpkg --compare-versions 1.0-1+co1 gt 1.0-1 && echo YES
    $ dpkg --compare-versions 1.0-1~co1 lt 1.0-1 && echo YES

Here `gt` stands for “greater than”, while `lt` means “less than”.

When making modifications to existing packages, the above rules should be used
to determine a suitable version.

# Apertis Source Code Versioning

For packages written specifically for Apertis the package is maintained as a
[native package](https://www.debian.org/doc/manuals/maint-guide/advanced.en.html#native-dh-make).
When handling such packages we directly modify the version number rather than
appending a revision. Source Code versioning differs for libraries and
applications.  Applications just require a package version, libraries need a
libtool version specified in addition to their package version.

## Libtool versioning

Libraries have two version numbers: a libtool version which tracks ABI
backwards compatibility, and a [package version](#package-versioning) which
tracks feature changes.  These are normally incremented in synchronisation, but
should be kept separate because ABI backwards compatibility is not necessarily
related to feature changes or bug fixes. Furthermore, the two version numbers
have different semantics, and cannot be automatically generated from each
other.

A good overview of libtool versioning, and the differences from package
versioning, is given in the
[Autotools Mythbuster](https://autotools.io/libtool/version.html).

To update the libtool version, follow the algorithm given in the comments
below. This is a typical `configure.ac` snippet for setting up libtool
versioning:

```
# Before making a release, the LT_VERSION string should be modified. The
# string is of the form c:r:a. Follow these instructions sequentially:
#   1. If the library source code has changed at all since the last update, then
#      increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
#   2. If any interfaces have been added, removed, or changed since the last
#      update, increment current, and set revision to 0.
#   3. If any interfaces have been added since the last public release, then
#      increment age.
#   4. If any interfaces have been removed or changed since the last public
#      release, then set age to 0.
AC_SUBST([LT_VERSION],[0:0:0])
```

The following snippet can be used in a `Makefile.am` to pass that version info
to libtool:

```
my_library_la_LDFLAGS = -version-info $(LT_VERSION)
```

If a package contains more than one library, it should usually have a separate
libtool version for each one.

The standard process for making a release of a module increments the libtool
version (if the module is a library) and the package version immediately before
release. This is called pre-release incrementing.

The use of pre-release increment for libtool versions means that they are only
incremented once for all ABI changes in a release. Some projects use
post-release increment for package versions to ensure that the package version
number is not outdated (i.e. still equal to the previous release) during the
development cycle; we achieve this by altering the version number automatically
in
[the build-snapshot script](https://gitlab.apertis.org/pkg/target/apertis-customizations/blob/apertis/v2020dev0/development/build-snapshot)
instead.

## Package Versioning

The package version number for a library is that passed to `AC_INIT()`, and the
one which is typically known as the project’s version number.  For example, the
Debian package for a library will use the library’s package version.

Versions of packages developed for Apertis have the form `x.y.z` and are
updated according to the following rules:

- `x` starts at 0, and increments when there is a major compatibility break.
  Libraries with different major versions should usually be
  [parallel-installable]( {{< ref "module_setup.md#parallel-installability" >}} ).
- `y` is the Apertis branch year and month as a single 4-digit number, for
  instance `1706`.
- `z` is 0 for the first release to each branch, and goes up for each release
  (whether it is a feature release or bugfix-only).

# Understanding Binary Build Suffixes

For every binary release (*Developer, Preview, Product*), we add a build suffix
string to the packages, which relates to the release name of Apertis.  The
build suffix gets added to every built .deb package. Having a build suffix
helps determine which Apertis release the .deb package was built for.

The suffix string is constructed of: `b<Release_Name>b<B_CNT>`.
- The initial `b` is for backward compatibility ensuring the new suffix string
  can work well together with older release packages.
- `<Release_Name>` refers to the Apertis release's name.
- `b<B_CNT>` refers to being a binary build along with the build count.

The build count is incremented each time the package is built, regardless of
whether the source has changed.

For example, for the Apertis Developer Release `v2020dev0` we add the string
`bv2020dev0b1` to the project configuration on OBS when the package is first
built.  Similarly, for an Apertis Product Release of `v2019.0` we add the
string `bv2019.0b2` to the project configuration on OBS when it is built for
the second time with no source change.

# Product Point Release Versioning

A product point release rolls the packages previously released in the update and
security repositories into the stable branch. It is required to ensure that the
packages in the new point release have a higher version than the binary package
in the updates or security repositories, it is thus necessary to include the point
releases numbering (e.g. `v2020.1`, `v2020.2`) in the build suffix.

For example, during the initial release of the v2020 release, the build suffix
was `bv2020.0b<B_CNT>`. The same build suffix is inherited by the updates and
security sub-repositories during this time period. Before doing a new point
release *v2020.1*, the build suffix of the main repositories
(`apertis:v2020:target`, `apertis:v2020:development`, `apertis:v2020:sdk`,
`apertis:v2020:hmi` etc) is set to `vb2020.1b<B_CNT>`.

Once this step has been taken, changes previously commited to Apertis update
and security branches (such as `apertis/v2020-updates` and
`apertis/v2020-security`) are merged into the main release branch
(`apertis/v2020`), thus triggering a build and generation of a package with the
required point release suffix. This ensures that the packages synced from the
updates and security sub-repositories have higher versions than packages from
the updates and security sub-repositories. Once the merge has been completed,
the equivalent packages in the update and security branches are purged to allow
these branches to be used for following updates and security fixes to the new
point release.