Use the ARCHS option to select universal2/arm64 builds
This commit is contained in:
@@ -312,7 +312,7 @@ def print_build_identifiers(
|
|||||||
elif platform == 'windows':
|
elif platform == 'windows':
|
||||||
python_configurations = cibuildwheel.windows.get_python_configurations(build_selector)
|
python_configurations = cibuildwheel.windows.get_python_configurations(build_selector)
|
||||||
elif platform == 'macos':
|
elif platform == 'macos':
|
||||||
python_configurations = cibuildwheel.macos.get_python_configurations(build_selector)
|
python_configurations = cibuildwheel.macos.get_python_configurations(build_selector, architectures)
|
||||||
|
|
||||||
for config in python_configurations:
|
for config in python_configurations:
|
||||||
print(config.identifier)
|
print(config.identifier)
|
||||||
|
|||||||
+17
-14
@@ -46,7 +46,8 @@ class PythonConfiguration(NamedTuple):
|
|||||||
url: str
|
url: str
|
||||||
|
|
||||||
|
|
||||||
def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfiguration]:
|
def get_python_configurations(build_selector: BuildSelector,
|
||||||
|
architectures: List[Architecture]) -> List[PythonConfiguration]:
|
||||||
python_configurations = [
|
python_configurations = [
|
||||||
# CPython
|
# CPython
|
||||||
PythonConfiguration(version='2.7', identifier='cp27-macosx_x86_64', url='https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg'),
|
PythonConfiguration(version='2.7', identifier='cp27-macosx_x86_64', url='https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg'),
|
||||||
@@ -58,19 +59,22 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
|||||||
PythonConfiguration(version='3.9', identifier='cp39-macosx_universal2', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
|
PythonConfiguration(version='3.9', identifier='cp39-macosx_universal2', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
|
||||||
PythonConfiguration(version='3.9', identifier='cp39-macosx_arm64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
|
PythonConfiguration(version='3.9', identifier='cp39-macosx_arm64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
|
||||||
# PyPy
|
# PyPy
|
||||||
# TODO: may not support 11.0 yet
|
|
||||||
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'),
|
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'),
|
||||||
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'),
|
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'),
|
||||||
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
|
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# skip builds as required
|
# filter out configs that don't match any of the selected architectures
|
||||||
|
python_configurations = [c for c in python_configurations
|
||||||
|
if any(c.identifier.endswith(a.value) for a in architectures)]
|
||||||
|
|
||||||
|
# skip builds as required by BUILD/SKIP
|
||||||
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
||||||
|
|
||||||
if get_macos_version() >= (11, 0):
|
if get_macos_version() >= (11, 0):
|
||||||
# pypy doesn't work on macOS 11 yet
|
|
||||||
# See https://foss.heptapod.net/pypy/pypy/-/issues/3314
|
|
||||||
if any(c.identifier.startswith('pp') for c in python_configurations):
|
if any(c.identifier.startswith('pp') for c in python_configurations):
|
||||||
|
# pypy doesn't work on macOS 11 yet
|
||||||
|
# See https://foss.heptapod.net/pypy/pypy/-/issues/3314
|
||||||
log.warning(wrap_text('''
|
log.warning(wrap_text('''
|
||||||
PyPy is currently unsupported when building on macOS 11. To build macOS PyPy wheels,
|
PyPy is currently unsupported when building on macOS 11. To build macOS PyPy wheels,
|
||||||
build on an older OS, such as macOS 10.15. To silence this warning, deselect PyPy by
|
build on an older OS, such as macOS 10.15. To silence this warning, deselect PyPy by
|
||||||
@@ -81,14 +85,12 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
|||||||
if any(c.identifier.startswith('cp35') for c in python_configurations):
|
if any(c.identifier.startswith('cp35') for c in python_configurations):
|
||||||
# CPython 3.5 doesn't work on macOS 11
|
# CPython 3.5 doesn't work on macOS 11
|
||||||
log.warning(wrap_text('''
|
log.warning(wrap_text('''
|
||||||
CPython is unsupported when building on macOS 11. To build CPython 3.5 wheels, build
|
CPython 3.5 is unsupported when building on macOS 11. To build CPython 3.5 wheels,
|
||||||
on an older OS, such as macOS 10.15. To silence this warning, deselect CPython 3.5
|
build on an older OS, such as macOS 10.15. To silence this warning, deselect CPython
|
||||||
by adding "cp35-macosx_x86_64" to your CIBW_SKIP option.
|
3.5 by adding "cp35-macosx_x86_64" to your CIBW_SKIP option.
|
||||||
'''))
|
'''))
|
||||||
python_configurations = [c for c in python_configurations if not c.identifier.startswith('cp35')]
|
python_configurations = [c for c in python_configurations if not c.identifier.startswith('cp35')]
|
||||||
|
|
||||||
python_configurations = [c for c in python_configurations if not c.identifier.startswith('cp35')]
|
|
||||||
|
|
||||||
return python_configurations
|
return python_configurations
|
||||||
|
|
||||||
|
|
||||||
@@ -236,10 +238,11 @@ def setup_python(python_configuration: PythonConfiguration,
|
|||||||
|
|
||||||
|
|
||||||
def build(options: BuildOptions) -> None:
|
def build(options: BuildOptions) -> None:
|
||||||
if options.architectures != [Architecture.x86_64]:
|
allowed_archs = {Architecture.x86_64, Architecture.universal2, Architecture.arm64}
|
||||||
|
if set(options.architectures) <= allowed_archs:
|
||||||
raise ValueError(textwrap.dedent(f'''
|
raise ValueError(textwrap.dedent(f'''
|
||||||
Invalid archs option {options.architectures}. macOS only supports x86_64 for the moment.
|
Invalid archs option {options.architectures}. macOS only supports
|
||||||
If you want to set emulation architectures on Linux, use CIBW_ARCHS_LINUX instead.
|
these architectures: {', '.join(a.value for a in allowed_archs)}.
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
|
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
|
||||||
@@ -253,7 +256,7 @@ def build(options: BuildOptions) -> None:
|
|||||||
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
|
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
|
||||||
call([before_all_prepared], shell=True, env=env)
|
call([before_all_prepared], shell=True, env=env)
|
||||||
|
|
||||||
python_configurations = get_python_configurations(options.build_selector)
|
python_configurations = get_python_configurations(options.build_selector, options.architectures)
|
||||||
|
|
||||||
for config in python_configurations:
|
for config in python_configurations:
|
||||||
log.build_start(config.identifier)
|
log.build_start(config.identifier)
|
||||||
|
|||||||
@@ -127,11 +127,17 @@ class DependencyConstraints:
|
|||||||
class Architecture(Enum):
|
class Architecture(Enum):
|
||||||
# mac/linux archs
|
# mac/linux archs
|
||||||
x86_64 = 'x86_64'
|
x86_64 = 'x86_64'
|
||||||
|
|
||||||
|
# linux archs
|
||||||
i686 = 'i686'
|
i686 = 'i686'
|
||||||
aarch64 = 'aarch64'
|
aarch64 = 'aarch64'
|
||||||
ppc64le = 'ppc64le'
|
ppc64le = 'ppc64le'
|
||||||
s390x = 's390x'
|
s390x = 's390x'
|
||||||
|
|
||||||
|
# mac archs
|
||||||
|
universal2 = 'universal2'
|
||||||
|
arm64 = 'arm64'
|
||||||
|
|
||||||
# windows archs
|
# windows archs
|
||||||
x86 = 'x86'
|
x86 = 'x86'
|
||||||
AMD64 = 'AMD64'
|
AMD64 = 'AMD64'
|
||||||
@@ -150,11 +156,18 @@ class Architecture(Enum):
|
|||||||
def auto_archs(platform: str) -> 'List[Architecture]':
|
def auto_archs(platform: str) -> 'List[Architecture]':
|
||||||
native_architecture = Architecture(platform_module.machine())
|
native_architecture = Architecture(platform_module.machine())
|
||||||
result = [native_architecture]
|
result = [native_architecture]
|
||||||
|
|
||||||
if platform == 'linux' and native_architecture == Architecture.x86_64:
|
if platform == 'linux' and native_architecture == Architecture.x86_64:
|
||||||
# x86_64 machines can run i686 docker containers
|
# x86_64 machines can run i686 docker containers
|
||||||
result.append(Architecture.i686)
|
result.append(Architecture.i686)
|
||||||
|
|
||||||
if platform == 'windows' and native_architecture == Architecture.AMD64:
|
if platform == 'windows' and native_architecture == Architecture.AMD64:
|
||||||
result.append(Architecture.x86)
|
result.append(Architecture.x86)
|
||||||
|
|
||||||
|
if platform == 'macos' and native_architecture == Architecture.arm64:
|
||||||
|
# arm64 can build and test both archs of a universal2 wheel.
|
||||||
|
result.append(Architecture.universal2)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from . import test_projects, utils
|
||||||
|
|
||||||
|
basic_project = test_projects.new_c_project()
|
||||||
|
|
||||||
|
|
||||||
|
def test_cross_compiled_build(tmp_path):
|
||||||
|
if utils.platform != 'macos':
|
||||||
|
pytest.skip('this test is only relevant to macos')
|
||||||
|
|
||||||
|
project_dir = tmp_path / 'project'
|
||||||
|
basic_project.generate(project_dir)
|
||||||
|
|
||||||
|
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||||
|
'CIBW_ARCHS': 'x86_64, universal2, arm64',
|
||||||
|
})
|
||||||
|
|
||||||
|
expected_wheels = (
|
||||||
|
utils.expected_wheels('spam', '0.1.0', machine_arch='x86_64')
|
||||||
|
+ utils.expected_wheels('spam', '0.1.0', machine_arch='arm64')
|
||||||
|
)
|
||||||
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
# TODO: add a TEST_COMMAND test when using cross-compiling
|
||||||
+27
-7
@@ -100,9 +100,11 @@ def expected_wheels(package_name, package_version, manylinux_versions=None,
|
|||||||
if platform == 'linux':
|
if platform == 'linux':
|
||||||
python_abi_tags.append('cp27-cp27mu') # python 2.7 has 2 different ABI on manylinux
|
python_abi_tags.append('cp27-cp27mu') # python 2.7 has 2 different ABI on manylinux
|
||||||
|
|
||||||
if platform == 'macos':
|
if platform == 'macos' and get_macos_version() >= (11, 0):
|
||||||
# TODO: perhaps drop Python 3.5 across the board?
|
# CPython 3.5 doesn't work on macOS 11.
|
||||||
python_abi_tags.remove('cp35-cp35m')
|
python_abi_tags.remove('cp35-cp35m')
|
||||||
|
# pypy not supported on macOS 11.
|
||||||
|
python_abi_tags = [t for t in python_abi_tags if not t.startswith('pp')]
|
||||||
|
|
||||||
wheels = []
|
wheels = []
|
||||||
|
|
||||||
@@ -129,11 +131,17 @@ def expected_wheels(package_name, package_version, manylinux_versions=None,
|
|||||||
|
|
||||||
elif platform == 'macos':
|
elif platform == 'macos':
|
||||||
if python_abi_tag == 'cp39-cp39':
|
if python_abi_tag == 'cp39-cp39':
|
||||||
platform_tags = [
|
if machine_arch == 'x86_64':
|
||||||
f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64',
|
platform_tags = [
|
||||||
f'macosx_{macosx_deployment_target.replace(".", "_")}_universal2.macosx_11_0_universal2',
|
f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64',
|
||||||
'macosx_11_0_arm64',
|
]
|
||||||
]
|
elif machine_arch == 'arm64':
|
||||||
|
platform_tags = [
|
||||||
|
f'macosx_{macosx_deployment_target.replace(".", "_")}_universal2.macosx_11_0_universal2',
|
||||||
|
# macosx_deployment_target is ignored on arm64, because arm64 isn't supported on
|
||||||
|
# macOS earlier than 11.0
|
||||||
|
'macosx_11_0_arm64',
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
platform_tags = [
|
platform_tags = [
|
||||||
f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64',
|
f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64',
|
||||||
@@ -152,6 +160,18 @@ def expected_wheels(package_name, package_version, manylinux_versions=None,
|
|||||||
return wheels
|
return wheels
|
||||||
|
|
||||||
|
|
||||||
|
def get_macos_version():
|
||||||
|
'''
|
||||||
|
Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
|
||||||
|
|
||||||
|
These tuples can be used in comparisons, e.g.
|
||||||
|
(10, 14) <= (11, 0) == True
|
||||||
|
(11, 2) <= (11, 0) != True
|
||||||
|
'''
|
||||||
|
version_str, _, _ = pm.mac_ver()
|
||||||
|
return tuple(map(int, version_str.split(".")[:2]))
|
||||||
|
|
||||||
|
|
||||||
platform = None
|
platform = None
|
||||||
|
|
||||||
if 'CIBW_PLATFORM' in os.environ:
|
if 'CIBW_PLATFORM' in os.environ:
|
||||||
|
|||||||
Reference in New Issue
Block a user