diff --git a/.github/workflows/deploy-on-release.yml b/.github/workflows/deploy-on-release.yml index af80931d7..b4689a958 100644 --- a/.github/workflows/deploy-on-release.yml +++ b/.github/workflows/deploy-on-release.yml @@ -275,29 +275,28 @@ jobs: wheels: needs: setup-jobs if: needs.setup-jobs.outputs.allowed-jobs == 'Wheels' || needs.setup-jobs.outputs.allowed-jobs == 'All' - name: ${{ matrix.name }} ${{ matrix.py }} wheel + name: ${{ matrix.name }} Stable ABI wheel runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [macos-15, ubuntu-24.04, ubuntu-24.04-arm, windows-2025-vs2026, windows-11-arm] - py: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + os: [macos-15, macos-15-intel, ubuntu-24.04, ubuntu-24.04-arm, windows-2025-vs2026, windows-11-arm] + py: ['3.14'] include: - - name: 'Windows' - os: windows-2025-vs2026 - - name: 'Windows ARM' - os: windows-11-arm - - name: 'Linux' + - name: 'LinuxARM' os: ubuntu-24.04-arm - - name: 'Linux ARM' + - name: 'LinuxIntel' os: ubuntu-24.04 - - name: 'macOS' + - name: 'macOSARM' os: macos-15 - exclude: - - os: ubuntu-24.04 - py: '3.9' - - os: ubuntu-24.04-arm - py: '3.9' + - name: 'macOSIntel' + os: macos-15-intel + - name: 'WindowsARM' + os: windows-11-arm + arch: arm64 + - name: 'WindowsIntel' + os: windows-2025-vs2026 + arch: amd64 steps: - name: Check out libCellML @@ -309,8 +308,9 @@ jobs: id: setup shell: bash run: | - VERSION="${GITHUB_REF_NAME_TMP#refs/tags/v}" - if [[ "$OSTYPE" == "darwin*" ]]; then + VERSION="${GITHUB_REF#refs/tags/v}" + echo "Setting version as: VERSION=${VERSION}" + if [[ "$OSTYPE" == darwin* ]]; then sed -i '' "s/__VERSION__/${VERSION}/" src/bindings/python/pyproject.toml else sed -i "s/__VERSION__/${VERSION}/" src/bindings/python/pyproject.toml @@ -318,48 +318,34 @@ jobs: grep '^version' src/bindings/python/pyproject.toml v=${{ matrix.py }} - echo "Setting tag as: tag=${GITHUB_REF#refs/tags/}" - echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT echo "Setting build as: build=cp${v/./}-*" echo "build=cp${v/./}-*" >> $GITHUB_OUTPUT - if [[ "macOS" == "${{ matrix.name }}" ]]; then - echo "Setting macos_archs as: macos_archs='x86_64 arm64'" - echo "macos_archs=x86_64 arm64" >> $GITHUB_OUTPUT - echo "macos_deployment_target=14.0" >> $GITHUB_OUTPUT - elif [[ "Windows" == "${{ matrix.name }}" ]]; then - echo "Setting win_arch as: win_arch=amd64" - echo "win_arch=amd64" >> $GITHUB_OUTPUT - elif [[ "Windows ARM" == "${{ matrix.name }}" ]]; then - echo "Setting win_arch as: win_arch=arm64" - echo "win_arch=arm64" >> $GITHUB_OUTPUT - fi - name: Configure MSVC (Windows) if: runner.os == 'Windows' uses: TheMrMilchmann/setup-msvc-dev@v4 with: - arch: ${{ steps.setup.outputs.win_arch }} + arch: ${{ matrix.arch }} - name: Install SWIG (macOS) if: runner.os == 'macOS' run: brew install swig - name: Build wheels - uses: pypa/cibuildwheel@v3.4 + uses: pypa/cibuildwheel@v4.2 env: #CIBW_BUILD_VERBOSITY: 1 CIBW_ARCHS: auto64 - CIBW_ARCHS_MACOS: ${{ steps.setup.outputs.macos_archs }} CIBW_BUILD: ${{ steps.setup.outputs.build }} - CIBW_TEST_SKIP: "*_arm64" CIBW_BEFORE_ALL_LINUX: yum install -y libxml2-devel || (apk add libxml2-dev && rm /usr/lib/cmake/libxml2/libxml2-config.cmake) CIBW_ENVIRONMENT: > - LIBCELLML_VERSION_TAG=${{ steps.setup.outputs.tag }} - MACOSX_DEPLOYMENT_TARGET=${{ steps.setup.outputs.macos_deployment_target }} - CIBW_REPAIR_WHEEL_COMMAND_MACOS: "" + LIBCELLML_VERSION_TAG=${{ github.event.release.tag_name }} + MACOSX_DEPLOYMENT_TARGET=14.0 CIBW_BEFORE_BUILD_LINUX: pip install renamewheel CIBW_BEFORE_BUILD_WINDOWS: cd src/bindings/python && cmake -S wheel_dependencies -B build-wheel_dependencies -G Ninja && cd build-wheel_dependencies && ninja CIBW_REPAIR_WHEEL_COMMAND_LINUX: renamewheel -w {dest_dir} {wheel} + CIBW_REPAIR_WHEEL_COMMAND_MACOS: "" + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "" with: output-dir: wheelhouse package-dir: src/bindings/python/ @@ -368,13 +354,13 @@ jobs: uses: actions/upload-artifact@v7 with: path: ./wheelhouse/*.whl - name: ${{ matrix.name }}-${{ matrix.py }}-wheel + name: ${{ matrix.name }}-wheel retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} publish-wheels: if: needs.setup-jobs.outputs.binaries-destination == 'Publish' needs: wheels - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 5 # Docker+network are slow sometimes. permissions: id-token: write diff --git a/CMakeLists.txt b/CMakeLists.txt index 728e7416c..52cb7b5be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.18.0) +cmake_minimum_required(VERSION 3.26.0) if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET 14.0 CACHE STRING "Minimum OS X deployment version.") diff --git a/cmake/environmentchecks.cmake b/cmake/environmentchecks.cmake index 21ba618b5..a508a1b28 100644 --- a/cmake/environmentchecks.cmake +++ b/cmake/environmentchecks.cmake @@ -26,16 +26,18 @@ if (EMSCRIPTEN) find_program(NODE_EXE NAMES ${PREFERRED_NODE_NAMES} node) find_program(NPM_EXE NAMES ${PREFERRED_NPM_NAMES} npm) else () - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18 AND CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(_FIND_PYTHON_DEVELOPMENT_TYPE Development.Module) - set(FIND_PYTHON_DEVELOPMENT_MODULE TRUE) - else() - set(_FIND_PYTHON_DEVELOPMENT_TYPE Development) - endif() - test_undefined_symbols_allowed() - find_package(Python ${PREFERRED_PYTHON_VERSION} COMPONENTS Interpreter ${_FIND_PYTHON_DEVELOPMENT_TYPE}) + find_package(Python ${PREFERRED_PYTHON_VERSION} COMPONENTS Interpreter Development.SABIModule Development.Module) + + if (TARGET Python::SABIModule) + set(_PYTHON_LINK_TARGET Python::SABIModule) + elseif (TARGET Python::Module) + message(STATUS "Using backup Python::Module target for linking.") + set(_PYTHON_LINK_TARGET Python::Module) + else() + message(STATUS "Could not find Python::SABIModule or Python::Module target.") + endif() find_program(BUILDCACHE_EXE buildcache) if(NOT BUILDCACHE_EXE) @@ -73,7 +75,7 @@ else () find_package(Doxygen) find_package(Sphinx) - find_package(SWIG 3) + find_package(SWIG 4) set(_ORIGINAL_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) @@ -152,7 +154,7 @@ if(SWIG_EXECUTABLE) set(BINDINGS_AVAILABLE TRUE CACHE INTERNAL "Executable required to generate bindings is available.") endif() -if(BINDINGS_AVAILABLE AND (Python_Development.Module_FOUND OR Python_Development_FOUND)) +if(BINDINGS_AVAILABLE AND (Python_Development.SABIModule_FOUND OR Python_Development.Module_FOUND)) set(PYTHON_BINDINGS_AVAILABLE TRUE CACHE INTERNAL "Requirements for creating Python bindings are available.") endif() diff --git a/docs/configure_and_build.rst b/docs/configure_and_build.rst index 7a8ba0540..da848da8b 100644 --- a/docs/configure_and_build.rst +++ b/docs/configure_and_build.rst @@ -23,7 +23,7 @@ Configure with CMake The first step is to use :cmake:`CMake<>` to configure and generate build files for the libCellML library. Linux and MacOS use a command line interface, and under Windows there is an optional GUI. -Note that CMake version 3.2 or later is required to configure libCellML. +Note that CMake version 3.26 or later is required to configure libCellML. Instructions and information about installing CMake can be found in the :ref:`Setup ` section. diff --git a/docs/dev_building_web_assembly.rst b/docs/dev_building_web_assembly.rst index 463ba8449..4222dee81 100644 --- a/docs/dev_building_web_assembly.rst +++ b/docs/dev_building_web_assembly.rst @@ -15,7 +15,7 @@ To build *libCellML* for the browser, we will need the following tools ready for - Emscripten - Compiler toolchain -- CMake (at least version 3.14) +- CMake (at least version 3.26) - Git Building diff --git a/docs/setup.rst b/docs/setup.rst index 2fa3190ab..3afcc45f1 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -59,7 +59,7 @@ CMake :cmake:`CMake<>` is the cross-platform family of tools designed to build, test and package software. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and to generate native makefiles and workspaces that can be used in the compiler environment of your choice. -Note that CMake version 3.2 or later is required to configure libCellML. +Note that CMake version 3.26 or later is required to configure libCellML. Again, installation of CMake is particular to each operating system. diff --git a/docs/versions.rst b/docs/versions.rst index 4e6405929..040298098 100644 --- a/docs/versions.rst +++ b/docs/versions.rst @@ -4,10 +4,9 @@ Dependency versions and compatibility ===================================== -This document outlines the versions of packages which libCellML requires. - -**TODO** - - +This document outlines the versions of packages which libCellML requires. +SWIG version 4.4.0 or later is required when generating stable-ABI Python bindings intended for Python 3.15 or later. +SWIG version 4 remains supported for developers who are only targeting the Python version the bindings were compiled against. +**TODO** diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index d4f702aa5..c8e73269c 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -94,17 +94,14 @@ foreach(SWIG_INTERFACE_SRC ${SWIG_INTERFACE_SRCS}) SOURCES ${SWIG_INTERFACE_SRC} ) target_link_libraries(${MODULE_TARGET} PRIVATE cellml) + if(Python_Development.SABIModule_FOUND) + target_compile_definitions(${MODULE_TARGET} PRIVATE Py_LIMITED_API=0x030a0000) + endif() if(SWIG_VERSION VERSION_GREATER_EQUAL 4.1.0) set_target_properties(${MODULE_TARGET} PROPERTIES SWIG_COMPILE_OPTIONS -flatstaticmethod) endif() - if(FIND_PYTHON_DEVELOPMENT_MODULE) - set(_PYTHON_LINK_TARGET Python::Module) - else() - set(_PYTHON_LINK_TARGET Python::Python) - endif() - if (APPLE) # Specifically allow dynamic lookup, here we are really targeting Python symbols. set_target_properties(${MODULE_TARGET} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") diff --git a/src/bindings/python/pyproject.toml b/src/bindings/python/pyproject.toml index 7f3297b09..4a659763a 100644 --- a/src/bindings/python/pyproject.toml +++ b/src/bindings/python/pyproject.toml @@ -34,6 +34,7 @@ cmake.source-dir = "../../.." cmake.version = ">=3.26.1" install.targets = ["install-wheel"] ninja.version = ">=1.11" +wheel.py-api = "cp310" [[tool.scikit-build.overrides]] if.platform-system = "^win32"