Repository: scikit-build/scikit-build-core (python)

Issue:
Introduce `SKBUILD_SABI_VERSION` CMake variable
To follow-up on https://github.com/orgs/scikit-build/discussions/1128#discussioncomment-11489351 answering a question from @minrk, I suggest we introduce the CMake cache variable `SKBUILD_SABI_VERSION` set from the value associated with the `wheel.py-api` setting.

Related documentation:
* https://scikit-build-core.readthedocs.io/en/latest/schema.html
* https://scikit-build-core.readthedocs.io/en/latest/cmakelists.html#limited-api-stable-abi
* https://scikit-build-core.readthedocs.io/en/latest/configuration.html#customizing-the-output-wheel

Related issues & pull requests:
* https://github.com/scikit-build/scikit-build-core/issues/743
* https://github.com/scikit-build/scikit-build-core/pull/957

Pull request:
feat: SKBUILD_SABI_VERSION
Fix #958.


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ad65c7c..ca94f29 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,7 +27,7 @@ jobs:
       - uses: actions/setup-python@v5
         with:
           python-version: "3.12"
-      - uses: astral-sh/setup-uv@v4
+      - uses: astral-sh/setup-uv@v5
       - name: Install nox
         run: uv tool install nox
       - uses: pre-commit/action@v3.0.1
@@ -112,7 +112,7 @@ jobs:
           python-version: ${{ matrix.python-version }}
           allow-prereleases: true
 
-      - uses: astral-sh/setup-uv@v4
+      - uses: astral-sh/setup-uv@v5
         if:
           matrix.python-version != '3.7' && matrix.python-version != 'pypy-3.8'
           && matrix.python-version != 'pypy-3.7'
@@ -177,7 +177,7 @@ jobs:
         with:
           python-version: ${{ matrix.python-version }}
 
-      - uses: astral-sh/setup-uv@v4
+      - uses: astral-sh/setup-uv@v5
 
       # The min requirements are not compatible with some of the extra test
       # deps, so limit to just built-in deps.
@@ -341,7 +341,7 @@ jobs:
         with:
           fetch-depth: 0
 
-      - uses: astral-sh/setup-uv@v4
+      - uses: astral-sh/setup-uv@v5
 
       - uses: wntrblm/nox@2024.10.09
         with:
diff --git a/docs/cmakelists.md b/docs/cmakelists.md
index c979241..062ec2d 100644
--- a/docs/cmakelists.md
+++ b/docs/cmakelists.md
@@ -36,7 +36,8 @@ related to making Python extension modules.
 
 If you are making a Limited API / Stable ABI package, you'll need the
 `Development.SABIModule` component instead (CMake 3.26+). You can use the
-`SKBUILD_SABI_COMPONENT` variable to check to see if it was requested.
+`SKBUILD_SABI_COMPONENT` variable to check to see if it was requested. You can
+get the version requested with `${SKBUILD_SABI_VERSION}`.
 
 <!-- prettier-ignore-start -->
 :::{warning}
@@ -142,13 +143,25 @@ When defining your module, if you only support the Stable ABI after some point,
 you should use (for example for 3.11):
 
 ```cmake
-if(NOT "${SKBUILD_SABI_COMPONENT}" STREQUAL "")
-  python_add_library(some_ext MODULE WITH_SOABI USE_SABI 3.11 ...)
+if(NOT "${SKBUILD_SABI_VERSION}" STREQUAL "")
+  python_add_library(some_ext MODULE WITH_SOABI USE_SABI ${SKBUILD_SABI_VERSION} ...)
 else()
   python_add_library(some_ext MODULE WITH_SOABI ...)
 endif()
 ```
 
+If you have a lot of libraries, you can conditionally save these two items into
+a variable with `set(USE_SABI USE_SABI ${SKBUILD_SABI_VERSION})` and use it in
+all your `python_add_library` calls:
+
+```
+if(NOT "${SKBUILD_SABI_VERSION}" STREQUAL "")
+  set(USE_SABI "USE_SABI ${SKBUILD_SABI_VERSION}")
+endif()
+
+python_add_library(some_ext MODULE WITH_SOABI ${USE_SABI} ...)
+```
+
 This will define `Py_LIMITED_API` for you. If you want to support building
 directly from CMake, you need to protect this for Python version,
 `Python_INTERPRETER_ID STREQUAL Python`, and free-threading Python 3.13+ doesn't
diff --git a/src/scikit_build_core/builder/builder.py b/src/scikit_build_core/builder/builder.py
index 5aecd1d..b19173f 100644
--- a/src/scikit_build_core/builder/builder.py
+++ b/src/scikit_build_core/builder/builder.py
@@ -233,6 +233,14 @@ class Builder:
             "Development.SABIModule" if limited_api else ""
         )
 
+        # Allow users to detect the version requested in settings
+        py_api = self.settings.wheel.py_api
+        cache_config["SKBUILD_SABI_VERSION"] = (
+            f"{py_api[2]}.{py_api[3:]}"
+            if limited_api and py_api.startswith("cp")
+            else ""
+        )
+
         if cache_entries:
             cache_config.update(cache_entries)
 


Test patch:
diff --git a/tests/packages/abi3_pyproject_ext/CMakeLists.txt b/tests/packages/abi3_pyproject_ext/CMakeLists.txt
index 9deb08e..33b13a2 100644
--- a/tests/packages/abi3_pyproject_ext/CMakeLists.txt
+++ b/tests/packages/abi3_pyproject_ext/CMakeLists.txt
@@ -10,8 +10,16 @@ find_package(
   COMPONENTS Interpreter Development.Module ${SKBUILD_SABI_COMPONENT}
   REQUIRED)
 
-if(NOT "${SKBUILD_SABI_COMPONENT}" STREQUAL "")
-  python_add_library(abi3_example MODULE abi3_example.c WITH_SOABI USE_SABI 3.7)
+if(NOT "${SKBUILD_SABI_VERSION}" STREQUAL "")
+  python_add_library(abi3_example MODULE abi3_example.c WITH_SOABI USE_SABI
+                     ${SKBUILD_SABI_VERSION})
+
+  if(NOT SKBUILD_SABI_VERSION STREQUAL "3.7")
+    message(
+      FATAL_ERROR
+        "TEST FAILED: SKBUILD_SABI_VERSION (${SKBUILD_SABI_VERSION}) is not 3.7"
+    )
+  endif()
 else()
   python_add_library(abi3_example MODULE abi3_example.c WITH_SOABI)
 endif()