@@ -28,6 +28,14 @@ set(PY_LIMITED_API_DEF "Py_LIMITED_API=0x03090000")
2828string (TOLOWER "$ENV{NO_STABLE_ABI} " _abi_val)
2929if (_abi_val STREQUAL "1" OR _abi_val STREQUAL "true" )
3030 set (PY_LIMITED_API_DEF "" )
31+ if (NOT Python3_SOABI)
32+ execute_process (
33+ COMMAND ${Python3_EXECUTABLE} -c
34+ "import sysconfig; print(sysconfig.get_config_var('SOABI') or '')"
35+ OUTPUT_VARIABLE Python3_SOABI
36+ OUTPUT_STRIP_TRAILING_WHITESPACE
37+ )
38+ endif ()
3139 set (SOABI ".${Python3_SOABI} " )
3240endif ()
3341
@@ -188,6 +196,31 @@ install(
188196 COMPONENT python
189197)
190198
199+ #############################################################
200+ #################### SUFFIX TESTS ####################
201+ #############################################################
202+
203+ # Verify that each extension module was linked with a valid Python ABI suffix.
204+ # Guards against the double-dot bug (_solver..so) that occurs when
205+ # CMake's FindPython3 fails to populate Python3_SOABI.
206+ # Run with: cmake --build <build_dir> && ctest --test-dir <build_dir>
207+
208+ foreach (_ext_target output solver)
209+ add_test (
210+ NAME ExtensionSuffix_${_ext_target}
211+ COMMAND ${Python3_EXECUTABLE} -c
212+ "import importlib.machinery, os; \
213+ p = r'$<TARGET_FILE :${_ext_target} >'; \
214+ valid = importlib.machinery.EXTENSION_SUFFIXES; \
215+ assert os.path.exists(p), f'Extension not found: {p!r}'; \
216+ assert '..' not in os.path.basename(p), \
217+ f'Double-dot ABI bug in {p!r} -- Python3_SOABI was empty at configure time'; \
218+ assert any(p.endswith(s) for s in valid), \
219+ f'Invalid suffix in {p!r}, expected one of {valid}'; \
220+ print('PASS:', p)"
221+ )
222+ endforeach ()
223+
191224# Copy libomp.dylib on macOS if using scikit-build-core
192225if (APPLE AND DEFINED SKBUILD_PLATLIB_DIR)
193226 install (
0 commit comments