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..277125391 100644 --- a/cmake/environmentchecks.cmake +++ b/cmake/environmentchecks.cmake @@ -35,7 +35,16 @@ else () 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) @@ -152,7 +161,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/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index d4f702aa5..3e314d020 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -94,17 +94,12 @@ foreach(SWIG_INTERFACE_SRC ${SWIG_INTERFACE_SRCS}) SOURCES ${SWIG_INTERFACE_SRC} ) target_link_libraries(${MODULE_TARGET} PRIVATE cellml) + target_compile_definitions(${MODULE_TARGET} PRIVATE Py_LIMITED_API=0x030a0000) 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/cibuildwheel.setup.py b/src/bindings/python/cibuildwheel.setup.py new file mode 100644 index 000000000..52b9cebc8 --- /dev/null +++ b/src/bindings/python/cibuildwheel.setup.py @@ -0,0 +1,48 @@ +""" libCellML Library: A library for the parsing, printing, and manipulation +of CellML 2.0 compliant models. + +""" + +classifiers = """\ +Development Status :: 5 - Production/Stable +Intended Audience :: Developers +Intended Audience :: Education +Intended Audience :: Science/Research +Programming Language :: Python +Operating System :: Microsoft :: Windows +Operating System :: Unix +Operating System :: MacOS :: MacOS X +Topic :: Software Development :: Libraries :: Python Modules +""" + +import os +import platform + +from skbuild import setup + +cmake_args = ["-DUNIT_TESTS=OFF", "-DCOVERAGE=OFF", "-DMEMCHECK=OFF", "-DLLVM_COVERAGE=OFF", "-DCLANG_TIDY=OFF"] + +if platform.system() == "Windows": + cmake_args.append("-DLibXml2_DIR=C:/Program Files (x86)/libxml2/libxml2-2.9.10/CMake/") + +doclines = __doc__.split("\n") + +tag = os.environ.get("LIBCELLML_VERSION_TAG", "v0.0.0") + +setup( + name="libcellml", + version=tag[1:], + description=doclines[0], + author="libCellML contributors", + url="https://libcellml.org", + license="Apache 2.0", + packages=["libcellml"], + classifiers=[cl for cl in classifiers.split("\n") if cl], + long_description=open('README.rst').read(), + long_description_content_type='text/x-rst', + include_package_data=True, + cmake_source_dir="../../../", + cmake_install_target="install-wheel", + cmake_args=cmake_args, + exclude_package_data={"": ["bin/*", "cmake/*", "include/*", "lib/*"]}, +) 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"