SDL_image: build: Use minor version number for feature releases

From 3682d066f2c51582d48e1c89da201ddb055cb200 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Thu, 5 May 2022 13:19:20 +0100
Subject: [PATCH] build: Use minor version number for feature releases

Similar to what has been done in SDL itself, this allows micro versions
with an odd minor version to be used as prereleases for a stable
release. It also allows micro versions with an even minor version to
be used to fix regressions in their corresponding .0 release
if that becomes necessary.

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 .github/workflows/main.yml                |   4 +
 CMakeLists.txt                            |  42 +++++++
 IMG.c                                     |  22 ++++
 Makefile.os2                              |   5 +-
 README-versions.md                        |  59 +++++++++
 SDL_image.h                               |  16 ++-
 VisualC/Version.rc                        |   8 +-
 Xcode/Info-Framework.plist                |   4 +-
 Xcode/SDL_image.xcodeproj/project.pbxproj |   4 +-
 configure.ac                              |  40 +++---
 release_checklist.md                      |  93 ++++++++++++++
 test-versioning.sh                        | 143 ++++++++++++++++++++++
 12 files changed, 412 insertions(+), 28 deletions(-)
 create mode 100644 README-versions.md
 create mode 100644 release_checklist.md
 create mode 100755 test-versioning.sh

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 9e3fcc7..f03ff0d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -59,6 +59,10 @@ jobs:
           zlib1g-dev \
           ${NULL+}
     - uses: actions/checkout@v2
+    - name: Check that versioning is consistent
+      # We only need to run this once: arbitrarily use the Linux/CMake build
+      if: "runner.os == 'Linux' && matrix.platform.cmake"
+      run: ./test-versioning.sh
 
     - name: Configure CMake
       if: "matrix.platform.cmake"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5829b4f..23d3689 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,12 @@
 cmake_minimum_required(VERSION 3.3.2)
 project(SDL_image C)
 
+# See docs/release_checklist.md
+set(MAJOR_VERSION 2)
+set(MINOR_VERSION 5)
+set(MICRO_VERSION 0)
+set(FULL_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}")
+
 # FIXME: CMAKE SUPPORT IN SDL2_image IS VERY INCOMPLETE YET !!!
 #
 # FIXME: make it able build against system codec libraries, too.
@@ -25,6 +31,42 @@ if (NOT TARGET SDL2::SDL2)
 		IMPORTED_LOCATION "${SDL2_LIBRARY}")
 endif()
 
+# Calculate a libtool-like version number
+math(EXPR BINARY_AGE "${MINOR_VERSION} * 100 + ${MICRO_VERSION}")
+if(MINOR_VERSION MATCHES "[02468]$")
+    # Stable branch, 2.6.1 -> libSDL2_image-2.0.so.0.600.1
+    set(INTERFACE_AGE ${MICRO_VERSION})
+else()
+    # Development branch, 2.5.1 -> libSDL2_image-2.0.so.0.501.0
+    set(INTERFACE_AGE 0)
+endif()
+
+# Increment this if there is an incompatible change - but if that happens,
+# we should rename the library from SDL2 to SDL3, at which point this would
+# reset to 0 anyway.
+set(LT_MAJOR "0")
+
+math(EXPR LT_AGE "${BINARY_AGE} - ${INTERFACE_AGE}")
+math(EXPR LT_CURRENT "${LT_MAJOR} + ${LT_AGE}")
+set(LT_REVISION "${INTERFACE_AGE}")
+# For historical reasons, the library name redundantly includes the major
+# version twice: libSDL2_image-2.0.so.0.
+# TODO: in SDL 3, set the OUTPUT_NAME to plain SDL3_image, which will simplify
+# it to libSDL3_image.so.0
+set(LT_RELEASE "2.0")
+set(LT_VERSION "${LT_MAJOR}.${LT_AGE}.${LT_REVISION}")
+
+# The following should match the versions in the Xcode project file.
+# Each version is 1 higher than you might expect, for compatibility
+# with libtool: macOS ABI versioning is 1-based, unlike other platforms
+# which are normally 0-based.
+math(EXPR DYLIB_CURRENT_VERSION_MAJOR "${LT_MAJOR} + ${LT_AGE} + 1")
+math(EXPR DYLIB_CURRENT_VERSION_MINOR "${LT_REVISION}")
+math(EXPR DYLIB_COMPAT_VERSION_MAJOR "${LT_MAJOR} + 1")
+set(DYLIB_CURRENT_VERSION "${DYLIB_CURRENT_VERSION_MAJOR}.${DYLIB_CURRENT_VERSION_MINOR}.0")
+# For historical reasons this is 3.0.0 rather than the expected 1.0.0
+set(DYLIB_COMPATIBILITY_VERSION "3.0.0")
+
 option(SUPPORT_JPG "Support loading JPEG images" ON)
 option(SUPPORT_PNG "Support loading PNG images" ON)
 option(SUPPORT_WEBP "Support loading WEBP images" OFF)
