diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d8c4686a..1afd8300 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,26 +15,6 @@ concurrency: cancel-in-progress: true jobs: - job_metadata: - runs-on: ubuntu-latest - outputs: - commit_message: ${{ steps.get_commit_message.outputs.commit_message }} - steps: - - name: Checkout - uses: actions/checkout@v5 - with: - fetch-depth: 2 - - name: Print head git commit message - id: get_commit_message - run: | - if [[ -z "$COMMIT_MSG" ]]; then - COMMIT_MSG=$(git show -s --format=%s $REF) - fi - echo commit_message=$COMMIT_MSG | tee -a $GITHUB_OUTPUT - env: - COMMIT_MSG: ${{ github.event.head_commit.message }} - REF: ${{ github.event.pull_request.head.sha }} - build-sdist: name: Build sdist runs-on: ubuntu-latest @@ -50,47 +30,32 @@ jobs: path: ./dist/*.tar.gz build-wheel: - name: Build wheel for ${{ matrix.python }}-${{ matrix.buildplat[1] }} - needs: [job_metadata] + name: Build wheel for ${{ matrix.buildplat[1] }} runs-on: ${{ matrix.buildplat[0] }} - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') || contains(needs.job_metadata.outputs.commit_message, '[build wheels]') strategy: fail-fast: false matrix: buildplat: - [ubuntu-latest, musllinux_x86_64] - - [ubuntu-latest, manylinux_aarch64] - - [macos-15-intel, macosx_x86_64] # native Intel hardware + - [ubuntu-latest, manylinux_x86_64] + - [ubuntu-24.04-arm, manylinux_aarch64] + - [macos-latest, macosx_arm64] + - [macos-15-intel, macosx_x86_64] - [windows-latest, win_amd64] - python: ["cp310", "cp311", "cp312", "cp313", "cp314"] - include: - # Manylinux and arm64 builds (on native hardware) are cheap, do all in one - - { buildplat: ["ubuntu-latest", "manylinux_x86_64"], python: "*" } - - { buildplat: ["macos-14", "macosx_arm64"], python: "*" } steps: - uses: actions/checkout@v5 with: fetch-depth: 0 - - name: Install the latest version of uv - uses: astral-sh/setup-uv@v6 - - # For aarch64 support - # https://cibuildwheel.pypa.io/en/stable/faq/#emulation - - uses: docker/setup-qemu-action@v3 - with: - platforms: all - if: runner.os == 'Linux' && endsWith(matrix.buildplat[1], 'aarch64') - - name: Build wheel(s) - run: uvx cibuildwheel + uses: pypa/cibuildwheel@v3.2.1 env: - CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} + CIBW_BUILD: "cp310-${{ matrix.buildplat[1] }} cp311-${{ matrix.buildplat[1] }} " - uses: actions/upload-artifact@v5 with: - name: ${{ matrix.python == '*' && 'all' || matrix.python }}-${{ startsWith(matrix.buildplat[1], 'macosx') && 'macosx' || matrix.buildplat[1] }}-dist + name: ${{ matrix.buildplat[1] }}-dist path: ./wheelhouse/*.whl test-sdist: diff --git a/pyproject.toml b/pyproject.toml index 3141e3ab..e1d4365a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,11 +64,12 @@ test = [ [tool.cibuildwheel] # Disable PyPy skip = "pp*" - +# 3.11 is abi3 +build = "cp310-* cp311-*" # 64-bit builds only; 32-bit builds seem pretty niche these days, so # don't bother unless someone asks archs = ["native"] - +before-build = "pip install abi3audit" test-requires = [ "pytest", "nitime[full]", # Enable all optional behavior @@ -76,7 +77,24 @@ test-requires = [ test-command = "pytest -rsx --pyargs nitime" [tool.cibuildwheel.linux] -archs = ["x86_64", "aarch64"] +repair-wheel-command = [ + "auditwheel repair -w {dest_dir} {wheel}", + "bash tools/audit_wheel.sh {wheel}", +] + +[tool.cibuildwheel.macos] +archs = ["native"] +repair-wheel-command = [ + "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}", + "bash tools/audit_wheel.sh {wheel}", +] + +[tool.cibuildwheel.windows] +before-build = "pip install delvewheel abi3audit" +repair-wheel-command = [ + "delvewheel repair -w {dest_dir} {wheel}", + "bash tools/audit_wheel.sh {wheel}", +] [tool.pytest.ini_options] minversion = "8" diff --git a/setup.py b/setup.py index 3974b51f..300dcb10 100755 --- a/setup.py +++ b/setup.py @@ -4,26 +4,47 @@ This file only contains cython components. See pyproject.toml for the remaining configuration. """ -from setuptools import setup - -try: - from setuptools import Extension - from Cython.Build import cythonize - from numpy import get_include - - # add Cython extensions to the setup options - exts = [ - Extension( - 'nitime._utils', - ['nitime/_utils.pyx'], - include_dirs=[get_include()], - define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')], - ) - ] - opts = {'ext_modules': cythonize(exts, language_level='3')} -except ImportError: - # no loop for you! - opts = {} +import platform +import sys + +from Cython.Build import cythonize +from numpy import get_include +from setuptools import setup, Extension +from wheel.bdist_wheel import bdist_wheel + +# add Cython extensions to the setup options + + +# https://github.com/joerick/python-abi3-package-sample/blob/main/setup.py +class bdist_wheel_abi3(bdist_wheel): # noqa: D101 + def get_tag(self): # noqa: D102 + python, abi, plat = super().get_tag() + + if python.startswith("cp"): + return "cp311", "abi3", plat + + return python, abi, plat + + +macros = [('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')] +ext_kwargs = {} +setup_kwargs = {} +if sys.version_info.minor >= 11 and platform.python_implementation() == "CPython": + # Can create an abi3 wheel (typed memoryviews first available in 3.11)! + macros.append(("Py_LIMITED_API", "0x030B0000")) + ext_kwargs["py_limited_api"] = True + setup_kwargs["cmdclass"] = {"bdist_wheel": bdist_wheel_abi3} + + +exts = [ + Extension( + 'nitime._utils', + ['nitime/_utils.pyx'], + include_dirs=[get_include()], + define_macros=macros, + ) +] +opts = {'ext_modules': cythonize(exts, language_level='3'), **setup_kwargs} # Now call the actual setup function if __name__ == '__main__': diff --git a/tools/audit_wheel.sh b/tools/audit_wheel.sh new file mode 100755 index 00000000..dcd80bef --- /dev/null +++ b/tools/audit_wheel.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eo pipefail +set -x + +PY_MINOR=$(python -c "import sys; print(sys.version_info.minor)") +if [ "$PY_MINOR" -lt 11 ]; then + echo "Not checking abi3audit for Python $PY_MINOR < 3.11" + exit 0 +fi +abi3audit --strict --report --verbose "$1"