Skip to content

Commit 73a435b

Browse files
authored
Merge pull request #1266 from henryiii/henryiii/fix/crossplatform
fix: better cross-platform auto archs
2 parents 8b0aa9b + faa3ab4 commit 73a435b

File tree

2 files changed

+115
-3
lines changed

2 files changed

+115
-3
lines changed

cibuildwheel/architecture.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@
33
import functools
44
import platform as platform_module
55
import re
6+
import sys
67
from enum import Enum
78

89
from .typing import Final, Literal, PlatformName, assert_never
910

1011
PRETTY_NAMES: Final = {"linux": "Linux", "macos": "macOS", "windows": "Windows"}
1112

13+
ARCH_SYNONYMS: Final[list[dict[PlatformName, str | None]]] = [
14+
{"linux": "x86_64", "macos": "x86_64", "windows": "AMD64"},
15+
{"linux": "i686", "macos": None, "windows": "x86"},
16+
{"linux": "aarch64", "macos": "arm64", "windows": "ARM64"},
17+
]
18+
1219

1320
@functools.total_ordering
1421
class Architecture(Enum):
@@ -56,14 +63,37 @@ def parse_config(config: str, platform: PlatformName) -> set[Architecture]:
5663

5764
@staticmethod
5865
def auto_archs(platform: PlatformName) -> set[Architecture]:
59-
native_architecture = Architecture(platform_module.machine())
66+
native_machine = platform_module.machine()
67+
68+
# Cross-platform support. Used for --print-build-identifiers or docker builds.
69+
host_platform: PlatformName = (
70+
"windows"
71+
if sys.platform.startswith("win")
72+
else ("macos" if sys.platform.startswith("darwin") else "linux")
73+
)
74+
75+
native_architecture = Architecture(native_machine)
76+
77+
# we might need to rename the native arch to the machine we're running
78+
# on, as the same arch can have different names on different platforms
79+
if host_platform != platform:
80+
for arch_synonym in ARCH_SYNONYMS:
81+
if native_machine == arch_synonym.get(host_platform):
82+
synonym = arch_synonym[platform]
83+
84+
if synonym is None:
85+
# can't build anything on this platform
86+
return set()
87+
88+
native_architecture = Architecture(synonym)
89+
6090
result = {native_architecture}
6191

62-
if platform == "linux" and native_architecture == Architecture.x86_64:
92+
if platform == "linux" and Architecture.x86_64 in result:
6393
# x86_64 machines can run i686 containers
6494
result.add(Architecture.i686)
6595

66-
if platform == "windows" and native_architecture == Architecture.AMD64:
96+
if platform == "windows" and Architecture.AMD64 in result:
6797
result.add(Architecture.x86)
6898

6999
return result

unit_test/architecture_test.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from __future__ import annotations
2+
3+
import platform as platform_module
4+
import sys
5+
6+
import pytest
7+
8+
from cibuildwheel.architecture import Architecture
9+
10+
11+
@pytest.fixture(
12+
params=[
13+
pytest.param(("linux", "linux", "x86_64", "64"), id="linux-64"),
14+
pytest.param(("linux", "linux", "i686", "32"), id="linux-32"),
15+
pytest.param(("linux", "linux", "aarch64", "arm"), id="linux-arm"),
16+
pytest.param(("macos", "darwin", "x86_64", "64"), id="macos-64"),
17+
pytest.param(("macos", "darwin", "arm64", "arm"), id="macos-arm"),
18+
pytest.param(("windows", "win32", "x86", "32"), id="windows-32"),
19+
pytest.param(("windows", "win32", "AMD64", "64"), id="windows-64"),
20+
pytest.param(("windows", "win32", "ARM64", "arm"), id="windows-arm"),
21+
]
22+
)
23+
def platform_machine(request, monkeypatch):
24+
platform_name, platform_value, machine_value, machine_name = request.param
25+
monkeypatch.setattr(sys, "platform", platform_value)
26+
monkeypatch.setattr(platform_module, "machine", lambda: machine_value)
27+
return platform_name, machine_name
28+
29+
30+
def test_arch_auto(platform_machine):
31+
platform_name, machine_name = platform_machine
32+
33+
arch_set = Architecture.auto_archs("linux")
34+
expected = {
35+
"32": {Architecture.i686},
36+
"64": {Architecture.x86_64, Architecture.i686},
37+
"arm": {Architecture.aarch64},
38+
}
39+
assert arch_set == expected[machine_name]
40+
41+
arch_set = Architecture.auto_archs("macos")
42+
expected = {"32": set(), "64": {Architecture.x86_64}, "arm": {Architecture.arm64}}
43+
assert arch_set == expected[machine_name]
44+
45+
arch_set = Architecture.auto_archs("windows")
46+
expected = {
47+
"32": {Architecture.x86},
48+
"64": {Architecture.AMD64, Architecture.x86},
49+
"arm": {Architecture.ARM64},
50+
}
51+
assert arch_set == expected[machine_name]
52+
53+
54+
def test_arch_auto64(platform_machine):
55+
platform_name, machine_name = platform_machine
56+
57+
arch_set = Architecture.parse_config("auto64", "linux")
58+
expected = {"32": set(), "64": {Architecture.x86_64}, "arm": {Architecture.aarch64}}
59+
assert arch_set == expected[machine_name]
60+
61+
arch_set = Architecture.parse_config("auto64", "macos")
62+
expected = {"32": set(), "64": {Architecture.x86_64}, "arm": {Architecture.arm64}}
63+
assert arch_set == expected[machine_name]
64+
65+
arch_set = Architecture.parse_config("auto64", "windows")
66+
expected = {"32": set(), "64": {Architecture.AMD64}, "arm": {Architecture.ARM64}}
67+
assert arch_set == expected[machine_name]
68+
69+
70+
def test_arch_auto32(platform_machine):
71+
platform_name, machine_name = platform_machine
72+
73+
arch_set = Architecture.parse_config("auto32", "linux")
74+
expected = {"32": {Architecture.i686}, "64": {Architecture.i686}, "arm": set()}
75+
assert arch_set == expected[machine_name]
76+
77+
arch_set = Architecture.parse_config("auto32", "macos")
78+
assert arch_set == set()
79+
80+
arch_set = Architecture.parse_config("auto32", "windows")
81+
expected = {"32": {Architecture.x86}, "64": {Architecture.x86}, "arm": set()}
82+
assert arch_set == expected[machine_name]

0 commit comments

Comments
 (0)