Skip to content

Commit 5e54e7f

Browse files
committed
WHL: build limited-api compliant wheels
1 parent 8ee8ec8 commit 5e54e7f

3 files changed

Lines changed: 29 additions & 3 deletions

File tree

.github/workflows/cibuildwheel.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,21 @@ jobs:
4646
if: ${{ github.event_name }} == pull_request
4747
shell: bash
4848
# - On PPs, omit musllinux for speed
49-
# - On PRs, run just oldest and newest Python versions
49+
# - On PRs, run just oldest and newest Python versions (3.11 is the oldest abi3 target)
5050
run: |
51-
CIBW_SKIP="cp310-win_arm64 cp311-* cp312-* cp313-* *musllinux*"
51+
CIBW_SKIP="cp310-win_arm64 *musllinux*"
5252
echo "CIBW_SKIP=$CIBW_SKIP" >> $GITHUB_ENV
5353
echo "Setting CIBW_SKIP=$CIBW_SKIP"
5454
55+
CIBW_TEST_SKIP="cp312-* cp313-*"
56+
echo "CIBW_TEST_SKIP=$CIBW_TEST_SKIP" >> $GITHUB_ENV
57+
echo "Setting CIBW_TEST_SKIP=$CIBW_TEST_SKIP"
58+
5559
- name: "Building ${{ matrix.os }} (${{ matrix.arch }}) wheels"
5660
uses: pypa/cibuildwheel@v3.3.1
5761
env:
5862
CIBW_SKIP: ${{ env.CIBW_SKIP }}
63+
CIBW_TEST_SKIP: ${{ env.CIBW_TEST_SKIP }}
5964
CIBW_ARCHS: ${{ matrix.arch }}
6065

6166
- uses: actions/upload-artifact@v6

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,4 @@ test-command = [
127127
]
128128
manylinux-x86_64-image = "manylinux2014"
129129
manylinux-aarch64-image = "manylinux2014"
130+
environment = { CFTIME_LIMITED_API = "1" }

setup.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import sys
3+
import sysconfig
34
import numpy
45

56
from Cython.Build import cythonize
@@ -29,6 +30,21 @@
2930
CFTIME_DIR = os.path.join(SRCDIR, NAME)
3031
CYTHON_FNAME = os.path.join(CFTIME_DIR, '_{}.pyx'.format(NAME))
3132

33+
USE_PY_LIMITED_API = (
34+
# require opt-in (builds are specialized by default)
35+
os.getenv('CFTIME_LIMITED_API', '0') == '1'
36+
# Cython + numpy + limited API de facto requires Python >=3.11
37+
and sys.version_info >= (3, 11)
38+
# as of Python 3.14t, free-threaded builds don't support the limited API
39+
and not sysconfig.get_config_var("Py_GIL_DISABLED")
40+
)
41+
ABI3_TARGET_VERSION = "".join(str(_) for _ in sys.version_info[:2])
42+
ABI3_TARGET_HEX = hex(sys.hexversion & 0xFFFF00F0)
43+
44+
if USE_PY_LIMITED_API:
45+
SETUP_OPTIONS = {"bdist_wheel": {"py_limited_api": f"cp{ABI3_TARGET_VERSION}"}}
46+
else:
47+
SETUP_OPTIONS = {}
3248

3349
class CleanCython(Command):
3450
description = 'Purge artifacts built by Cython'
@@ -60,6 +76,8 @@ def run(self):
6076
}
6177
DEFINE_MACROS += [('CYTHON_TRACE', '1'),
6278
('CYTHON_TRACE_NOGIL', '1')]
79+
if USE_PY_LIMITED_API:
80+
DEFINE_MACROS.append(("Py_LIMITED_API", ABI3_TARGET_HEX))
6381
if FLAG_COVERAGE in sys.argv:
6482
sys.argv.remove(FLAG_COVERAGE)
6583
print('enable: "linetrace" Cython compiler directive')
@@ -71,7 +89,8 @@ def run(self):
7189
extension = Extension('{}._{}'.format(NAME, NAME),
7290
sources=[os.path.relpath(CYTHON_FNAME, BASEDIR)],
7391
define_macros=DEFINE_MACROS,
74-
include_dirs=[numpy.get_include(),])
92+
include_dirs=[numpy.get_include()],
93+
py_limited_api=USE_PY_LIMITED_API)
7594

7695
ext_modules = cythonize(
7796
extension,
@@ -82,4 +101,5 @@ def run(self):
82101
setup(
83102
cmdclass={'clean_cython': CleanCython},
84103
ext_modules=ext_modules,
104+
options=SETUP_OPTIONS,
85105
)

0 commit comments

Comments
 (0)