From f68a9f7df9535b4b6dc826ced140ff4546eb81a7 Mon Sep 17 00:00:00 2001 From: mementorc Date: Mon, 14 Sep 2026 17:37:29 -0500 Subject: [PATCH 1/2] Accept macOS triples in the Apple OS version split --- crossenv/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crossenv/__init__.py b/crossenv/__init__.py index b1119f1..6be885c 100644 --- a/crossenv/__init__.py +++ b/crossenv/__init__.py @@ -464,8 +464,12 @@ def run_compiler(arg): ) def _split_apple_os_version(self, value): - # Split the Apple OS version from the OS name prefix. - if value.startswith("ios"): + # Split the Apple OS version from the OS name prefix. On macOS the + # version is the Darwin kernel version, not the macOS version, so it + # is only used to normalize the triple for comparison. + if value.startswith("darwin"): + offset = 6 + elif value.startswith("ios"): offset = 3 elif value.startswith("tvos"): offset = 4 From 275d14e75b7c3c6d38265b5e9681dcee9a0c8cac Mon Sep 17 00:00:00 2001 From: mementorc Date: Tue, 15 Sep 2026 17:04:11 -0500 Subject: [PATCH 2/2] Split Apple OS version at first digit Covers darwin, macos and other Apple OS names without a fixed list. Make the triple helpers static/class methods and add unit tests for the split and triple cleanup. --- crossenv/__init__.py | 26 +++++++++------------- tests/test_triples.py | 52 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 tests/test_triples.py diff --git a/crossenv/__init__.py b/crossenv/__init__.py index 6be885c..cad190e 100644 --- a/crossenv/__init__.py +++ b/crossenv/__init__.py @@ -463,23 +463,17 @@ def run_compiler(arg): expected, ) - def _split_apple_os_version(self, value): - # Split the Apple OS version from the OS name prefix. On macOS the - # version is the Darwin kernel version, not the macOS version, so it - # is only used to normalize the triple for comparison. - if value.startswith("darwin"): - offset = 6 - elif value.startswith("ios"): - offset = 3 - elif value.startswith("tvos"): - offset = 4 - elif value.startswith("watchos"): - offset = 7 - else: - raise ValueError("Unknown Apple compiler triple.") + @staticmethod + def _split_apple_os_version(value): + # Split the Apple OS version from the OS name prefix (e.g. ios13.0 -> + # ios, 13.0). No Apple OS name contains a digit, so the version starts + # at the first one. On macOS the version is the Darwin kernel version + # (e.g. darwin23.4.0), not the macOS version. + offset = next((i for i, c in enumerate(value) if c.isdigit()), len(value)) return value[:offset], value[offset:] - def _clean_triple(self, triple): + @classmethod + def _clean_triple(cls, triple): # Triples are in the form cpu-vendor-kernel-system or cpu-kernel-system. So we'll # get something like: x86_64-linux-gnu or x86_64-pc-linux-gnu. We won't # overcomplicate this, since it's just to generate a warning. @@ -494,7 +488,7 @@ def _clean_triple(self, triple): parts[0] = "aarch64" # Remove any version identifier from the OS (e.g., ios13.0 -> ios) - parts[2], _ = self._split_apple_os_version(parts[2]) + parts[2], _ = cls._split_apple_os_version(parts[2]) if len(parts) == 4 and parts[1] != "apple": # 4-part "triples" are expected for Apple simulators; diff --git a/tests/test_triples.py b/tests/test_triples.py new file mode 100644 index 0000000..c94da9f --- /dev/null +++ b/tests/test_triples.py @@ -0,0 +1,52 @@ +################################################# +# Compiler triple parsing (no crossenv required) +################################################# + +from crossenv import CrossEnvBuilder + + +def test_split_apple_os_version(): + expected = { + "ios13.0": ("ios", "13.0"), + "ios": ("ios", ""), + "tvos17.0": ("tvos", "17.0"), + "tvos": ("tvos", ""), + "watchos10.0": ("watchos", "10.0"), + "watchos": ("watchos", ""), + "darwin23.4.0": ("darwin", "23.4.0"), + "darwin": ("darwin", ""), + # Previously rejected as unknown + "macos14.0": ("macos", "14.0"), + "macosx14.0": ("macosx", "14.0"), + "xros1.0": ("xros", "1.0"), + } + actual = { + value: CrossEnvBuilder._split_apple_os_version(value) for value in expected + } + assert actual == expected + + +def test_clean_triple(): + expected = { + # Apple: arm64 -> aarch64, OS version removed. The clang -dumpmachine + # and HOST_GNU_TYPE forms must clean to the same value. + "arm64-apple-ios13.0": ["aarch64", "apple", "ios"], + "aarch64-apple-ios": ["aarch64", "apple", "ios"], + "arm64-apple-tvos17.0": ["aarch64", "apple", "tvos"], + "arm64-apple-watchos10.0": ["aarch64", "apple", "watchos"], + "arm64-apple-darwin23.4.0": ["aarch64", "apple", "darwin"], + "aarch64-apple-darwin": ["aarch64", "apple", "darwin"], + "x86_64-apple-darwin23.4.0": ["x86_64", "apple", "darwin"], + # Apple simulator: 4 parts, not compared + "arm64-apple-ios13.0-simulator": None, + # Non-Apple: vendor dropped from 4-part triples + "x86_64-linux-gnu": ["x86_64", "linux", "gnu"], + "x86_64-pc-linux-gnu": ["x86_64", "linux", "gnu"], + "aarch64-unknown-linux-gnu": ["aarch64", "linux", "gnu"], + # Other forms + "x86_64": None, + "aarch64-linux": None, + "a-b-c-d-e": None, + } + actual = {triple: CrossEnvBuilder._clean_triple(triple) for triple in expected} + assert actual == expected