From ec99c01b2f4908316f5caccee7ce4481421002b5 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Wed, 16 Dec 2020 23:17:51 +0000 Subject: [PATCH] Allow architecture selection --- cibuildwheel/__main__.py | 26 +++++++++++++++++++++++--- cibuildwheel/linux.py | 22 ++++++++++++++-------- cibuildwheel/util.py | 9 +++++++++ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index e171ab20..4486aee8 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -17,6 +17,7 @@ from cibuildwheel.environment import ( parse_environment, ) from cibuildwheel.util import ( + Architecture, BuildOptions, BuildSelector, DependencyConstraints, @@ -67,6 +68,22 @@ def main() -> None: run in Windows, and it will build and test for all versions of Python. Default: auto. ''') + + parser.add_argument( + '-a', + '--architectures', + choices=[arch.value for arch in Architecture], + default=[], + help=''' + Comma-separated list of CPU architectures to build for. + If unspecified, builds the architectures natively supported + on this machine. Set this option to build an architecture + via emulation, for example, using binfmt_misc and qemu. + ''', + action="extend", + nargs="+", + type=Architecture, + ) parser.add_argument('--output-dir', default=os.environ.get('CIBW_OUTPUT_DIR', 'wheelhouse'), help='Destination folder for the wheels.') @@ -169,7 +186,7 @@ def main() -> None: exit(2) if args.print_build_identifiers: - print_build_identifiers(platform, build_selector) + print_build_identifiers(platform, build_selector, args.architectures) exit(0) manylinux_images: Optional[Dict[str, str]] = None @@ -202,6 +219,7 @@ def main() -> None: manylinux_images[build_platform] = image build_options = BuildOptions( + architectures=args.architectures, package_dir=package_dir, output_dir=output_dir, test_command=test_command, @@ -284,10 +302,12 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None: print('\nHere we go!\n') -def print_build_identifiers(platform: str, build_selector: BuildSelector) -> None: +def print_build_identifiers( + platform: str, build_selector: BuildSelector, architectures: List[Architecture] +) -> None: python_configurations: List[Any] = [] if platform == 'linux': - python_configurations = cibuildwheel.linux.get_python_configurations(build_selector) + python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures) elif platform == 'windows': python_configurations = cibuildwheel.windows.get_python_configurations(build_selector) elif platform == 'macos': diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 57e83803..b27b4c65 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -9,18 +9,18 @@ from typing import List, NamedTuple, Union from .docker_container import DockerContainer from .logger import log -from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, - get_build_verbosity_extra_flags, prepare_command) +from .util import ( + Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, + get_build_verbosity_extra_flags, prepare_command, +) re_pattern = re.compile(r'[cp]p\d{2}-manylinux_(\w*)') -def matches_platform(identifier: str, supported_platforms: List[str]) -> bool: +def matches_platform(identifier: str, supported_platforms: List[Architecture]) -> bool: matched_architecture = re_pattern.search(identifier) id_architecture = matched_architecture.group(1) if matched_architecture else '' - # x86_64 machines can run i686 docker containers - id_architecture = id_architecture if id_architecture == 'i686' else 'x86_64' return id_architecture in supported_platforms @@ -34,7 +34,9 @@ class PythonConfiguration(NamedTuple): return PurePath(self.path_str) -def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfiguration]: +def get_python_configurations( + build_selector: BuildSelector, architectures: List[Architecture] +) -> List[PythonConfiguration]: python_configurations = [ PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27m'), PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27mu'), @@ -71,7 +73,11 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi ] # skip builds as required - target_archs = [platform.machine()] + target_archs = architectures or [Architecture(platform.machine())] + # x86_64 machines can run i686 docker containers + if Architecture.i686 not in target_archs and Architecture.x86_64 in target_archs: + target_archs.append(Architecture.i686) + print("matching platforms to architectures: ", target_archs) return [ c for c in python_configurations if matches_platform(c.identifier, target_archs) @@ -90,7 +96,7 @@ def build(options: BuildOptions) -> None: exit(2) assert options.manylinux_images is not None - python_configurations = get_python_configurations(options.build_selector) + python_configurations = get_python_configurations(options.build_selector, options.architectures) platforms = [ ('cp', 'manylinux_x86_64', options.manylinux_images['x86_64']), ('cp', 'manylinux_i686', options.manylinux_images['i686']), diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 87ce5d17..80ae3a36 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -121,7 +121,16 @@ class DependencyConstraints: return f'{self.__class__.__name__}{self.base_file_path!r})' +class Architecture(str, Enum): + x86_64 = 'x86_64' + i686 = 'i686' + aarch64 = 'aarch64' + ppc64le = 'ppc64le' + s390x = 's390x' + + class BuildOptions(NamedTuple): + architectures: List[Architecture] package_dir: Path output_dir: Path build_selector: BuildSelector