Skip to content

Change version numbering to accomodate betas, release candidates, point-releases etc.? #5217

@smcv

Description

@smcv

Some of the recent SDL releases have had regressions that needed to be fixed shortly after release: 2.0.16 had #4630 and a HIDAPI regression, and 2.0.18 had various regressions that led to 2.0.20 being effectively just a bugfix release for 2.0.18.

However, because there's only one branch in git, each new release also picks up new feature work and technical-debt cleanup, which needs some testing before it's ready to go in a release. It also has a risk of causing new regressions, and the cycle continues.

Downstream distributions like the Steam Runtime, Linux distributions, and games that bundle a copy of SDL can work around this by cherry-picking bugfix patches into their copy (and I regularly do this in Debian and the Steam Runtime), but then mechanisms that compare more than one version and try to use the newest are unable to tell which version is newer/better/more-bug-fixed than the other.

The unofficial prereleases that happen before a stable release, such as https://discourse.libsdl.org/t/sdl-2-0-20-prerelease/34342/7, also identify themselves as being the same version as the actual stable release, which seems likely to lead to confusion; and it isn't immediately obvious which git commit they were built from, because there's no tag like prerelease-2.0.20pre1 that corresponds to them.

I think it could be useful to consider changing the version-numbering model for SDL and adjacent libraries (SDL_image, etc.) to avoid those problems:

  • Major version: continue to use for incompatible changes. If there is a new version that breaks backwards compatibility, it should be SDL 3, similar to how GTK and Qt major versions work (since GTK 2 and at least Qt 3, maybe earlier). Ideally this doesn't happen very often. If the versioning model is that incompatible changes will always result in a major version bump, then SDL 3 could also simplify the SONAME from libSDL2-2.0.so.0 to libSDL3.so.0.

  • Minor version: reset to 0 for a new major version, or increment for new "feature" releases from main - the equivalent of 2.0.16 and 2.0.18 for example. These add new features, new API, or potentially destabilizing changes like the recent event-loop improvements.

  • Micro (patch) version: reset to 0 for a new minor version, or increment for new bug-fix releases. For example, if SDL 2.18.0 has regressions or other particularly bad bugs, then 2.18.1 could fix those regressions but not add any new features, new API, or potentially destabilizing changes (which would wait for 2.19 or 2.20 instead). Releases with micro version > 0 should come from a branch that branches off from main at the release tag, for example 2.18.1 might come from a 2.18.x branch. Branches can be maintained for as short or as long a time as you want them to be: it would be good to have a clear policy on which ones get security support, but there's no obligation to support anything older than the latest feature release.

  • Shared library version info: currently SDL uses libtool -version-info (current, revision, age) under Autotools, or calculates an equivalent version involving SDL_INTERFACE_AGE and SDL_BINARY_AGE under CMake. If the version number looked like I describe above, then I think it might perhaps make sense to switch to a setup where for example SDL 2.0.22 might be followed by 2.24.0, using libtool -version-number 0.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION} (making sure to choose the initial version number so that all versions sort in the intended order), and similarly the CMake build system uses SOVERSION 0 VERSION 0.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}. That would make sure that both feature and bug-fix versions sort correctly even if releases are made on more than one branch in parallel, and reduce the book-keeping involved.

GTK, Qt, Flatpak and dbus are some examples of projects with approximately this versioning model.

For betas and release candidates, there are a few conventions in common use:

  • GTK, Flatpak and dbus use the "odd/even" model, where an even minor version like Flatpak 1.10.x is a stable release, and an odd minor version like Flatpak 1.11.x is an alpha, beta or release candidate along the path to the next stable release branch 1.12.x. This relies on downstream distributors knowing which branches they should and shouldn't package (most distributors will only want the stable branches), but Github's ability to mark releases as a prerelease helps: for example in https://github.com/flatpak/flatpak/releases it's hopefully fairly obvious that 1.11.x were not intended for wide use.

  • Lots of projects use a non-numeric suffix for betas, for example many recent GNOME apps use versioning like 41.alpha1, 41.beta1, 41.rc1, and then 41.0 for the final release. Python does something similar. The disadvantage of this is that it can't easily be represented in SDL_version or SDL_VERSIONNUM.

  • X11 projects like Xorg use a version number like 1.19.901 to represent 1.20 release candidate 1, and so on. This is like the rc1 notation, but would be representable in SDL_version.

It would also be nice if there was a representation for intermediate versions in git. At the moment, SDL seems to have the same convention used in dbus, where an odd micro version indicates a git snapshot, and all formal prereleases or releases have an even micro version. This works by releasing 2.0.20, immediately bumping the version number to 2.0.21, and then bumping the version number again to 2.0.22 before the next release, so that if you see a SDL binary that claims to be version 2.0.21, you know that it's a snapshot from somewhere between 2.0.20 and 2.0.22. Keeping that convention, and documenting it, seems like a good idea.

One potential problem with these suggestions is that SDL_VERSIONNUM assumes that the minor version is <= 9 and the micro version is <= 99. That could perhaps be avoided by redefining SDL_VERSIONNUM to use a larger "width" for those fields: because SDL_VERSIONNUM is a compile-time thing rather than a runtime thing, hopefully that won't break anyone?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions