Skip to content

Commit d8ad327

Browse files
committed
WHL: build limited-api compliant wheels
1 parent b693757 commit d8ad327

3 files changed

Lines changed: 51 additions & 22 deletions

File tree

.github/workflows/cibuildwheel.yml

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ jobs:
5959
arch: aarch64
6060
- os: macos-14
6161
arch: arm64
62-
CIBW_ENVIRONMENT: MACOSX_DEPLOYMENT_TARGET=14.0
6362
- os: macos-13
6463
arch: x86_64
65-
CIBW_ENVIRONMENT: MACOSX_DEPLOYMENT_TARGET=13.0
6664

6765
steps:
6866
- uses: actions/checkout@v5
@@ -80,33 +78,17 @@ jobs:
8078
shell: bash
8179
# On PRs we run only oldest and newest Python versions to reduce CI load.
8280
# Skips pypy and musllinux everywhere.
83-
# We are buiding 38 and 312 for now.
81+
# We are buiding 39 and 314 for now.
8482
# These needs to rotate every new Python release.
8583
run: |
86-
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
87-
CIBW_SKIP="pp* cp36-* cp37-* cp38-* cp314t-* *-musllinux* cp39-* cp310-* cp311-* cp312-* cp313-*"
88-
else
89-
CIBW_SKIP="pp* cp36-* cp37-* cp38-* cp314t-* *-musllinux*"
90-
fi
91-
echo "CIBW_SKIP=$CIBW_SKIP" >> $GITHUB_ENV
92-
echo "Setting CIBW_SKIP=$CIBW_SKIP"
84+
echo "Setting CIBW_BUILD='cp39-* cp314-*'"
85+
echo "CIBW_BUILD='cp39-* cp314-*'" >> $GITHUB_ENV
86+
if: ${{ github.event_name }}" == "pull_request"
9387

9488
- name: "Building ${{ matrix.os }} (${{ matrix.arch }}) wheels"
9589
uses: pypa/cibuildwheel@v3.1.4
9690
env:
97-
CIBW_SKIP: ${{ env.CIBW_SKIP }}
9891
CIBW_ARCHS: ${{ matrix.arch }}
99-
CIBW_BUILD_FRONTEND: build
100-
CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/ocefpaf/manylinux_2_28_x86_64-netcdf
101-
CIBW_MANYLINUX_AARCH64_IMAGE: ghcr.io/ocefpaf/manylinux_2_28_aarch64-netcdf
102-
# Emulation testing is slow, testing only latest Python.
103-
CIBW_TEST_SKIP: "cp39-*_aarch64 cp310-*_aarch64 cp311-*_aarch64 cp312-*_aarch64"
104-
CIBW_ENVIRONMENT: ${{ matrix.CIBW_ENVIRONMENT }}
105-
CIBW_BEFORE_BUILD_MACOS: brew install hdf5 netcdf
106-
CIBW_TEST_REQUIRES: pytest cython packaging typing-extensions
107-
CIBW_TEST_COMMAND: >
108-
python -c "import netCDF4; print(f'netCDF4 v{netCDF4.__version__}')"
109-
&& pytest -s -rxs -v {project}/test
11092

11193
- uses: actions/upload-artifact@v4
11294
with:

pyproject.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ tests = [
4545
"Cython",
4646
"packaging",
4747
"pytest",
48+
"typing-extensions",
4849
]
4950
parallel = [
5051
"mpi4py",
@@ -102,3 +103,30 @@ module = [
102103
"filter_availability",
103104
"matplotlib.*"
104105
]
106+
107+
[tool.cibuildwheel]
108+
build-verbosity = 1
109+
build-frontend = "build"
110+
skip = [
111+
"*-musllinux*",
112+
"cp314t-*",
113+
]
114+
test-extras = "tests"
115+
test-command = [
116+
"""python -c "import netCDF4; print(f'netCDF4 v{netCDF4.__version__}')""",
117+
"pytest -s -rxs -v {project}/test",
118+
]
119+
manylinux-x86_64-image = "ghcr.io/ocefpaf/manylinux_2_28_x86_64-netcdf"
120+
manylinux-aarch64-image = "ghcr.io/ocefpaf/manylinux_2_28_aarch64-netcdf"
121+
environment = {"NETCDF4_LIMITED_API" = "1"}
122+
123+
[tool.cibuildwheel.macos]
124+
before-build = "brew install hdf5 netcdf"
125+
126+
[[tool.cibuildwheel.macos.environment]]
127+
select = "x86_64"
128+
MACOSX_DEPLOYMENT_TARGET = "13.0"
129+
130+
[[tool.cibuildwheel.macos.environment]]
131+
select = "amr64"
132+
MACOSX_DEPLOYMENT_TARGET = "14.0"

setup.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,27 @@
33
import pathlib
44
import shutil
55
import configparser
6+
import sysconfig
67
from setuptools import setup, Extension
78
from setuptools.dist import Distribution
89
from typing import List
910

1011

12+
USE_PY_LIMITED_API = (
13+
# require opt-in (builds are specilized by default)
14+
os.getenv('NETCDF4_LIMITED_API', '0') == '1'
15+
# Cython + numpy + limited API de facto requires Python >=3.11
16+
and sys.version_info >= (3, 11)
17+
# as of Python 3.14t, free-threaded builds don't support the limited API
18+
and not sysconfig.get_config_var("Py_GIL_DISABLED")
19+
)
20+
ABI3_TARGET_VERSION = "".join(str(_) for _ in sys.version_info[:2])
21+
ABI3_TARGET_HEX = hex(sys.hexversion & 0xFFFF00F0)
22+
23+
if USE_PY_LIMITED_API:
24+
SETUP_OPTIONS = {"bdist_wheel": {"py_limited_api": f"cp{ABI3_TARGET_VERSION}"}}
25+
else:
26+
SETUP_OPTIONS = {}
1127

1228
open_kwargs = {'encoding': 'utf-8'}
1329

@@ -436,6 +452,8 @@ def _populate_hdf5_info(dirstosearch, inc_dirs, libs, lib_dirs):
436452
str(nc_complex_dir / "include/generated_fallbacks"),
437453
]
438454
DEFINE_MACROS += [("NC_COMPLEX_NO_EXPORT", "1")]
455+
if USE_PY_LIMITED_API:
456+
DEFINE_MACROS.append(("Py_LIMITED_API", ABI3_TARGET_HEX))
439457

440458
ext_modules = [Extension("netCDF4._netCDF4",
441459
source_files,
@@ -477,6 +495,7 @@ def _populate_hdf5_info(dirstosearch, inc_dirs, libs, lib_dirs):
477495
name="netCDF4", # need by GitHub dependency graph
478496
version=extract_version(netcdf4_src_pyx),
479497
ext_modules=ext_modules,
498+
options=SETUP_OPTIONS,
480499
)
481500

482501
# remove plugin files copied from outside source tree

0 commit comments

Comments
 (0)