Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
import cibuildwheel.macos
import cibuildwheel.windows
from cibuildwheel.environment import EnvironmentParseError, parse_environment
from cibuildwheel.typing import PLATFORMS, PlatStr, assert_never
from cibuildwheel.util import (
Architecture,
BuildOptions,
BuildSelector,
DependencyConstraints,
Unbuffered,
detect_ci_provider,
read_python_configs,
resources_dir,
)

Expand Down Expand Up @@ -46,6 +48,8 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None


def main() -> None:
platform: PlatStr

parser = argparse.ArgumentParser(
description='Build wheels for all the platforms.',
epilog='''
Expand Down Expand Up @@ -120,15 +124,21 @@ def main() -> None:
file=sys.stderr)
exit(2)

if platform not in PLATFORMS:
print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr)
exit(2)

package_dir = Path(args.package_dir)
output_dir = Path(args.output_dir)

if platform == 'linux':
repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}'
elif platform == 'macos':
repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel --require-archs x86_64 -w {dest_dir} {wheel}'
else:
elif platform == 'windows':
repair_command_default = ''
else:
assert_never(platform)

build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
Expand Down Expand Up @@ -215,6 +225,8 @@ def main() -> None:

manylinux_images[build_platform] = image

python_configs = read_python_configs(resources_dir / 'build-platforms.toml', platform)

build_options = BuildOptions(
architectures=archs,
package_dir=package_dir,
Expand All @@ -231,6 +243,7 @@ def main() -> None:
environment=environment,
dependency_constraints=dependency_constraints,
manylinux_images=manylinux_images,
python_configs=python_configs,
)

# Python is buffering by default when running on the CI platforms, giving problems interleaving subprocess call output with unflushed calls to 'print'
Expand All @@ -248,8 +261,7 @@ def main() -> None:
elif platform == 'macos':
cibuildwheel.macos.build(build_options)
else:
print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr)
exit(2)
assert_never(platform)


def detect_obsolete_options() -> None:
Expand Down Expand Up @@ -302,13 +314,16 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None:
def print_build_identifiers(
platform: str, build_selector: BuildSelector, architectures: Set[Architecture]
) -> None:

python_configs = read_python_configs(resources_dir / "build-platforms.toml", platform)

python_configurations: List[Any] = []
if platform == 'linux':
python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures)
python_configurations = cibuildwheel.linux.get_python_configurations(python_configs, build_selector, architectures)
elif platform == 'windows':
python_configurations = cibuildwheel.windows.get_python_configurations(build_selector, architectures)
python_configurations = cibuildwheel.windows.get_python_configurations(python_configs, build_selector, architectures)
elif platform == 'macos':
python_configurations = cibuildwheel.macos.get_python_configurations(build_selector)
python_configurations = cibuildwheel.macos.get_python_configurations(python_configs, build_selector)

for config in python_configurations:
print(config.identifier)
Expand Down
44 changes: 7 additions & 37 deletions cibuildwheel/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
import textwrap
from pathlib import Path, PurePath
from typing import List, NamedTuple, Set
from typing import Dict, List, NamedTuple, Set

from .docker_container import DockerContainer
from .logger import log
Expand All @@ -29,42 +29,12 @@ def path(self) -> PurePath:


def get_python_configurations(
build_selector: BuildSelector, architectures: Set[Architecture]
python_configs: List[Dict[str, str]],
build_selector: BuildSelector,
architectures: Set[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'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_x86_64', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_x86_64', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_x86_64', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_x86_64', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_x86_64', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27m'),
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27mu'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_i686', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_i686', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_i686', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_i686', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_i686', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='2.7', identifier='pp27-manylinux_x86_64', path_str='/opt/python/pp27-pypy_73'),
PythonConfiguration(version='3.6', identifier='pp36-manylinux_x86_64', path_str='/opt/python/pp36-pypy36_pp73'),
PythonConfiguration(version='3.7', identifier='pp37-manylinux_x86_64', path_str='/opt/python/pp37-pypy37_pp73'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_aarch64', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_aarch64', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_aarch64', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_aarch64', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_aarch64', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_ppc64le', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_ppc64le', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_ppc64le', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_ppc64le', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_ppc64le', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_s390x', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_s390x', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_s390x', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_s390x', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'),
]

python_configurations = [PythonConfiguration(**item) for item in python_configs]

# return all configurations whose arch is in our `architectures` set,
# and match the build/skip rules
Expand All @@ -88,7 +58,7 @@ def build(options: BuildOptions) -> None:
exit(2)

assert options.manylinux_images is not None
python_configurations = get_python_configurations(options.build_selector, options.architectures)
python_configurations = get_python_configurations(options.python_configs, options.build_selector, options.architectures)
platforms = [
('cp', 'manylinux_x86_64', options.manylinux_images['x86_64']),
('cp', 'manylinux_i686', options.manylinux_images['i686']),
Expand Down
21 changes: 6 additions & 15 deletions cibuildwheel/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,11 @@ class PythonConfiguration(NamedTuple):
url: str


def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfiguration]:
python_configurations = [
# 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='3.5', identifier='cp35-macosx_x86_64', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'),
PythonConfiguration(version='3.6', identifier='cp36-macosx_x86_64', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg'),
PythonConfiguration(version='3.7', identifier='cp37-macosx_x86_64', url='https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg'),
PythonConfiguration(version='3.8', identifier='cp38-macosx_x86_64', url='https://www.python.org/ftp/python/3.8.7/python-3.8.7-macosx10.9.pkg'),
PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg'),
# PyPy
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.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
]
def get_python_configurations(
python_configs: List[Dict[str, str]],
build_selector: BuildSelector) -> List[PythonConfiguration]:

python_configurations = [PythonConfiguration(**item) for item in python_configs]

# skip builds as required
return [c for c in python_configurations if build_selector(c.identifier)]
Expand Down Expand Up @@ -207,7 +198,7 @@ def build(options: BuildOptions) -> None:
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
call([before_all_prepared], shell=True, env=env)

python_configurations = get_python_configurations(options.build_selector)
python_configurations = get_python_configurations(options.python_configs, options.build_selector)

for config in python_configurations:
log.build_start(config.identifier)
Expand Down
63 changes: 63 additions & 0 deletions cibuildwheel/resources/build-platforms.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[tool.cibw.build-platforms]
linux = [
{ identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27m" },
{ identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27mu" },
{ identifier = "cp35-manylinux_x86_64", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27m" },
{ identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27mu" },
{ identifier = "cp35-manylinux_i686", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "pp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/pp27-pypy_73" },
{ identifier = "pp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/pp36-pypy36_pp73" },
{ identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
{ identifier = "cp35-manylinux_aarch64", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp35-manylinux_ppc64le", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp35-manylinux_s390x", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" },
]
macos = [
{ identifier = "cp27-macosx_x86_64", version = "2.7", url = "https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg" },
{ identifier = "cp35-macosx_x86_64", version = "3.5", url = "https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg" },
{ identifier = "cp36-macosx_x86_64", version = "3.6", url = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg" },
{ identifier = "cp37-macosx_x86_64", version = "3.7", url = "https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg" },
{ identifier = "cp38-macosx_x86_64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.7/python-3.8.7-macosx10.9.pkg" },
{ identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg" },
{ identifier = "pp27-macosx_x86_64", version = "2.7", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2" },
{ identifier = "pp36-macosx_x86_64", version = "3.6", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2" },
{ identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2" },
]
windows = [
{ identifier = "cp27-win32", version = "2.7.18", arch = "32" },
{ identifier = "cp27-win_amd64", version = "2.7.18", arch = "64" },
{ identifier = "cp35-win32", version = "3.5.4", arch = "32" },
{ identifier = "cp35-win_amd64", version = "3.5.4", arch = "64" },
{ identifier = "cp36-win32", version = "3.6.8", arch = "32" },
{ identifier = "cp36-win_amd64", version = "3.6.8", arch = "64" },
{ identifier = "cp37-win32", version = "3.7.9", arch = "32" },
{ identifier = "cp37-win_amd64", version = "3.7.9", arch = "64" },
{ identifier = "cp38-win32", version = "3.8.7", arch = "32" },
{ identifier = "cp38-win_amd64", version = "3.8.7", arch = "64" },
{ identifier = "cp39-win32", version = "3.9.1", arch = "32" },
{ identifier = "cp39-win_amd64", version = "3.9.1", arch = "64" },
{ identifier = "pp27-win32", version = "2.7", arch = "32", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip" },
{ identifier = "pp36-win32", version = "3.6", arch = "32", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip" },
{ identifier = "pp37-win32", version = "3.7", arch = "32", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip" },
]
17 changes: 16 additions & 1 deletion cibuildwheel/typing.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
import os
import subprocess
from typing import TYPE_CHECKING, Union
import sys
from typing import TYPE_CHECKING, NoReturn, Set, Union

if sys.version_info < (3, 8):
from typing_extensions import Final, Literal
else:
from typing import Final, Literal


if TYPE_CHECKING:
PopenBytes = subprocess.Popen[bytes]
PathOrStr = Union[str, os.PathLike[str]]
else:
PopenBytes = subprocess.Popen
PathOrStr = Union[str, "os.PathLike[str]"]


PlatStr = Literal["linux", "macos", "windows"]
PLATFORMS: Final[Set[PlatStr]] = {"linux", "macos", "windows"}


def assert_never(value: NoReturn) -> NoReturn:
assert False, f'Unhandled value: {value} ({type(value).__name__})' # noqa: B011
22 changes: 12 additions & 10 deletions cibuildwheel/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import platform as platform_module
import re
import ssl
import sys
import textwrap
import urllib.request
from enum import Enum
Expand All @@ -13,14 +12,10 @@
from typing import Dict, List, NamedTuple, Optional, Set

import certifi
import toml

from .environment import ParsedEnvironment
from .typing import PathOrStr

if sys.version_info < (3, 8):
from typing_extensions import Literal
else:
from typing import Literal
from .typing import PathOrStr, PlatStr


def prepare_command(command: str, **kwargs: PathOrStr) -> str:
Expand All @@ -42,6 +37,12 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]:
return []


def read_python_configs(input_path: PathOrStr, config: str) -> List[Dict[str, str]]:
loaded_file = toml.load(input_path)
results: List[Dict[str, str]] = list(loaded_file["tool"]["cibw"]["build-platforms"][config])
return results


class BuildSelector:
def __init__(self, build_config: str, skip_config: str):
self.build_patterns = build_config.split()
Expand Down Expand Up @@ -151,7 +152,7 @@ def __lt__(self, other: "Architecture") -> bool:
return self.value < other.value

@staticmethod
def parse_config(config: str, platform: str) -> 'Set[Architecture]':
def parse_config(config: str, platform: PlatStr) -> 'Set[Architecture]':
result = set()
for arch_str in re.split(r'[\s,]+', config):
if arch_str == 'auto':
Expand All @@ -161,7 +162,7 @@ def parse_config(config: str, platform: str) -> 'Set[Architecture]':
return result

@staticmethod
def auto_archs(platform: str) -> 'Set[Architecture]':
def auto_archs(platform: PlatStr) -> 'Set[Architecture]':
native_architecture = Architecture(platform_module.machine())
result = {native_architecture}
if platform == 'linux' and native_architecture == Architecture.x86_64:
Expand All @@ -188,6 +189,7 @@ class BuildOptions(NamedTuple):
test_requires: List[str]
test_extras: str
build_verbosity: int
python_configs: List[Dict[str, str]]


resources_dir = Path(__file__).resolve().parent / 'resources'
Expand Down Expand Up @@ -255,7 +257,7 @@ def detect_ci_provider() -> Optional[CIProvider]:


def allowed_architectures_check(
name: Literal['linux', 'macos', 'windows'],
name: PlatStr,
options: BuildOptions,
) -> None:

Expand Down
Loading