fix(macos): wrap before_build with arch -x86_64 under Rosetta - #2921
Closed
henryiii wants to merge 1 commit into
Closed
fix(macos): wrap before_build with arch -x86_64 under Rosetta#2921henryiii wants to merge 1 commit into
henryiii wants to merge 1 commit into
Conversation
When building x86_64 wheels on an arm64 host, the test loop already runs before_test (and the test command) under an `arch -x86_64` prefix so that arch-probing tooling sees x86_64, but before_build was run via a plain `shell()` with no prefix. This made before_build/before_all behave differently from before_test on arm64-on-x86_64 (Rosetta) builds, which NumPy hit after the macos-13 runner deprecation. Extract the prefix computation into a shared `rosetta_arch_prefix` helper and use it for both the build and test paths. before_build is now wrapped for x86_64-only configs on an arm64 host; universal2 builds compile both arches in one ARCHFLAGS invocation and have no single correct prefix, so they remain unwrapped. before_all is left unwrapped for now (open question for maintainers). Closes pypa#2592 Assisted-by: ClaudeCode:claude-opus-4.8
henryiii
force-pushed
the
fix/macos-before-build-rosetta-wrap
branch
from
June 17, 2026 02:25
8e38c4d to
68a7b3f
Compare
Contributor
|
I'm not sure the conclusion of that issue thread #2592 was to emulate the before-build calls. There is indeed an inconsistency between build and test phases (cross-compile vs emulation) but isn't it worse to run before-build under emulation and then the build under the native arch? |
Contributor
Author
|
Okay, I wasn't sure. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI text below 🤖
Problem
On a macOS arm64 host building x86_64 wheels via Rosetta (common now that GHA deprecated
macos-13), the command hooks were wrapped witharch -x86_64inconsistently:before_testand the test command run underarch -x86_64(test loop:shell_with_arch = functools.partial(call, *arch_prefix, "/bin/sh", "-c")witharch_prefix = ["arch", "-x86_64"]).before_buildran via a plainshell(before_build_prepared, env=env)— no prefix.The wheel itself still cross-compiles via
ARCHFLAGS, but hooks that probe the architecture or invoke arch-specific tooling (platform.machine(),uname -m, compilers, etc.) behaved differently inbefore_buildvsbefore_test. The NumPy maintainers hit this (#2592).Fix
rosetta_arch_prefix(machine_arch, target_arch)so the build and test paths stay in sync.before_buildwitharch -x86_64when the host is arm64 and the build target is x86_64-only, mirroring the test loop.[]for native and the previously-handled cases).The native paths (arm64-on-arm64, x86_64-on-x86_64) are unchanged: the helper returns an empty prefix, so
before_buildstill goes through plainshell().Design decisions
ARCHFLAGS="-arch arm64 -arch x86_64". There is no singlearchprefix that is correct for that hook, so I left universal2 unwrapped (runs natively as arm64). Forcingarch -x86_64would be wrong for the arm64 slice. This matches how the build itself is invoked (one process, both arches).python_configurations[0], which does not necessarily represent the arch of every build in a mixed selection. Wrapping it based on the first config could be misleading. Tradeoff noted below as an open question.Open questions for maintainers
before_buildfor x86_64-only configs on arm64 hosts, but not universal2. Is leaving universal2 native correct, or would you prefer wrapping it as the native arch explicitly (a no-op today) for clarity?before_allalso be wrapped? If so, based on what — the first config's arch, or only when all selected configs target x86_64? Or leave it native (current behavior)?Tests
Added
unit_test/macos_rosetta_test.pycoveringrosetta_arch_prefixfor the arm64->x86_64 (Rosetta), native, and unsupported-direction cases. The wrapping wiring insidebuild()itself isn't unit-testable without a real cross-arch build (it requires real Python.org installs and Rosetta); this is noted as a limitation.uv run pytest unit_test-> 795 passed. Ruff + mypy (strict) clean on the changed file.Closes #2592