diff --git a/IMG.c b/IMG.c
index 8826eb8..456c6ef 100644
--- a/IMG.c
+++ b/IMG.c
@@ -27,6 +27,28 @@
 #include <emscripten/emscripten.h>
 #endif
 
+#if defined(SDL_BUILD_MAJOR_VERSION) && defined(SDL_COMPILE_TIME_ASSERT)
+SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MAJOR_VERSION,
+                        SDL_IMAGE_MAJOR_VERSION == SDL_BUILD_MAJOR_VERSION);
+SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MINOR_VERSION,
+                        SDL_IMAGE_MINOR_VERSION == SDL_BUILD_MINOR_VERSION);
+SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MICRO_VERSION,
+                        SDL_IMAGE_PATCHLEVEL == SDL_BUILD_MICRO_VERSION);
+#endif
+
+#if defined(SDL_COMPILE_TIME_ASSERT)
+SDL_COMPILE_TIME_ASSERT(SDL_IMAGE_MAJOR_VERSION_min, SDL_IMAGE_MAJOR_VERSION >= 0);
+/* Limited only by the need to fit in SDL_version */
+SDL_COMPILE_TIME_ASSERT(SDL_IMAGE_MAJOR_VERSION_max, SDL_IMAGE_MAJOR_VERSION <= 255);
+
+SDL_COMPILE_TIME_ASSERT(SDL_IMAGE_MINOR_VERSION_min, SDL_IMAGE_MINOR_VERSION >= 0);
+/* Limited only by the need to fit in SDL_version */
+SDL_COMPILE_TIME_ASSERT(SDL_IMAGE_MINOR_VERSION_max, SDL_IMAGE_MINOR_VERSION <= 255);
+
+SDL_COMPILE_TIME_ASSERT(SDL_IMAGE_PATCHLEVEL_min, SDL_IMAGE_PATCHLEVEL >= 0);
+/* Limited by its encoding in SDL_VERSIONNUM and in the ABI versions */
+SDL_COMPILE_TIME_ASSERT(SDL_IMAGE_PATCHLEVEL_max, SDL_IMAGE_PATCHLEVEL <= 99);
+#endif
 
 /* Table of image detection and loading functions */
 static struct {
diff --git a/Makefile.os2 b/Makefile.os2
index 13d5acd..a148b26 100644
--- a/Makefile.os2
+++ b/Makefile.os2
@@ -5,7 +5,10 @@
 # your own environment!.
 
 LIBNAME = SDL2img
-VERSION = 2.0.6
+MAJOR_VERSION = 2
+MINOR_VERSION = 5
+MICRO_VERSION = 0
+VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 
 TITLENAME = $(LIBNAME) $(VERSION)
 
diff --git a/README-versions.md b/README-versions.md
new file mode 100644
index 0000000..c58232d
--- /dev/null
+++ b/README-versions.md
@@ -0,0 +1,59 @@
+# Versioning
+
+## Since 2.5.0
+
+`SDL_image` follows an "odd/even" versioning policy, similar to GLib, GTK, Flatpak
+and older versions of the Linux kernel:
+
+* The major version (first part) increases when backwards compatibility
+    is broken, which will happen infrequently.
+
+* If the minor version (second part) is divisible by 2
+    (for example 2.6.x, 2.8.x), this indicates a version that
+    is believed to be stable and suitable for production use.
+
+    * In stable releases, the patchlevel or micro version (third part)
+        indicates bugfix releases. Bugfix releases should not add or
+        remove ABI, so the ".0" release (for example 2.6.0) should be
+        forwards-compatible with all the bugfix releases from the
+        same cycle (for example 2.6.1).
+
+    * The minor version increases when new API or ABI is added, or when
+        other significant changes are made. Newer minor versions are
+        backwards-compatible, but not fully forwards-compatible.
+        For example, programs built against `SDL_image` 2.6.x should work fine
+        with 2.8.x, but programs built against 2.8.x will not necessarily
+        work with 2.6.x.
+
+* If the minor version (second part) is not divisible by 2
+    (for example 2.5.x, 2.7.x), this indicates a development prerelease
+    that is not suitable for stable software distributions.
+    Use with caution.
+
+    * The patchlevel or micro version (third part) increases with
+        each prerelease.
+
+    * Each prerelease might add new API and/or ABI.
+
+    * Prereleases are backwards-compatible with older stable branches.
+        For example, 2.7.x will be backwards-compatible with 2.6.x.
+
+    * Prereleases are not guaranteed to be backwards-compatible with
+        each other. For example, new API or ABI added in 2.5.1
+        might be removed or changed in 2.5.2.
+        If this would be a problem for you, please do not use prereleases.
+
+    * Only upgrade to a prerelease if you can guarantee that you will
+        promptly upgrade to the stable release that follows it.
+        For example, do not upgrade to 2.5.x unless you will be able to
+        upgrade to 2.6.0 when it becomes available.
+
+    * Software distributions that have a freeze policy (in particular Linux
+        distributions with a release cycle, such as Debian and Fedora)
+        should usually only package stable releases, and not prereleases.
+
+## Before 2.5.0
+
+Older versions of `SDL_image` used the patchlevel (micro version,
+third part) for feature releases, and did not distinguish between feature
+and bugfix releases.
diff --git a/SDL_image.h b/SDL_image.h
index ea57d8e..4af45d3 100644
--- a/SDL_image.h
+++ b/SDL_image.h
@@ -36,8 +36,8 @@ extern "C" {
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_IMAGE_MAJOR_VERSION 2
-#define SDL_IMAGE_MINOR_VERSION 0
-#define SDL_IMAGE_PATCHLEVEL    6
+#define SDL_IMAGE_MINOR_VERSION 5
+#define SDL_IMAGE_PATCHLEVEL    0
 
 /* This macro can be used to fill a version structure with the compile-time
  * version of the SDL_image library.
@@ -49,17 +49,27 @@ extern "C" {
     (X)->patch = SDL_IMAGE_PATCHLEVEL;              \
 }
 
+#if SDL_IMAGE_MAJOR_VERSION < 3 && SDL_MAJOR_VERSION < 3
 /**
  *  This is the version number macro for the current SDL_image version.
+ *
+ *  In versions higher than 2.9.0, the minor version overflows into
+ *  the thousands digit: for example, 2.23.0 is encoded as 4300.
+ *  This macro will not be available in SDL 3.x or SDL_image 3.x.
+ *
+ *  Deprecated, use SDL_IMAGE_VERSION_ATLEAST or SDL_IMAGE_VERSION instead.
  */
 #define SDL_IMAGE_COMPILEDVERSION \
     SDL_VERSIONNUM(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_PATCHLEVEL)
+#endif /* SDL_IMAGE_MAJOR_VERSION < 3 && SDL_MAJOR_VERSION < 3 */
 
 /**
  *  This macro will evaluate to true if compiled with SDL_image at least X.Y.Z.
  */
 #define SDL_IMAGE_VERSION_ATLEAST(X, Y, Z) \
-    (SDL_IMAGE_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
+    ((SDL_IMAGE_MAJOR_VERSION >= X) && \
+     (SDL_IMAGE_MAJOR_VERSION > X || SDL_IMAGE_MINOR_VERSION >= Y) && \
+     (SDL_IMAGE_MAJOR_VERSION > X || SDL_IMAGE_MINOR_VERSION > Y || SDL_IMAGE_PATCHLEVEL >= Z))
 
 /* This function gets the version of the dynamically linked SDL_image library.
    it should NOT be used to fill a version structure, instead you should
diff --git a/VisualC/Version.rc b/VisualC/Version.rc
index 3bef787..c18a5c0 100644
--- a/VisualC/Version.rc
+++ b/VisualC/Version.rc
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,6,0
- PRODUCTVERSION 2,0,6,0
+ FILEVERSION 2,5,0,0
+ PRODUCTVERSION 2,5,0,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -46,12 +46,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "\0"
             VALUE "FileDescription", "SDL_image\0"
-            VALUE "FileVersion", "2, 0, 6, 0\0"
+            VALUE "FileVersion", "2, 5, 0, 0\0"
             VALUE "InternalName", "SDL_image\0"
             VALUE "LegalCopyright", "Copyright  2022 Sam Lantinga\0"
             VALUE "OriginalFilename", "SDL_image.dll\0"
             VALUE "ProductName", "Simple DirectMedia Layer\0"
-            VALUE "ProductVersion", "2, 0, 6, 0\0"
+            VALUE "ProductVersion", "2, 5, 0, 0\0"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/Xcode/Info-Framework.plist b/Xcode/Info-Framework.plist
index 5ca3a32..e1faacd 100644
--- a/Xcode/Info-Framework.plist
+++ b/Xcode/Info-Framework.plist
@@ -15,8 +15,8 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.6</string>
+	<string>2.5.0</string>
 	<key>CFBundleVersion</key>
-	<string>2.0.6</string>
+	<string>2.5.0</string>
 </dict>
 </plist>
diff --git a/Xcode/SDL_image.xcodeproj/project.pbxproj b/Xcode/SDL_image.xcodeproj/project.pbxproj
index 0e9cc0b..074ac1f 100644
--- a/Xcode/SDL_image.xcodeproj/project.pbxproj
+++ b/Xcode/SDL_image.xcodeproj/project.pbxproj
@@ -522,7 +522,7 @@
 				ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
 				COPY_PHASE_STRIP = NO;
 				DYLIB_COMPATIBILITY_VERSION = 3.0.0;
-				DYLIB_CURRENT_VERSION = 7.0.0;
+				DYLIB_CURRENT_VERSION = 501.0.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_TESTABILITY = YES;
 				FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/$(PLATFORM)\"";
@@ -609,7 +609,7 @@
 				ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
 				DEPLOYMENT_POSTPROCESSING = YES;
 				DYLIB_COMPATIBILITY_VERSION = 3.0.0;
-				DYLIB_CURRENT_VERSION = 7.0.0;
+				DYLIB_CURRENT_VERSION = 501.0.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/$(PLATFORM)\"";
 				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
diff --git a/configure.ac b/configure.ac
index 80a7112..018d116 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,18 +1,10 @@
 dnl Process this file with autoconf to produce a configure script.
 
 dnl Set various version strings - taken gratefully from the GTk sources
-# Making releases:
-#   MICRO_VERSION_MACRO += 1;
-#   INTERFACE_AGE_MACRO += 1;
-#   BINARY_AGE_MACRO += 1;
-# if any functions have been added, set INTERFACE_AGE_MACRO to 0.
-# if backwards compatibility has been broken,
-# set BINARY_AGE_MACRO and INTERFACE_AGE_MACRO to 0.
+# See docs/release_checklist.md
 m4_define([MAJOR_VERSION_MACRO], [2])
-m4_define([MINOR_VERSION_MACRO], [0])
-m4_define([MICRO_VERSION_MACRO], [6])
-m4_define([INTERFACE_AGE_MACRO], [0])
-m4_define([BINARY_AGE_MACRO], [6])
+m4_define([MINOR_VERSION_MACRO], [5])
+m4_define([MICRO_VERSION_MACRO], [0])
 
 AC_INIT([SDL2_image],
         MAJOR_VERSION_MACRO.MINOR_VERSION_MACRO.MICRO_VERSION_MACRO,
@@ -24,16 +16,32 @@ AC_CONFIG_SRCDIR([IMG.c])
 AC_SUBST([MAJOR_VERSION], MAJOR_VERSION_MACRO)
 AC_SUBST([MINOR_VERSION], MINOR_VERSION_MACRO)
 AC_SUBST([MICRO_VERSION], MICRO_VERSION_MACRO)
-AC_SUBST([INTERFACE_AGE], INTERFACE_AGE_MACRO)
-AC_SUBST([BINARY_AGE], BINARY_AGE_MACRO)
+
+BINARY_AGE=`expr $MINOR_VERSION \* 100 + $MICRO_VERSION`
+AS_CASE(["$MINOR_VERSION"],
+  [*[02468]],
+    dnl Stable branch, 2.6.1 -> libSDL2-2.0.so.0.600.1
+    [INTERFACE_AGE="$MICRO_VERSION"],
+  [*],
+    dnl Development branch, 2.5.1 -> libSDL2-2.0.so.0.501.0
+    [INTERFACE_AGE=0])
 
 dnl libtool versioning
 LT_INIT([win32-dll])
 
-LT_RELEASE=$MAJOR_VERSION.$MINOR_VERSION
-LT_CURRENT=`expr $MICRO_VERSION - $INTERFACE_AGE`
-LT_REVISION=$INTERFACE_AGE
+# For historical reasons, the library name redundantly includes the major
+# version twice: libSDL2_image-2.0.so.0.
+# TODO: in SDL 3, stop using -release, which will simplify it to libSDL3.so.0
+LT_RELEASE=2.0
+# Increment this if there is an incompatible change - but if that happens,
+# we should rename the library from SDL2 to SDL3, at which point this would
+# reset to 0 anyway.
+LT_MAJOR=0
 LT_AGE=`expr $BINARY_AGE - $INTERFACE_AGE`
+LT_CURRENT=`expr $LT_MAJOR + $LT_AGE`
+LT_REVISION=$INTERFACE_AGE
+m4_pattern_allow([LT_MAJOR])
+
 LT_EXTRA="" dnl for OS2 dll name
 
 AC_SUBST(LT_RELEASE)
diff --git a/release_checklist.md b/release_checklist.md
new file mode 100644
index 0000000..55b66ff
--- /dev/null
+++ b/release_checklist.md
@@ -0,0 +1,93 @@
+# Release checklist
+
+## New feature release
+
+* Update `CHANGES.txt`
+
+* Bump version number to 2.EVEN.0 in all these locations:
+
+    * `SDL_image.h`:
+        `SDL_IMAGE_MAJOR_VERSION`, `SDL_IMAGE_MINOR_VERSION`, `SDL_IMAGE_PATCHLEVEL`
+    * `configure.ac`:
+        `MAJOR_VERSION_MACRO`, `MINOR_VERSION_MACRO`, `MICRO_VERSION_MACRO`
+    * `CMakeLists.txt`:
+        `MAJOR_VERSION`, `MINOR_VERSION`, `MICRO_VERSION`
+    * `Makefile.os2`:
+        `MAJOR_VERSION`, `MINOR_VERSION`, `MICRO_VERSION`
+    * `VisualC/Version.rc`:
+        `FILEVERSION`, `PRODUCTVERSION`, `FileVersion`, `ProductVersion`
+
+* Bump ABI version information
+
+    * `Xcode/SDL_image.xcodeproj/project.pbxproj`:
+        `DYLIB_CURRENT_VERSION`, `DYLIB_COMPATIBILITY_VERSION`
+        * set first number in `DYLIB_CURRENT_VERSION` to
+            (100 * *minor*) + 1
+        * set second number in `DYLIB_CURRENT_VERSION` to 0
+        * if backwards compatibility has been broken,
+            increase `DYLIB_COMPATIBILITY_VERSION` (?)
+
+* Run `./test-versioning.sh` to verify that everything is consistent
+
+* Regenerate `configure`
+
+* Do the release
+
+## New bugfix release
+
+* Check that no new API/ABI was added
+
+    * If it was, do a new feature release (see above) instead
+
+* Bump version number from 2.Y.Z to 2.Y.(Z+1) (Y is even)
+
+    * Same places as listed above
+
+* Bump ABI version information
+
+    * `Xcode/SDL_image.xcodeproj/project.pbxproj`:
+        `DYLIB_CURRENT_VERSION`, `DYLIB_COMPATIBILITY_VERSION`
+        * set second number in `DYLIB_CURRENT_VERSION` to *patchlevel*
+
+* Run test/versioning.sh to verify that everything is consistent
+
+* Regenerate `configure`
+
+* Do the release
+
+## After a feature release
+
+* Create a branch like `release-2.6.x`
+
+* Bump version number to 2.ODD.0 for next development branch
+
+    * Same places as listed above
+
+* Bump ABI version information
+
+    * Same places as listed above
+    * Assume that the next feature release will contain new API/ABI
+
+* Run test/versioning.sh to verify that everything is consistent
+
+## New development prerelease
+
+* Bump version number from 2.Y.Z to 2.Y.(Z+1) (Y is odd)
+
+    * Same places as listed above
+
+* Bump ABI version information
+
+    * `Xcode/SDL_image.xcodeproj/project.pbxproj`:
+        `DYLIB_CURRENT_VERSION`, `DYLIB_COMPATIBILITY_VERSION`
+        * set first number in `DYLIB_CURRENT_VERSION` to
+            (100 * *minor*) + *patchlevel* + 1
+        * set second number in `DYLIB_CURRENT_VERSION` to 0
+        * if backwards compatibility has been broken,
+            increase `DYLIB_COMPATIBILITY_VERSION` (?)
+
+* Run test/versioning.sh to verify that everything is consistent
+
+* Regenerate `configure`
+
+* Do the release
diff --git a/test-versioning.sh b/test-versioning.sh
new file mode 100755
index 0000000..733029d
--- /dev/null
+++ b/test-versioning.sh
@@ -0,0 +1,143 @@
+#!/bin/sh
+# Copyright 2022 Collabora Ltd.
+# SPDX-License-Identifier: Zlib
+
+set -eu
+
+ref_major=$(sed -ne 's/^#define SDL_IMAGE_MAJOR_VERSION  *//p' SDL_image.h)
+ref_minor=$(sed -ne 's/^#define SDL_IMAGE_MINOR_VERSION  *//p' SDL_image.h)
+ref_micro=$(sed -ne 's/^#define SDL_IMAGE_PATCHLEVEL  *//p' SDL_image.h)
+ref_version="${ref_major}.${ref_minor}.${ref_micro}"
+
+tests=0
+failed=0
+
+ok () {
+    tests=$(( tests + 1 ))
+    echo "ok - $*"
+}
+
+not_ok () {
+    tests=$(( tests + 1 ))
+    echo "not ok - $*"
+    failed=1
+}
+
+major=$(sed -Ene 's/^m4_define\(\[MAJOR_VERSION_MACRO\], \[([0-9]+)\]\)$/\1/p' configure.ac)
+minor=$(sed -Ene 's/^m4_define\(\[MINOR_VERSION_MACRO\], \[([0-9]+)\]\)$/\1/p' configure.ac)
+micro=$(sed -Ene 's/^m4_define\(\[MICRO_VERSION_MACRO\], \[([0-9]+)\]\)$/\1/p' configure.ac)
+version="${major}.${minor}.${micro}"
+
+if [ "$ref_version" = "$version" ]; then
+    ok "configure.ac $version"
+else
+    not_ok "configure.ac $version disagrees with SDL_image.h $ref_version"
+fi
+
+major=$(sed -ne 's/^set(MAJOR_VERSION \([0-9]\+\))$/\1/p' CMakeLists.txt)
+minor=$(sed -ne 's/^set(MINOR_VERSION \([0-9]\+\))$/\1/p' CMakeLists.txt)
+micro=$(sed -ne 's/^set(MICRO_VERSION \([0-9]\+\))$/\1/p' CMakeLists.txt)
+version="${major}.${minor}.${micro}"
+
+if [ "$ref_version" = "$version" ]; then
+    ok "CMakeLists.txt $version"
+else
+    not_ok "CMakeLists.txt $version disagrees with SDL_image.h $ref_version"
+fi
+
+major=$(sed -ne 's/^MAJOR_VERSION *= *//p' Makefile.os2)
+minor=$(sed -ne 's/^MINOR_VERSION *= *//p' Makefile.os2)
+micro=$(sed -ne 's/^MICRO_VERSION *= *//p' Makefile.os2)
+version="${major}.${minor}.${micro}"
+
+if [ "$ref_version" = "$version" ]; then
+    ok "Makefile.os2 $version"
+else
+    not_ok "Makefile.os2 $version disagrees with SDL_image.h $ref_version"
+fi
+
+tuple=$(sed -ne 's/^ *FILEVERSION *//p' VisualC/Version.rc | tr -d '\r')
+ref_tuple="${ref_major},${ref_minor},${ref_micro},0"
+
+if [ "$ref_tuple" = "$tuple" ]; then
+    ok "Version.rc FILEVERSION $tuple"
+else
+    not_ok "Version.rc FILEVERSION $tuple disagrees with SDL_image.h $ref_tuple"
+fi
+
+tuple=$(sed -ne 's/^ *PRODUCTVERSION *//p' VisualC/Version.rc | tr -d '\r')
+
+if [ "$ref_tuple" = "$tuple" ]; then
+    ok "Version.rc PRODUCTVERSION $tuple"
+else
+    not_ok "Version.rc PRODUCTVERSION $tuple disagrees with SDL_image.h $ref_tuple"
+fi
+
+tuple=$(sed -Ene 's/^ *VALUE "FileVersion", "([0-9, ]+)\\0"\r?$/\1/p' VisualC/Version.rc | tr -d '\r')
+ref_tuple="${ref_major}, ${ref_minor}, ${ref_micro}, 0"
+
+if [ "$ref_tuple" = "$tuple" ]; then
+    ok "Version.rc FileVersion $tuple"
+else
+    not_ok "Version.rc FileVersion $tuple disagrees with SDL_image.h $ref_tuple"
+fi
+
+tuple=$(sed -Ene 's/^ *VALUE "ProductVersion", "([0-9, ]+)\\0"\r?$/\1/p' VisualC/Version.rc | tr -d '\r')
+
+if [ "$ref_tuple" = "$tuple" ]; then
+    ok "Version.rc ProductVersion $tuple"
+else
+    not_ok "Version.rc ProductVersion $tuple disagrees with SDL_image.h $ref_tuple"
+fi
+
+version=$(sed -Ene '/CFBundleShortVersionString/,+1 s/.*<string>(.*)<\/string>.*/\1/p' Xcode/Info-Framework.plist)
+
+if [ "$ref_version" = "$version" ]; then
+    ok "Info-Framework.plist CFBundleShortVersionString $version"
+else
+    not_ok "Info-Framework.plist CFBundleShortVersionString $version disagrees with SDL_image.h $ref_version"
+fi
+
+version=$(sed -Ene '/CFBundleVersion/,+1 s/.*<string>(.*)<\/string>.*/\1/p' Xcode/Info-Framework.plist)
+
+if [ "$ref_version" = "$version" ]; then
+    ok "Info-Framework.plist CFBundleVersion $version"
+else
+    not_ok "Info-Framework.plist CFBundleVersion $version disagrees with SDL_image.h $ref_version"
+fi
+
+# For simplicity this assumes we'll never break ABI before SDL 3.
+dylib_compat=$(sed -Ene 's/.*DYLIB_COMPATIBILITY_VERSION = (.*);$/\1/p' Xcode/SDL_image.xcodeproj/project.pbxproj)
+ref='3.0.0
+3.0.0'
+
+if [ "$ref" = "$dylib_compat" ]; then
+    ok "project.pbxproj DYLIB_COMPATIBILITY_VERSION is consistent"
+else
+    not_ok "project.pbxproj DYLIB_COMPATIBILITY_VERSION is inconsistent"
+fi
+
+dylib_cur=$(sed -Ene 's/.*DYLIB_CURRENT_VERSION = (.*);$/\1/p' Xcode/SDL_image.xcodeproj/project.pbxproj)
+
+case "$ref_minor" in
+    (*[02468])
+        major="$(( ref_minor * 100 + 1 ))"
+        minor="$ref_micro"
+        ;;
+    (*)
+        major="$(( ref_minor * 100 + ref_micro + 1 ))"
+        minor="0"
+        ;;
+esac
+
+ref="${major}.${minor}.0
+${major}.${minor}.0"
+
+if [ "$ref" = "$dylib_cur" ]; then
+    ok "project.pbxproj DYLIB_CURRENT_VERSION is consistent"
+else
+    not_ok "project.pbxproj DYLIB_CURRENT_VERSION is inconsistent"
+fi
+
+echo "1..$tests"
+exit "$failed"