Skip to content

ci: build x86_64 macOS wheels (cross-compiled on arm64) so Intel Macs never build from source - #32

Merged
stevevanhooser merged 1 commit into
mainfrom
ci/macos-x86_64-wheels
Oct 14, 2026
Merged

stevevanhooser merged 1 commit into
mainfrom
ci/macos-x86_64-wheels

Conversation

@stevevanhooser

@stevevanhooser stevevanhooser commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Why

Intel Macs had no wheel and installed from the sdist, which compiles the library at install time (needs CMake + a C++ compiler). The NDI installer will depend on pyraview, so an Intel Mac user must get a pre-built wheel.

What

  • pyproject.toml: [tool.cibuildwheel.macos] archs = ["x86_64", "arm64"] gives separate per-arch wheels. I didn't use universal2 because I found no reason to make every Mac download twice as big. GitHub has no Intel runner, so x86_64 is cross-compiled on the arm64 macos-latest runner: cibuildwheel exports ARCHFLAGS=-arch x86_64, which scikit-build-core maps to CMAKE_OSX_ARCHITECTURES. The bundled-library test-command still runs for every x86_64 wheel, under Rosetta 2 (arch -x86_64). No test-skip was needed.
  • x86_64 wheels get MACOSX_DEPLOYMENT_TARGET=10.13, the oldest target current Xcode supports and what CPython 3.12+ needs anyway. cibuildwheel raises it to 10.15 for CPython 3.14+, and logs a warning saying so. arm64 stays 11.0.
  • New .github/scripts/check_macos_wheel_arch.sh unzips every macOS wheel and runs lipo -archs / otool -l / file on the bundled dylib. It fails if the library's architecture differs from the wheel tag's (in either direction), or if its minos is newer than the tag claims. It runs in release.yml after cibuildwheel on macOS, and in the new workflow below.
  • New .github/workflows/wheels.yml (on pull_request, path-filtered to the C/Python sources, CMakeLists, pyproject, the workflows and the script; plus workflow_dispatch): builds, tests and arch-checks the macOS wheels for both archs exactly as the release does. test.yml has no cibuildwheel job, so this is the PR-time proof.
  • Updated the release.yml comment and the README; Intel Macs are no longer told to build from source.

Results (CI on this PR, cibuildwheel 4.3.1, macos-latest arm64)

macOS wheel tags produced (18):

Python Intel Apple Silicon
cp39, cp310, cp311, cp312, cp313 macosx_10_13_x86_64 macosx_11_0_arm64
cp314, cp314t, cp315, cp315t macosx_10_15_x86_64 macosx_11_0_arm64

Minimum macOS: 10.13 High Sierra on Intel (10.15 Catalina for Python 3.14+), 11.0 Big Sur on Apple Silicon. Each library's LC_BUILD_VERSION minos matches its tag.

How the architecture was verified:

  1. The check script output shows every x86_64-tagged wheel carries libpyraview.dylib as [x86_64] (Mach-O 64-bit dynamically linked shared library x86_64) and every arm64 wheel as [arm64], all 18 ok.
  2. cibuildwheel ran "Testing wheel on x86_64..." 9 times, as arch -x86_64 /bin/sh -c 'python -c ...' in an x86_64 venv. Each run printed bundled: .../venv-test-x86_64/.../pyraview/libpyraview.dylib, so an x86_64 Python actually loaded the bundled library.
  3. delocate's default --require-archs check also passed.

MATLAB toolbox (investigated; not changed here)

Intel-Mac MATLAB users are affected. The macOS MEX is built only on the arm64 macos-15 runner (R2025a), and the v0.4.1 release ships pyraview.mexa64, pyraview.mexmaca64 and pyraview.mexw64, with no pyraview.mexmaci64. On Intel-Mac MATLAB the toolbox has no binary. The auto-download fallback in pyraview.m then requests releases/latest/download/pyraview.mexmaci64, which doesn't exist, so users get the "could not download" error. The standalone pyraview-macOS-ARM64.zip is arm64-only too. #33 addresses the MEX separately.

Out of scope and unchanged: PyPI publishing, py3-none wheels, Windows ARM64, the MATLAB jobs.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NDx6PbBsjPuycBAhTwC6Ho

Intel Macs had no wheel and fell back to the sdist, which needs CMake and a
C++ compiler at install time. GitHub has no Intel macOS runner any more, so
cibuildwheel now builds both x86_64 and arm64 on macos-latest: x86_64 is
cross-compiled via ARCHFLAGS (which scikit-build-core maps to
CMAKE_OSX_ARCHITECTURES) and its bundled-library test runs under Rosetta 2.

x86_64 wheels target macOS 10.13 (10.15 for CPython 3.14+); arm64 stays 11.0.
A new check script runs lipo/otool on the dylib in every macOS wheel and fails
if its architecture or minimum macOS disagrees with the wheel tag. A new
wheels.yml builds and checks the macOS wheels on PRs that touch the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NDx6PbBsjPuycBAhTwC6Ho
@stevevanhooser
stevevanhooser merged commit 3922bbe into main Oct 14, 2026
11 checks passed
@stevevanhooser
stevevanhooser deleted the ci/macos-x86_64-wheels branch October 14, 2026 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants