Skip to content
Merged
54 changes: 43 additions & 11 deletions packaging/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ def _mac_binary_formats(version, cpu_arch):
if cpu_arch == "x86_64":
if version < (10, 4):
return []
formats.extend(["intel", "fat64", "fat32"])
formats.extend(["intel", "fat64", "fat32", "universal2"])

elif cpu_arch == "i386":
if version < (10, 4):
Expand All @@ -407,7 +407,12 @@ def _mac_binary_formats(version, cpu_arch):
return []
formats.extend(["fat32", "fat"])

formats.append("universal")
elif cpu_arch == "arm64":
formats.append("universal2")

if cpu_arch in {"x86_64", "i386", "ppc64", "ppc"}:
formats.append("universal")

return formats


Expand All @@ -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(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Mac OS X" was the name of the 10.x series. It was changed to "macOS" in 2016. Maybe it's time we do the switch for the tag too starting with 11.x? (could it somehow break backwards compatibility?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the tag format would probably require a PEP.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against changing the tag. This is bound to break stuff and has limited advantages.

In hindsight we should have set the tag to "macos" when we introduced this, but at that time "macosx" was the better choice (esp. because Mac OS 9 was still alive at that time).

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
Expand Down
67 changes: 63 additions & 4 deletions tests/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,16 @@ 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, 17),
"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, 4), "i386", ["i386", "intel", "fat32", "fat", "universal"]),
Expand All @@ -239,7 +247,13 @@ def test_architectures(self, arch, is_32bit, expected):
((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"]),
],
)
def test_binary_formats(self, version, arch, expected):
Expand Down Expand Up @@ -271,18 +285,63 @@ 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"))

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

def test_macos_11(self):
self._test_macos_11(11, 0)

def test_macos_11_3(self):
self._test_macos_11(11, 3)

def test_macos_12(self):
self._test_macos_11(12, 0)

def test_macos_12_3(self):
self._test_macos_11(12, 3)


class TestManylinuxPlatform:
def teardown_method(self):
Expand Down