Version Numbers
I use Semantic Versioning 2.0 as a base for my version number schemes. My version numbers aren’t exactly Semver 2.0 compliant, but they’re similar, and they should be somewhat familiar to users of Semver 2.0. One big difference right off the bat is that I treat the version numbers of libraries and programs slightly differently.
To start off, all of my version numbers are based around the format
<major>.<minor>.<revision>
. This may have a few extra bits of metadata
appended to it as well, but only in certain circumstances (see below). Each
element always starts at 0
and is a non-negative integer with no upper limit.
When considering the version numbers for libraries:
- When
<major>
version is incremented by1
when the API (or ABI, where applicable) changes and breaks backwards compatibility. When<major>
is increased by1
, then<minor>
and<revision>
are reset to0
.- All releases within the same
<major>
version are intended to be API-compatible (and and ABI-compatible, where applicable). - A
<major>
version of0
is special - see below in the section “Pre-1.0 Versions”.
- All releases within the same
- The
<minor>
number is incremented by1
when backwards-compatible additions (within the same<major>
series) are made. - The
<revision>
is incremented by1
when a release only provides bug fixes or content changes.
Programs mostly follow the same pattern as libraries, except for the following:
- Since a program usually does not export an API (as it’s not usually used as a
library), then rather than API breakage, a best-judgment is used. Major
internal design of the program, a change in config format, protocol changes,
or the like constitute an increase of
<major>
by1
, with<minor>
and<revision>
reset to0
. - The same goes for
<minor>
, where changes that the user may benefit from, but (as an example) won’t require them to modify a config file, constitute a bumping of the<minor>
version. - The
<revision>
field is handled the same. - All of these are given slight leeway based on “gut feeling”.
Pre-1.0 Versions
I use versions in the format 0.x.y
to indicate software that is alpha/beta
quality, not widely field-tested, or generally still in heavy development. For
example, CL-RemiMarshal’s API is mostly stable as of October of 2025, but
because it only supports three formats right now, I don’t feel it’s quite ready
for 1.x.y
.
The rules for 0.x.y
versions are slightly different:
- The
<minor>
number is incremented by1
when API (or ABI) breakage occurs. - A version in the format
0.99.x
indicates “beta” or “almost ready for1.x.y
”. When this happens, the<revision>
is the only number that changes, and almost no changes to the API/ABI are expected to be made (though it’s still possible).
Additional Metadata
Sometimes I may tack on extra metadata. This is done in one of three forms:
- The
-<build>
addition (e.g.<major>.<minor>.<revision>-<build>
,2.5.6-2
) is used to indicate rebuilds, and means the library/program itself didn’t change, but the build did. This may happen if, as an example, I forget to include a file in a tarball. - The
-rc<num>
addition is used to indicate release candidates. I usually only use these for programs, not libraries. This indicates a code freeze (so no new features except maybe extremely trivial ones), and that the program is mostly ready for production use, but may still have a few last-minute bugs. This grows out of my preference to not to do the whole “move quickly and break things” or “rolling release” approaches, and instead favor stability. - Other tags such as
-featuretest
are just extra descriptive tags. - I only use one extra tag/piece of metadata at a time.
CPU Architectures
Sometimes I may include CPU architectures in my version numbers for binary releases of programs. These follow Slackware’s package naming format:
<version>-<cpu>-<build>
The <cpu>
field here is one such as x86-64
or aarch64
.