SDL_net: build: Use minor version number for feature releases

From ce340cf32970a5a0622f41be52c38c81d4bfd5d9 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Thu, 5 May 2022 19:09:54 +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              |   3 +
 Makefile.os2                            |  10 +-
 README-versions.md                      |  59 ++++++++++
 SDL_net.h                               |  16 ++-
 SDLnet.c                                |  23 ++++
 VisualC/Version.rc                      |   8 +-
 Xcode/Info-Framework.plist              |   4 +-
 Xcode/SDL_net.xcodeproj/project.pbxproj |   8 +-
 configure.ac                            |  44 +++++---
 release_checklist.md                    |  93 ++++++++++++++++
 test-versioning.sh                      | 138 ++++++++++++++++++++++++
 version.rc                              |   8 +-
 12 files changed, 382 insertions(+), 32 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 2959a72..8ab48bc 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -43,6 +43,9 @@ jobs:
           ${NULL+}
     - uses: actions/checkout@v2
 
+    - name: Check that versioning is consistent
+      run: ./test-versioning.sh
+
     - name: Configure Autotools
       run: |
         set -eu
diff --git a/Makefile.os2 b/Makefile.os2
index a5f3d90..6e1e759 100644
--- a/Makefile.os2
+++ b/Makefile.os2
@@ -5,7 +5,10 @@
 # your own environment!.
 
 LIBNAME = SDL2net
-VERSION = 2.0.1
+MAJOR_VERSION = 2
+MINOR_VERSION = 1
+MICRO_VERSION = 0
+VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 
 TITLENAME = $(LIBNAME) $(VERSION)
 
@@ -37,6 +40,11 @@ CFLAGS+= -DBUILD_SDL
 CFLAGS+= -I$(%WATCOM)/h/os2 -I$(%WATCOM)/h
 CFLAGS+= -I. $(DEPS_INC)
 
+# For the static assertions in SDLnet.c
+CFLAGS+= -DSDL_BUILD_MAJOR_VERSION=$(MAJOR_VERSION)
+CFLAGS+= -DSDL_BUILD_MINOR_VERSION=$(MINOR_VERSION)
+CFLAGS+= -DSDL_BUILD_MICRO_VERSION=$(MICRO_VERSION)
+
 $(LIBFILE): $(DLLFILE)
   @echo * Create library: $@...
   wlib -b -n -q -c -pa -s -t -zld -ii -io $@ $(DLLFILE)
