Merge remote-tracking branch 'origin/master' into macos-universal2

# Conflicts:
#	cibuildwheel/macos.py
#	cibuildwheel/util.py
This commit is contained in:
Joe Rickerby
2021-01-06 21:39:32 +00:00
7 changed files with 90 additions and 46 deletions
+3 -3
View File
@@ -6,7 +6,7 @@ import traceback
from configparser import ConfigParser from configparser import ConfigParser
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional, overload from typing import Any, Dict, List, Optional, Set, overload
import cibuildwheel import cibuildwheel
import cibuildwheel.linux import cibuildwheel.linux
@@ -304,13 +304,13 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None:
def print_build_identifiers( def print_build_identifiers(
platform: str, build_selector: BuildSelector, architectures: List[Architecture] platform: str, build_selector: BuildSelector, architectures: Set[Architecture]
) -> None: ) -> None:
python_configurations: List[Any] = [] python_configurations: List[Any] = []
if platform == 'linux': if platform == 'linux':
python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures) python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures)
elif platform == 'windows': elif platform == 'windows':
python_configurations = cibuildwheel.windows.get_python_configurations(build_selector) python_configurations = cibuildwheel.windows.get_python_configurations(build_selector, architectures)
elif platform == 'macos': elif platform == 'macos':
python_configurations = cibuildwheel.macos.get_python_configurations(build_selector, architectures) python_configurations = cibuildwheel.macos.get_python_configurations(build_selector, architectures)
+6 -4
View File
@@ -2,13 +2,13 @@ import subprocess
import sys import sys
import textwrap import textwrap
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import List, NamedTuple from typing import List, NamedTuple, Set
from .docker_container import DockerContainer from .docker_container import DockerContainer
from .logger import log from .logger import log
from .util import ( from .util import (
Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
get_build_verbosity_extra_flags, prepare_command, allowed_architectures_check, get_build_verbosity_extra_flags, prepare_command,
) )
from .typing import PathOrStr from .typing import PathOrStr
@@ -24,7 +24,7 @@ class PythonConfiguration(NamedTuple):
def get_python_configurations( def get_python_configurations(
build_selector: BuildSelector, architectures: List[Architecture] build_selector: BuildSelector, architectures: Set[Architecture]
) -> List[PythonConfiguration]: ) -> List[PythonConfiguration]:
python_configurations = [ 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-cp27m'),
@@ -61,7 +61,7 @@ def get_python_configurations(
PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'), PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'),
] ]
# return all configurations whose arch is in our `architectures` list, # return all configurations whose arch is in our `architectures` set,
# and match the build/skip rules # and match the build/skip rules
return [ return [
c for c in python_configurations c for c in python_configurations
@@ -71,6 +71,8 @@ def get_python_configurations(
def build(options: BuildOptions) -> None: def build(options: BuildOptions) -> None:
allowed_architectures_check("linux", options)
try: try:
subprocess.check_output(['docker', '--version']) subprocess.check_output(['docker', '--version'])
except Exception: except Exception:
+5 -10
View File
@@ -5,15 +5,15 @@ import shutil
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import textwrap
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Tuple, cast from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Set, Tuple, cast
from .environment import ParsedEnvironment from .environment import ParsedEnvironment
from .logger import log from .logger import log
from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
download, get_build_verbosity_extra_flags, get_pip_script, download, get_build_verbosity_extra_flags, get_pip_script,
install_certifi_script, prepare_command, unwrap) install_certifi_script, prepare_command, allowed_architectures_check,
unwrap)
from .typing import PathOrStr from .typing import PathOrStr
@@ -47,7 +47,7 @@ class PythonConfiguration(NamedTuple):
def get_python_configurations(build_selector: BuildSelector, def get_python_configurations(build_selector: BuildSelector,
architectures: List[Architecture]) -> List[PythonConfiguration]: architectures: Set[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'),
@@ -238,12 +238,7 @@ def setup_python(python_configuration: PythonConfiguration,
def build(options: BuildOptions) -> None: def build(options: BuildOptions) -> None:
allowed_archs = {Architecture.x86_64, Architecture.universal2, Architecture.arm64} allowed_architectures_check("macos", options)
if any(a not in allowed_archs for a in options.architectures):
raise ValueError(textwrap.dedent(f'''
Invalid archs option {[a.value for a in options.architectures]}. macOS only supports
these architectures: {', '.join(a.value for a in allowed_archs)}.
'''))
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel')) temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
built_wheel_dir = temp_dir / 'built_wheel' built_wheel_dir = temp_dir / 'built_wheel'
+55 -11
View File
@@ -2,19 +2,26 @@ import os
import platform as platform_module import platform as platform_module
import re import re
import ssl import ssl
import sys
import functools
import textwrap import textwrap
import urllib.request import urllib.request
from enum import Enum from enum import Enum
from fnmatch import fnmatch from fnmatch import fnmatch
from pathlib import Path from pathlib import Path
from time import sleep from time import sleep
from typing import Dict, List, NamedTuple, Optional from typing import Dict, List, NamedTuple, Optional, Set
import certifi import certifi
from .environment import ParsedEnvironment from .environment import ParsedEnvironment
from .typing import PathOrStr from .typing import PathOrStr
if sys.version_info < (3, 8):
from typing_extensions import Literal
else:
from typing import Literal
def prepare_command(command: str, **kwargs: PathOrStr) -> str: def prepare_command(command: str, **kwargs: PathOrStr) -> str:
''' '''
@@ -124,7 +131,10 @@ class DependencyConstraints:
return f'{self.__class__.__name__}{self.base_file_path!r})' return f'{self.__class__.__name__}{self.base_file_path!r})'
@functools.total_ordering
class Architecture(Enum): class Architecture(Enum):
value: str
# mac/linux archs # mac/linux archs
x86_64 = 'x86_64' x86_64 = 'x86_64'
@@ -142,31 +152,35 @@ class Architecture(Enum):
x86 = 'x86' x86 = 'x86'
AMD64 = 'AMD64' AMD64 = 'AMD64'
# Allow this to be sorted
def __lt__(self, other: "Architecture") -> bool:
return self.value < other.value
@staticmethod @staticmethod
def parse_config(config: str, platform: str) -> 'List[Architecture]': def parse_config(config: str, platform: str) -> 'Set[Architecture]':
result = [] result = set()
for arch_str in re.split(r'[\s,]+', config): for arch_str in re.split(r'[\s,]+', config):
if arch_str == 'auto': if arch_str == 'auto':
result += Architecture.auto_archs(platform=platform) result |= Architecture.auto_archs(platform=platform)
else: else:
result.append(Architecture(arch_str)) result.add(Architecture(arch_str))
return result return result
@staticmethod @staticmethod
def auto_archs(platform: str) -> 'List[Architecture]': def auto_archs(platform: str) -> 'Set[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.add(Architecture.i686)
if platform == 'windows' and native_architecture == Architecture.AMD64: if platform == 'windows' and native_architecture == Architecture.AMD64:
result.append(Architecture.x86) result.add(Architecture.x86)
if platform == 'macos' and native_architecture == Architecture.arm64: if platform == 'macos' and native_architecture == Architecture.arm64:
# arm64 can build and test both archs of a universal2 wheel. # arm64 can build and test both archs of a universal2 wheel.
result.append(Architecture.universal2) result.add(Architecture.universal2)
return result return result
@@ -175,7 +189,7 @@ class BuildOptions(NamedTuple):
package_dir: Path package_dir: Path
output_dir: Path output_dir: Path
build_selector: BuildSelector build_selector: BuildSelector
architectures: List[Architecture] architectures: Set[Architecture]
environment: ParsedEnvironment environment: ParsedEnvironment
before_all: str before_all: str
before_build: Optional[str] before_build: Optional[str]
@@ -244,6 +258,36 @@ def detect_ci_provider() -> Optional[CIProvider]:
return None return None
PRETTY_NAMES = {'linux': 'Linux', 'macos': 'macOS', 'windows': 'Windows'}
ALLOWED_ARCHITECTURES = {
'linux': {Architecture.x86_64, Architecture.i686, Architecture.aarch64, Architecture.ppc64le, Architecture.s390x},
'macos': {Architecture.x86_64},
'windows': {Architecture.AMD64, Architecture.x86},
}
def allowed_architectures_check(
name: Literal['linux', 'macos', 'windows'],
options: BuildOptions,
) -> None:
allowed_architectures = ALLOWED_ARCHITECTURES[name]
msg = f'{PRETTY_NAMES[name]} only supports {sorted(allowed_architectures)} at the moment.'
if name != 'linux':
msg += ' If you want to set emulation architectures on Linux, use CIBW_ARCHS_LINUX instead.'
if not options.architectures <= allowed_architectures:
msg = f'Invalid archs option {options.architectures}. ' + msg
raise ValueError(msg)
if not options.architectures:
msg = 'Empty archs option set. ' + msg
raise ValueError(msg)
def unwrap(text: str) -> str: def unwrap(text: str) -> str:
''' '''
Unwraps multi-line text to a single line Unwraps multi-line text to a single line
+14 -12
View File
@@ -3,9 +3,8 @@ import shutil
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import textwrap
from pathlib import Path from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Sequence from typing import Dict, List, NamedTuple, Optional, Sequence, Set
from zipfile import ZipFile from zipfile import ZipFile
import toml import toml
@@ -14,7 +13,7 @@ from .environment import ParsedEnvironment
from .logger import log from .logger import log
from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
download, get_build_verbosity_extra_flags, get_pip_script, download, get_build_verbosity_extra_flags, get_pip_script,
prepare_command) prepare_command, allowed_architectures_check)
from .typing import PathOrStr from .typing import PathOrStr
IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists() IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
@@ -48,7 +47,12 @@ class PythonConfiguration(NamedTuple):
url: Optional[str] url: Optional[str]
def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfiguration]: def get_python_configurations(build_selector: BuildSelector, architectures: Set[Architecture]) -> List[PythonConfiguration]:
map_arch = {
'32': Architecture.x86,
'64': Architecture.AMD64,
}
python_configurations = [ python_configurations = [
# CPython # CPython
PythonConfiguration(version='2.7.18', arch='32', identifier='cp27-win32', url=None), PythonConfiguration(version='2.7.18', arch='32', identifier='cp27-win32', url=None),
@@ -75,7 +79,10 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
python_configurations = [c for c in python_configurations if not c.version.startswith('2.7')] python_configurations = [c for c in python_configurations if not c.version.startswith('2.7')]
# skip builds as required # skip builds as required
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) and map_arch[c.arch] in architectures
]
return python_configurations return python_configurations
@@ -202,12 +209,7 @@ def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None:
def build(options: BuildOptions) -> None: def build(options: BuildOptions) -> None:
if options.architectures != [Architecture.AMD64, Architecture.x86]: allowed_architectures_check("windows", options)
raise ValueError(textwrap.dedent(f'''
Invalid archs option {options.architectures}. Windows only supports 'amd64,x86' for the
moment. If you want to set emulation architectures on Linux, use CIBW_ARCHS_LINUX
instead.
'''))
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel')) temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
built_wheel_dir = temp_dir / 'built_wheel' built_wheel_dir = temp_dir / 'built_wheel'
@@ -220,7 +222,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)
shell(before_all_prepared, env=env) shell(before_all_prepared, 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)
+1
View File
@@ -31,6 +31,7 @@ install_requires =
bashlex!=0.13 bashlex!=0.13
toml toml
certifi certifi
typing_extensions; python_version < '3.8'
[options.package_data] [options.package_data]
cibuildwheel = resources/* cibuildwheel = resources/*
+6 -6
View File
@@ -75,9 +75,9 @@ def test_archs_default(platform, intercepted_build_args, monkeypatch):
build_options = intercepted_build_args.args[0] build_options = intercepted_build_args.args[0]
if platform == 'linux': if platform == 'linux':
assert build_options.architectures == [Architecture.x86_64, Architecture.i686] assert build_options.architectures == {Architecture.x86_64, Architecture.i686}
else: else:
assert build_options.architectures == [Architecture.x86_64] assert build_options.architectures == {Architecture.x86_64}
@pytest.mark.parametrize('use_env_var', [False, True]) @pytest.mark.parametrize('use_env_var', [False, True])
@@ -92,7 +92,7 @@ def test_archs_argument(platform, intercepted_build_args, monkeypatch, use_env_v
main() main()
build_options = intercepted_build_args.args[0] build_options = intercepted_build_args.args[0]
assert build_options.architectures == [Architecture.ppc64le] assert build_options.architectures == {Architecture.ppc64le}
def test_archs_platform_specific(platform, intercepted_build_args, monkeypatch): def test_archs_platform_specific(platform, intercepted_build_args, monkeypatch):
@@ -106,8 +106,8 @@ def test_archs_platform_specific(platform, intercepted_build_args, monkeypatch):
build_options = intercepted_build_args.args[0] build_options = intercepted_build_args.args[0]
if platform == 'linux': if platform == 'linux':
assert build_options.architectures == [Architecture.ppc64le] assert build_options.architectures == {Architecture.ppc64le}
elif platform == 'windows': elif platform == 'windows':
assert build_options.architectures == [Architecture.x86] assert build_options.architectures == {Architecture.x86}
elif platform == 'macos': elif platform == 'macos':
assert build_options.architectures == [Architecture.x86_64] assert build_options.architectures == {Architecture.x86_64}