From 746aff4b98b4e26f11cae3ef314fa61f18bf9ba5 Mon Sep 17 00:00:00 2001 From: Lawrence D'Anna <64555057+lawrence-danna-apple@users.noreply.github.com> Date: Tue, 24 Nov 2020 14:07:51 -0800 Subject: [PATCH] add support for macos 11.0, arm64, universal2 (#319) --- packaging/tags.py | 52 +++++++++++++++++++++++++++++-------- tests/test_tags.py | 64 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/packaging/tags.py b/packaging/tags.py index 289ed5c1..842447d8 100644 --- a/packaging/tags.py +++ b/packaging/tags.py @@ -407,7 +407,12 @@ def _mac_binary_formats(version, cpu_arch): return [] formats.extend(["fat32", "fat"]) - formats.append("universal") + if cpu_arch in {"arm64", "x86_64"}: + formats.append("universal2") + + if cpu_arch in {"x86_64", "i386", "ppc64", "ppc"}: + formats.append("universal") + return formats @@ -430,15 +435,42 @@ def mac_platforms(version=None, arch=None): arch = _mac_arch(cpu_arch) else: arch = arch - for minor_version in range(version[1], -1, -1): - compat_version = version[0], minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) + + if (10, 0) <= version and version < (11, 0): + # Prior to Mac OS 11, each yearly release of Mac OS bumped the + # "minor" version number. The major version was always 10. + for minor_version in range(version[1], -1, -1): + compat_version = 10, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield "macosx_{major}_{minor}_{binary_format}".format( + major=10, minor=minor_version, binary_format=binary_format + ) + + if version >= (11, 0): + # Starting with Mac OS 11, each yearly release bumps the major version + # number. The minor versions are now the midyear updates. + for major_version in range(version[0], 10, -1): + compat_version = major_version, 0 + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield "macosx_{major}_{minor}_{binary_format}".format( + major=major_version, minor=0, binary_format=binary_format + ) + + if version >= (11, 0) and arch == "x86_64": + # Mac OS 11 on x86_64 is compatible with binaries from previous releases. + # Arm64 support was introduced in 11.0, so no Arm binaries from previous + # releases exist. + for minor_version in range(16, 3, -1): + compat_version = 10, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield "macosx_{major}_{minor}_{binary_format}".format( + major=compat_version[0], + minor=compat_version[1], + binary_format=binary_format, + ) # From PEP 513, PEP 600 diff --git a/tests/test_tags.py b/tests/test_tags.py index e9ea3343..68b109a8 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -225,21 +225,37 @@ def test_architectures(self, arch, is_32bit, expected): @pytest.mark.parametrize( "version,arch,expected", [ - ((10, 17), "x86_64", ["x86_64", "intel", "fat64", "fat32", "universal"]), - ((10, 4), "x86_64", ["x86_64", "intel", "fat64", "fat32", "universal"]), + ( + (10, 15), + "x86_64", + ["x86_64", "intel", "fat64", "fat32", "universal2", "universal"], + ), + ( + (10, 4), + "x86_64", + ["x86_64", "intel", "fat64", "fat32", "universal2", "universal"], + ), ((10, 3), "x86_64", []), - ((10, 17), "i386", ["i386", "intel", "fat32", "fat", "universal"]), + ((10, 15), "i386", ["i386", "intel", "fat32", "fat", "universal"]), ((10, 4), "i386", ["i386", "intel", "fat32", "fat", "universal"]), ((10, 3), "i386", []), - ((10, 17), "ppc64", []), + ((10, 15), "ppc64", []), ((10, 6), "ppc64", []), ((10, 5), "ppc64", ["ppc64", "fat64", "universal"]), ((10, 3), "ppc64", []), - ((10, 17), "ppc", []), + ((10, 15), "ppc", []), ((10, 7), "ppc", []), ((10, 6), "ppc", ["ppc", "fat32", "fat", "universal"]), ((10, 0), "ppc", ["ppc", "fat32", "fat", "universal"]), - ((11, 0), "riscv", ["riscv", "universal"]), + ((11, 0), "riscv", ["riscv"]), + ( + (11, 0), + "x86_64", + ["x86_64", "intel", "fat64", "fat32", "universal2", "universal"], + ), + ((11, 0), "arm64", ["arm64", "universal2"]), + ((11, 1), "arm64", ["arm64", "universal2"]), + ((12, 0), "arm64", ["arm64", "universal2"]), ], ) def test_binary_formats(self, version, arch, expected): @@ -271,18 +287,52 @@ def test_mac_platforms(self): "macosx_10_5_intel", "macosx_10_5_fat64", "macosx_10_5_fat32", + "macosx_10_5_universal2", "macosx_10_5_universal", "macosx_10_4_x86_64", "macosx_10_4_intel", "macosx_10_4_fat64", "macosx_10_4_fat32", + "macosx_10_4_universal2", "macosx_10_4_universal", ] - assert len(list(tags.mac_platforms((10, 17), "x86_64"))) == 14 * 5 + assert len(list(tags.mac_platforms((10, 17), "x86_64"))) == 14 * 6 assert not list(tags.mac_platforms((10, 0), "x86_64")) + @pytest.mark.parametrize("major,minor", [(11, 0), (11, 3), (12, 0), (12, 3)]) + def test_macos_11(self, major, minor): + platforms = list(tags.mac_platforms((major, minor), "x86_64")) + assert "macosx_11_0_arm64" not in platforms + assert "macosx_11_0_x86_64" in platforms + assert "macosx_11_3_x86_64" not in platforms + assert "macosx_11_0_universal" in platforms + assert "macosx_11_0_universal2" in platforms + # Mac OS "10.16" is the version number that binaries compiled against an old + # (pre 11.0) SDK will see. It can also be enabled explicitly for a process + # with the environment variable SYSTEM_VERSION_COMPAT=1. + assert "macosx_10_16_x86_64" in platforms + assert "macosx_10_15_x86_64" in platforms + assert "macosx_10_4_x86_64" in platforms + assert "macosx_10_3_x86_64" not in platforms + if major >= 12: + assert "macosx_12_0_x86_64" in platforms + assert "macosx_12_0_universal" in platforms + assert "macosx_12_0_universal2" in platforms + + platforms = list(tags.mac_platforms((major, minor), "arm64")) + assert "macosx_11_0_arm64" in platforms + assert "macosx_11_3_arm64" not in platforms + assert "macosx_11_0_universal" not in platforms + assert "macosx_11_0_universal2" in platforms + assert "macosx_10_15_x86_64" not in platforms + assert "macosx_10_4_x86_64" not in platforms + assert "macosx_10_3_x86_64" not in platforms + if major >= 12: + assert "macosx_12_0_arm64" in platforms + assert "macosx_12_0_universal2" in platforms + class TestManylinuxPlatform: def teardown_method(self):