diff --git a/README-versions.md b/README-versions.md
new file mode 100644
index 0000000..364d356
--- /dev/null
+++ b/README-versions.md
@@ -0,0 +1,59 @@
+# Versioning
+
+## Since 2.1.0
+
+`SDL_net` 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.2.x, 2.4.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.2.0) should be
+        forwards-compatible with all the bugfix releases from the
+        same cycle (for example 2.2.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_net` 2.2.x should work fine
+        with 2.4.x, but programs built against 2.4.x will not necessarily
+        work with 2.2.x.
+
+* If the minor version (second part) is not divisible by 2
+    (for example 2.1.x, 2.3.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.3.x will be backwards-compatible with 2.2.x.
+
+    * Prereleases are not guaranteed to be backwards-compatible with
+        each other. For example, new API or ABI added in 2.1.1
+        might be removed or changed in 2.1.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.1.x unless you will be able to
+        upgrade to 2.2.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.1.0
+
+Older versions of `SDL_net` used the patchlevel (micro version,
+third part) for feature releases, and did not distinguish between feature
+and bugfix releases.
diff --git a/SDL_net.h b/SDL_net.h
index d701a52..529048b 100644
--- a/SDL_net.h
+++ b/SDL_net.h
@@ -55,8 +55,8 @@ extern "C" {
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_NET_MAJOR_VERSION   2
-#define SDL_NET_MINOR_VERSION   0
-#define SDL_NET_PATCHLEVEL      1
+#define SDL_NET_MINOR_VERSION   1
+#define SDL_NET_PATCHLEVEL      0
 
 /* This macro can be used to fill a version structure with the compile-time
  * version of the SDL_net library.
@@ -68,17 +68,27 @@ extern "C" {
     (X)->patch = SDL_NET_PATCHLEVEL;                \
 }
 
+#if SDL_NET_MAJOR_VERSION < 3 && SDL_MAJOR_VERSION < 3
 /**
  *  This is the version number macro for the current SDL_net 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_net 3.x.
+ *
+ *  Deprecated, use SDL_NET_VERSION_ATLEAST or SDL_NET_VERSION instead.
  */
 #define SDL_NET_COMPILEDVERSION \
     SDL_VERSIONNUM(SDL_NET_MAJOR_VERSION, SDL_NET_MINOR_VERSION, SDL_NET_PATCHLEVEL)
+#endif /* SDL_NET_MAJOR_VERSION < 3 && SDL_MAJOR_VERSION < 3 */
 
 /**
  *  This macro will evaluate to true if compiled with SDL_net at least X.Y.Z.
  */
 #define SDL_NET_VERSION_ATLEAST(X, Y, Z) \
-    (SDL_NET_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
+    ((SDL_NET_MAJOR_VERSION >= X) && \
+     (SDL_NET_MAJOR_VERSION > X || SDL_NET_MINOR_VERSION >= Y) && \
+     (SDL_NET_MAJOR_VERSION > X || SDL_NET_MINOR_VERSION > Y || SDL_NET_PATCHLEVEL >= Z))
 
 /* This function gets the version of the dynamically linked SDL_net library.
    it should NOT be used to fill a version structure, instead you should
diff --git a/SDLnet.c b/SDLnet.c
index 70949a6..24eb05b 100644
--- a/SDLnet.c
+++ b/SDLnet.c
@@ -28,6 +28,29 @@
 #include <stdarg.h>
 #endif
 
+#if defined(SDL_BUILD_MAJOR_VERSION) && defined(SDL_COMPILE_TIME_ASSERT)
+SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MAJOR_VERSION,
+                        SDL_NET_MAJOR_VERSION == SDL_BUILD_MAJOR_VERSION);
+SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MINOR_VERSION,
+                        SDL_NET_MINOR_VERSION == SDL_BUILD_MINOR_VERSION);
+SDL_COMPILE_TIME_ASSERT(SDL_BUILD_MICRO_VERSION,
+                        SDL_NET_PATCHLEVEL == SDL_BUILD_MICRO_VERSION);
+#endif
+
+#if defined(SDL_COMPILE_TIME_ASSERT)
+SDL_COMPILE_TIME_ASSERT(SDL_NET_MAJOR_VERSION_min, SDL_NET_MAJOR_VERSION >= 0);
+/* Limited only by the need to fit in SDL_version */
+SDL_COMPILE_TIME_ASSERT(SDL_NET_MAJOR_VERSION_max, SDL_NET_MAJOR_VERSION <= 255);
+
+SDL_COMPILE_TIME_ASSERT(SDL_NET_MINOR_VERSION_min, SDL_NET_MINOR_VERSION >= 0);
+/* Limited only by the need to fit in SDL_version */
+SDL_COMPILE_TIME_ASSERT(SDL_NET_MINOR_VERSION_max, SDL_NET_MINOR_VERSION <= 255);
+
+SDL_COMPILE_TIME_ASSERT(SDL_NET_PATCHLEVEL_min, SDL_NET_PATCHLEVEL >= 0);
+/* Limited by its encoding in SDL_VERSIONNUM and in the ABI versions */
+SDL_COMPILE_TIME_ASSERT(SDL_NET_PATCHLEVEL_max, SDL_NET_PATCHLEVEL <= 99);
+#endif
+
 const SDLNet_version *SDLNet_Linked_Version(void)
 {
     static SDLNet_version linked_version;
diff --git a/VisualC/Version.rc b/VisualC/Version.rc
index d9b4ab0..df6bffb 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,1,0
- PRODUCTVERSION 2,0,1,0
+ FILEVERSION 2,1,0,0
+ PRODUCTVERSION 2,1,0,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -46,12 +46,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "\0"
             VALUE "FileDescription", "SDL_net\0"
-            VALUE "FileVersion", "2, 0, 1, 0\0"
+            VALUE "FileVersion", "2, 1, 0, 0\0"
             VALUE "InternalName", "SDL_net\0"
             VALUE "LegalCopyright", "Copyright  2022 Sam Lantinga\0"
             VALUE "OriginalFilename", "SDL_net.dll\0"
             VALUE "ProductName", "Simple DirectMedia Layer\0"
-            VALUE "ProductVersion", "2, 0, 1, 0\0"
+            VALUE "ProductVersion", "2, 1, 0, 0\0"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/Xcode/Info-Framework.plist b/Xcode/Info-Framework.plist
index 903b155..af2aedf 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.1</string>
+	<string>2.1.0</string>
 	<key>CFBundleVersion</key>
-	<string>2.0.1</string>
+	<string>2.1.0</string>
 </dict>
 </plist>
diff --git a/Xcode/SDL_net.xcodeproj/project.pbxproj b/Xcode/SDL_net.xcodeproj/project.pbxproj
index 5491bc1..efdb73c 100644
--- a/Xcode/SDL_net.xcodeproj/project.pbxproj
+++ b/Xcode/SDL_net.xcodeproj/project.pbxproj
@@ -361,7 +361,7 @@
 			buildSettings = {
 				COMBINE_HIDPI_IMAGES = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 1.1.0;
+				DYLIB_CURRENT_VERSION = 101.0.0;
 				FRAMEWORK_VERSION = A;
 				INFOPLIST_FILE = "Info-Framework.plist";
 				INSTALL_PATH = "@rpath";
@@ -374,7 +374,7 @@
 			buildSettings = {
 				COMBINE_HIDPI_IMAGES = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 1.1.0;
+				DYLIB_CURRENT_VERSION = 101.0.0;
 				FRAMEWORK_VERSION = A;
 				INFOPLIST_FILE = "Info-Framework.plist";
 				INSTALL_PATH = "@rpath";
@@ -387,7 +387,7 @@
 			buildSettings = {
 				COMBINE_HIDPI_IMAGES = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 101.0.0;
 				LIBRARY_STYLE = STATIC;
 				OTHER_LIBTOOL_FLAGS = "";
 				OTHER_REZFLAGS = "";
@@ -402,7 +402,7 @@
 			buildSettings = {
 				COMBINE_HIDPI_IMAGES = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 101.0.0;
 				LIBRARY_STYLE = STATIC;
 				OTHER_LIBTOOL_FLAGS = "";
 				OTHER_REZFLAGS = "";
diff --git a/configure.ac b/configure.ac
index 2df6836..0aa1e91 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,21 +5,21 @@ AC_CONFIG_SRCDIR([SDLnet.c])
 
 dnl Set various version strings - taken gratefully from the GTk sources
 
-# Making releases:
-#   MICRO_VERSION += 1;
-#   INTERFACE_AGE += 1;
-#   BINARY_AGE += 1;
-# if any functions have been added, set INTERFACE_AGE to 0.
-# if backwards compatibility has been broken,
-# set BINARY_AGE and INTERFACE_AGE to 0.
-
+# See release_checklist.md
 MAJOR_VERSION=2
-MINOR_VERSION=0
-MICRO_VERSION=1
-INTERFACE_AGE=1
-BINARY_AGE=1
+MINOR_VERSION=1
+MICRO_VERSION=0
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION
 
+BINARY_AGE=`expr $MINOR_VERSION \* 100 + $MICRO_VERSION`
+AS_CASE(["$MINOR_VERSION"],
+  [*@<:@02468@:>@],
+    dnl Stable branch, 2.2.1 -> libSDL2_net-2.0.so.0.200.1
+    [INTERFACE_AGE="$MICRO_VERSION"],
+  [*],
+    dnl Development branch, 2.1.1 -> libSDL2_net-2.0.so.0.101.0
+    [INTERFACE_AGE=0])
+
 AC_SUBST(MAJOR_VERSION)
 AC_SUBST(MINOR_VERSION)
 AC_SUBST(MICRO_VERSION)
@@ -30,11 +30,27 @@ AC_SUBST(VERSION)
 dnl libtool versioning
 LT_INIT([win32-dll])
 
-LT_RELEASE=$MAJOR_VERSION.$MINOR_VERSION
-LT_CURRENT=`expr $MICRO_VERSION - $INTERFACE_AGE`
+# For historical reasons, the library name redundantly includes the major
+# version twice: libSDL2_net-2.0.so.0.
+# TODO: in SDL 3, stop using -release, which will simplify it to libSDL3_net.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_REVISION=$INTERFACE_AGE
 LT_AGE=`expr $BINARY_AGE - $INTERFACE_AGE`
+LT_CURRENT=`expr $LT_MAJOR + $LT_AGE`
 LT_EXTRA="" dnl for OS2 dll name
+m4_pattern_allow([^LT_MAJOR$])
+
+
+dnl For use in static assertions
+AC_DEFINE_UNQUOTED([SDL_BUILD_MAJOR_VERSION], $MAJOR_VERSION, [ ])
+AC_DEFINE_UNQUOTED([SDL_BUILD_MINOR_VERSION], $MINOR_VERSION, [ ])
+AC_DEFINE_UNQUOTED([SDL_BUILD_MICRO_VERSION], $MICRO_VERSION, [ ])
 
 AC_SUBST(LT_RELEASE)
 AC_SUBST(LT_CURRENT)
diff --git a/release_checklist.md b/release_checklist.md
new file mode 100644
index 0000000..f5ef5f4
--- /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_net.h`:
+        `SDL_NET_MAJOR_VERSION`, `SDL_NET_MINOR_VERSION`, `SDL_NET_PATCHLEVEL`
+    * `configure.ac`:
+        `MAJOR_VERSION`, `MINOR_VERSION`, `MICRO_VERSION`
+    * `Makefile.os2`:
+        `MAJOR_VERSION`, `MINOR_VERSION`, `MICRO_VERSION`
+    * `version.rc`:
+        `FILEVERSION`, `PRODUCTVERSION`, `FileVersion`, `ProductVersion`
+    * `VisualC/Version.rc`:
+        `FILEVERSION`, `PRODUCTVERSION`, `FileVersion`, `ProductVersion`
+
+* Bump ABI version information
+
+    * `Xcode/SDL_net.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_net.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_net.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..df9f0e7
--- /dev/null
+++ b/test-versioning.sh
@@ -0,0 +1,138 @@
+#!/bin/sh
+# Copyright 2022 Collabora Ltd.
+# SPDX-License-Identifier: Zlib
+
+set -eu
+
+ref_major=$(sed -ne 's/^#define SDL_NET_MAJOR_VERSION  *//p' SDL_net.h)
+ref_minor=$(sed -ne 's/^#define SDL_NET_MINOR_VERSION  *//p' SDL_net.h)
+ref_micro=$(sed -ne 's/^#define SDL_NET_PATCHLEVEL  *//p' SDL_net.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 -ne 's/^MAJOR_VERSION=//p' configure.ac)
+minor=$(sed -ne 's/^MINOR_VERSION=//p' configure.ac)
+micro=$(sed -ne 's/^MICRO_VERSION=//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_net.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_net.h $ref_version"
+fi
+
+for rcfile in version.rc VisualC/Version.rc; do
+    tuple=$(sed -ne 's/^ *FILEVERSION *//p' "$rcfile" | tr -d '\r')
+    ref_tuple="${ref_major},${ref_minor},${ref_micro},0"
+
+    if [ "$ref_tuple" = "$tuple" ]; then
+        ok "$rcfile FILEVERSION $tuple"
+    else
+        not_ok "$rcfile FILEVERSION $tuple disagrees with SDL_net.h $ref_tuple"
+    fi
+
+    tuple=$(sed -ne 's/^ *PRODUCTVERSION *//p' "$rcfile" | tr -d '\r')
+
+    if [ "$ref_tuple" = "$tuple" ]; then
+        ok "$rcfile PRODUCTVERSION $tuple"
+    else
+        not_ok "$rcfile PRODUCTVERSION $tuple disagrees with SDL_net.h $ref_tuple"
+    fi
+
+    tuple=$(sed -Ene 's/^ *VALUE "FileVersion", "([0-9, ]+)\\0"\r?$/\1/p' "$rcfile" | tr -d '\r')
+    ref_tuple="${ref_major}, ${ref_minor}, ${ref_micro}, 0"
+
+    if [ "$ref_tuple" = "$tuple" ]; then
+        ok "$rcfile FileVersion $tuple"
+    else
+        not_ok "$rcfile FileVersion $tuple disagrees with SDL_net.h $ref_tuple"
+    fi
+
+    tuple=$(sed -Ene 's/^ *VALUE "ProductVersion", "([0-9, ]+)\\0"\r?$/\1/p' "$rcfile" | tr -d '\r')
+
+    if [ "$ref_tuple" = "$tuple" ]; then
+        ok "$rcfile ProductVersion $tuple"
+    else
+        not_ok "$rcfile ProductVersion $tuple disagrees with SDL_net.h $ref_tuple"
+    fi
+done
+
+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_net.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_net.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_net.xcodeproj/project.pbxproj)
+ref='1
+1
+1
+1'
+
+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_net.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
+${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"
diff --git a/version.rc b/version.rc
index 237a3c4..463180d 100644
--- a/version.rc
+++ b/version.rc
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,1,0
- PRODUCTVERSION 2,0,1,0
+ FILEVERSION 2,1,0,0
+ PRODUCTVERSION 2,1,0,0
  FILEFLAGSMASK 0x3fL
  FILEFLAGS 0x0L
  FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "\0"
             VALUE "FileDescription", "SDL_net\0"
-            VALUE "FileVersion", "2, 0, 1, 0\0"
+            VALUE "FileVersion", "2, 1, 0, 0\0"
             VALUE "InternalName", "SDL_net\0"
             VALUE "LegalCopyright", "Copyright  2022 Sam Lantinga\0"
             VALUE "OriginalFilename", "SDL_net.dll\0"
             VALUE "ProductName", "Simple DirectMedia Layer\0"
-            VALUE "ProductVersion", "2, 0, 1, 0\0"
+            VALUE "ProductVersion", "2, 1, 0, 0\0"
         END
     END
     BLOCK "VarFileInfo"