[llvm] TargetParser: Move triple to CMake system name mapping into CMake (PR #225379)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 05:04:48 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/225379

Reimplement the triple -> CMAKE_SYSTEM_NAME derivation added in #208773
entirely in CMake, dropping the Python script it introduced.

The previous mechanism widened TRIPLE_OS/TRIPLE_ENV in TripleName.def with
a CMake system name column and parsed it from a Python helper invoked by
CMake at configure time. Two problems motivated this rework:

 - The CMake system name is a property of CMake (and can vary by CMake
   version), not of llvm::Triple, so it does not belong in the shared
   triple name table. The C++ never consumed the added column.
 - Invoking Python from CMake at configure time is an unwanted build
   dependency, and the Python-driven lit test broke Windows bots where the
   interpreter path contains a space.

Revert the TripleName.def/Triple.cpp column back to the two-argument
macros, delete the Python script and its unittest, and reimplement the
mapping as a self-contained pure-CMake module. The classification still
mirrors Triple::normalize's permissiveness for unnormalized and legacy
triples. A cmake -P driven unit test replaces the Python unittest and adds
a drift guard asserting every OS/environment name in TripleName.def has a
mapping entry.

Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>

>From 922809a8a3c18f3375050983d15015dc2efdc561 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 2 Aug 2026 21:43:55 +0200
Subject: [PATCH] TargetParser: Move triple to CMake system name mapping into
 CMake

Reimplement the triple -> CMAKE_SYSTEM_NAME derivation added in #208773
entirely in CMake, dropping the Python script it introduced.

The previous mechanism widened TRIPLE_OS/TRIPLE_ENV in TripleName.def with
a CMake system name column and parsed it from a Python helper invoked by
CMake at configure time. Two problems motivated this rework:

 - The CMake system name is a property of CMake (and can vary by CMake
   version), not of llvm::Triple, so it does not belong in the shared
   triple name table. The C++ never consumed the added column.
 - Invoking Python from CMake at configure time is an unwanted build
   dependency, and the Python-driven lit test broke Windows bots where the
   interpreter path contains a space.

Revert the TripleName.def/Triple.cpp column back to the two-argument
macros, delete the Python script and its unittest, and reimplement the
mapping as a self-contained pure-CMake module. The classification still
mirrors Triple::normalize's permissiveness for unnormalized and legacy
triples. A cmake -P driven unit test replaces the Python unittest and adds
a drift guard asserting every OS/environment name in TripleName.def has a
mapping entry.

Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>
---
 cmake/Modules/GetTripleCMakeSystemName.cmake  | 162 +++++++++++--
 llvm/include/llvm/TargetParser/TripleName.def | 228 +++++++++---------
 llvm/lib/TargetParser/Triple.cpp              |   8 +-
 llvm/test/lit.cfg.py                          |   1 +
 llvm/test/lit.site.cfg.py.in                  |   1 +
 .../get-triple-cmake-system-name.cmake        | 208 ++++++++++++++++
 .../TargetParser/get-triple-system-name.test  |   9 +-
 .../get_triple_system_name_test.py            | 206 ----------------
 llvm/utils/get_triple_system_name.py          | 148 ------------
 9 files changed, 476 insertions(+), 495 deletions(-)
 create mode 100644 llvm/test/tools/TargetParser/get-triple-cmake-system-name.cmake
 delete mode 100644 llvm/test/tools/TargetParser/get_triple_system_name_test.py
 delete mode 100755 llvm/utils/get_triple_system_name.py

diff --git a/cmake/Modules/GetTripleCMakeSystemName.cmake b/cmake/Modules/GetTripleCMakeSystemName.cmake
index 8ad725f34175c..d7b1d1388fcea 100644
--- a/cmake/Modules/GetTripleCMakeSystemName.cmake
+++ b/cmake/Modules/GetTripleCMakeSystemName.cmake
@@ -13,25 +13,157 @@
 #
 # Sets <out_var> to the CMake-style system name
 # (e.g. "x86_64-pc-linux-gnu" -> Linux, "arm64-apple-macos" ->
-# "Darwin"). A triple with an OS cmake does not recognize maps to
-# "Generic".
+# "Darwin"). A triple whose OS CMake does not recognize maps to
+# "Generic"; a triple with no identifiable OS falls back to
+# CMAKE_HOST_SYSTEM_NAME.
 #
-# The OS/environment -> system name data is derived from
-# llvm/include/llvm/TargetParser/TripleName.def
+# The recognized OS and environment names mirror the tables in
+# llvm/include/llvm/TargetParser/TripleName.def (and the classification
+# mirrors Triple::normalize), but the OS -> CMake system name mapping is
+# maintained here: the CMake system names are a property of CMake, not of
+# llvm::Triple, and can vary by CMake version.
+#
+# llvm/test/tools/TargetParser/get-triple-cmake-system-name.cmake unit
+# tests this module and guards against the .def OS/environment tables
+# drifting out of sync with the mapping below.
 
-get_filename_component(_gtcsn_llvm_dir "${CMAKE_CURRENT_LIST_DIR}/../../llvm"
-                       ABSOLUTE)
-set(_gtcsn_script "${_gtcsn_llvm_dir}/utils/get_triple_system_name.py")
+# Populate the OS/environment name tables in the caller's scope. Defined as
+# a macro so both the classifier and the unit test share one copy of the data.
+#
+# Order is significant: matching is by prefix, so a name that is a prefix of
+# another must come first (wasip1/2/3 before wasi). _GTCSN_OS_NAMES and
+# _GTCSN_OS_CMAKE are parallel lists. Only environments that force a system
+# name regardless of the OS appear in the environment tables.
+macro(_gtcsn_populate_tables)
+  set(_GTCSN_OS_NAMES
+      darwin dragonfly freebsd fuchsia ios kfreebsd linux lv2 macosx macos
+      managarm netbsd openbsd solaris uefi windows win32 zos haiku rtems aix
+      cuda nvcl amdhsa ps4 ps5 elfiamcu tvos watchos bridgeos driverkit xros
+      visionos mesa3d amdpal hermit hurd wasip1 wasip2 wasip3 wasi emscripten
+      shadermodel liteos serenity vulkan cheriotrtos opencl chipstar firmware
+      qurt h2)
+  set(_GTCSN_OS_CMAKE
+      Darwin DragonFly FreeBSD Fuchsia iOS FreeBSD Linux Generic Darwin Darwin
+      Generic NetBSD OpenBSD SunOS Generic Windows Windows OS390 Haiku RTEMS AIX
+      Generic Generic Generic Generic Generic Generic tvOS watchOS Darwin Darwin
+      visionOS visionOS Generic Generic Generic GNU WASI WASI WASI WASI
+      Emscripten Generic Generic SerenityOS Generic Generic Generic Generic
+      Generic Generic Generic)
 
-function(get_triple_cmake_system_name triple out_var)
-  execute_process(
-    COMMAND "${Python3_EXECUTABLE}" "${_gtcsn_script}" "--triple" "${triple}"
-    OUTPUT_VARIABLE _name
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-    RESULT_VARIABLE _result)
-  if(NOT _result EQUAL 0)
-    message(FATAL_ERROR "Failed to derive CMake system name for '${triple}'")
+  set(_GTCSN_ENV_NAMES android cygnus)
+  set(_GTCSN_ENV_OVERRIDE Android CYGWIN)
+endmacro()
+
+# Return TRUE in result_var if str starts with prefix.
+function(_gtcsn_starts_with str prefix result_var)
+  string(FIND "${str}" "${prefix}" _pos)
+  if(_pos EQUAL 0)
+    set(${result_var} TRUE PARENT_SCOPE)
+  else()
+    set(${result_var} FALSE PARENT_SCOPE)
+  endif()
+endfunction()
+
+# Classify a triple to a CMake system name, or the empty string if no OS
+# component can be identified (the caller then falls back to the host system
+# name). This mirrors the component classification of Triple::normalize: it
+# does not trust fixed positions, since a triple may omit the vendor
+# (aarch64-linux-android), put the OS in the vendor slot (wasm32-wasi,
+# i686-linux), or be a bare OS with no arch (clang accepts --target=darwin as
+# unknown-unknown-darwin). No arch name is a prefix of any OS/env name, so
+# scanning the first component too cannot misclassify a real arch.
+function(_get_triple_cmake_system_name_raw triple out_var)
+  _gtcsn_populate_tables()
+
+  string(REPLACE "-" ";" _parts "${triple}")
+  list(LENGTH _parts _nparts)
+
+  # An environment override takes precedence over the OS mapping (e.g. android
+  # wins over the linux in aarch64-linux-android), so scan for it first.
+  list(LENGTH _GTCSN_ENV_NAMES _nenv)
+  if(_nenv GREATER 0)
+    math(EXPR _last_env "${_nenv} - 1")
+    foreach(_comp IN LISTS _parts)
+      foreach(_i RANGE ${_last_env})
+        list(GET _GTCSN_ENV_NAMES ${_i} _name)
+        _gtcsn_starts_with("${_comp}" "${_name}" _match)
+        if(_match)
+          list(GET _GTCSN_ENV_OVERRIDE ${_i} _override)
+          set(${out_var} "${_override}" PARENT_SCOPE)
+          return()
+        endif()
+      endforeach()
+    endforeach()
+  endif()
+
+  # Find the first component that classifies as an OS. A specific (non-Generic)
+  # name wins immediately. A "Generic" match means the component is a recognized
+  # OS with no CMake equivalent; stop scanning once any OS is identified.
+  list(LENGTH _GTCSN_OS_NAMES _nos)
+  math(EXPR _last_os "${_nos} - 1")
+  set(_found_generic_os FALSE)
+  foreach(_comp IN LISTS _parts)
+    set(_matched FALSE)
+    foreach(_i RANGE ${_last_os})
+      list(GET _GTCSN_OS_NAMES ${_i} _name)
+      _gtcsn_starts_with("${_comp}" "${_name}" _match)
+      if(_match)
+        list(GET _GTCSN_OS_CMAKE ${_i} _cmake)
+        if(NOT _cmake STREQUAL "Generic")
+          set(${out_var} "${_cmake}" PARENT_SCOPE)
+          return()
+        endif()
+        set(_found_generic_os TRUE)
+        set(_matched TRUE)
+        break()
+      endif()
+    endforeach()
+    if(_matched)
+      break()
+    endif()
+  endforeach()
+
+  # Legacy OS spellings that normalize rewrites to windows.
+  foreach(_comp IN LISTS _parts)
+    _gtcsn_starts_with("${_comp}" "mingw" _match)
+    if(_match)
+      set(${out_var} "Windows" PARENT_SCOPE)
+      return()
+    endif()
+    _gtcsn_starts_with("${_comp}" "cygwin" _match_cygwin)
+    _gtcsn_starts_with("${_comp}" "msys" _match_msys)
+    if(_match_cygwin OR _match_msys)
+      set(${out_var} "CYGWIN" PARENT_SCOPE)
+      return()
+    endif()
+  endforeach()
+
+  # Apple vendor triples with no specific CMake OS name (e.g. firmware) map to
+  # Darwin.
+  if(_nparts GREATER 1)
+    list(GET _parts 1 _vendor)
+    if(_vendor STREQUAL "apple")
+      set(${out_var} "Darwin" PARENT_SCOPE)
+      return()
+    endif()
   endif()
+
+  if(_found_generic_os)
+    set(${out_var} "Generic" PARENT_SCOPE)
+    return()
+  endif()
+
+  # No OS could be identified. Too few components to have one -> let the caller
+  # fall back to the host system name.
+  if(_nparts LESS 3)
+    set(${out_var} "" PARENT_SCOPE)
+  else()
+    set(${out_var} "Generic" PARENT_SCOPE)
+  endif()
+endfunction()
+
+function(get_triple_cmake_system_name triple out_var)
+  _get_triple_cmake_system_name_raw("${triple}" _name)
   if(_name)
     set(${out_var} "${_name}" PARENT_SCOPE)
   else()
diff --git a/llvm/include/llvm/TargetParser/TripleName.def b/llvm/include/llvm/TargetParser/TripleName.def
index 95026bd39db78..bbc03b3188019 100644
--- a/llvm/include/llvm/TargetParser/TripleName.def
+++ b/llvm/include/llvm/TargetParser/TripleName.def
@@ -5,21 +5,15 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// Also parsed by llvm/utils/get_triple_system_name.py, so keep the macro
-// invocations one per line with string literals.
-//
-//===----------------------------------------------------------------------===//
 
 // NOTE: NO INCLUDE GUARD DESIRED!
 
 //===----------------------------------------------------------------------===//
 // OS names.
 //
-// TRIPLE_OS(Enum, Name, CMakeName)
-//   Enum      - the Triple::OSType enumerator
-//   Name      - the canonical string
-//   CMakeName - the CMake system name, or "Generic" if there is no equivalent
+// TRIPLE_OS(Enum, Name)
+//   Enum - the Triple::OSType enumerator
+//   Name - the canonical string
 //
 // TRIPLE_OS_ALIAS(Enum, AliasName)
 //   An additional prefix maps to an OSType.
@@ -29,64 +23,64 @@
 // ===----------------------------------------------------------------------===//
 
 #ifndef TRIPLE_OS
-#define TRIPLE_OS(Enum, Name, CMakeName)
+#define TRIPLE_OS(Enum, Name)
 #endif
 #ifndef TRIPLE_OS_ALIAS
 #define TRIPLE_OS_ALIAS(Enum, AliasName)
 #endif
 
-TRIPLE_OS(Darwin, "darwin", "Darwin")
-TRIPLE_OS(DragonFly, "dragonfly", "DragonFly")
-TRIPLE_OS(FreeBSD, "freebsd", "FreeBSD")
-TRIPLE_OS(Fuchsia, "fuchsia", "Fuchsia")
-TRIPLE_OS(IOS, "ios", "iOS")
-TRIPLE_OS(KFreeBSD, "kfreebsd", "FreeBSD")
-TRIPLE_OS(Linux, "linux", "Linux")
-TRIPLE_OS(Lv2, "lv2", "Generic")
-TRIPLE_OS(MacOSX, "macosx", "Darwin")
+TRIPLE_OS(Darwin, "darwin")
+TRIPLE_OS(DragonFly, "dragonfly")
+TRIPLE_OS(FreeBSD, "freebsd")
+TRIPLE_OS(Fuchsia, "fuchsia")
+TRIPLE_OS(IOS, "ios")
+TRIPLE_OS(KFreeBSD, "kfreebsd")
+TRIPLE_OS(Linux, "linux")
+TRIPLE_OS(Lv2, "lv2")
+TRIPLE_OS(MacOSX, "macosx")
 TRIPLE_OS_ALIAS(MacOSX, "macos")
-TRIPLE_OS(Managarm, "managarm", "Generic")
-TRIPLE_OS(NetBSD, "netbsd", "NetBSD")
-TRIPLE_OS(OpenBSD, "openbsd", "OpenBSD")
-TRIPLE_OS(Solaris, "solaris", "SunOS")
-TRIPLE_OS(UEFI, "uefi", "Generic")
-TRIPLE_OS(Win32, "windows", "Windows")
+TRIPLE_OS(Managarm, "managarm")
+TRIPLE_OS(NetBSD, "netbsd")
+TRIPLE_OS(OpenBSD, "openbsd")
+TRIPLE_OS(Solaris, "solaris")
+TRIPLE_OS(UEFI, "uefi")
+TRIPLE_OS(Win32, "windows")
 TRIPLE_OS_ALIAS(Win32, "win32")
-TRIPLE_OS(ZOS, "zos", "OS390")
-TRIPLE_OS(Haiku, "haiku", "Haiku")
-TRIPLE_OS(RTEMS, "rtems", "RTEMS")
-TRIPLE_OS(AIX, "aix", "AIX")
-TRIPLE_OS(CUDA, "cuda", "Generic")
-TRIPLE_OS(NVCL, "nvcl", "Generic")
-TRIPLE_OS(AMDHSA, "amdhsa", "Generic")
-TRIPLE_OS(PS4, "ps4", "Generic")
-TRIPLE_OS(PS5, "ps5", "Generic")
-TRIPLE_OS(ELFIAMCU, "elfiamcu", "Generic")
-TRIPLE_OS(TvOS, "tvos", "tvOS")
-TRIPLE_OS(WatchOS, "watchos", "watchOS")
-TRIPLE_OS(BridgeOS, "bridgeos", "Darwin")
-TRIPLE_OS(DriverKit, "driverkit", "Darwin")
-TRIPLE_OS(XROS, "xros", "visionOS")
+TRIPLE_OS(ZOS, "zos")
+TRIPLE_OS(Haiku, "haiku")
+TRIPLE_OS(RTEMS, "rtems")
+TRIPLE_OS(AIX, "aix")
+TRIPLE_OS(CUDA, "cuda")
+TRIPLE_OS(NVCL, "nvcl")
+TRIPLE_OS(AMDHSA, "amdhsa")
+TRIPLE_OS(PS4, "ps4")
+TRIPLE_OS(PS5, "ps5")
+TRIPLE_OS(ELFIAMCU, "elfiamcu")
+TRIPLE_OS(TvOS, "tvos")
+TRIPLE_OS(WatchOS, "watchos")
+TRIPLE_OS(BridgeOS, "bridgeos")
+TRIPLE_OS(DriverKit, "driverkit")
+TRIPLE_OS(XROS, "xros")
 TRIPLE_OS_ALIAS(XROS, "visionos")
-TRIPLE_OS(Mesa3D, "mesa3d", "Generic")
-TRIPLE_OS(AMDPAL, "amdpal", "Generic")
-TRIPLE_OS(HermitCore, "hermit", "Generic")
-TRIPLE_OS(Hurd, "hurd", "GNU")
-TRIPLE_OS(WASIp1, "wasip1", "WASI")
-TRIPLE_OS(WASIp2, "wasip2", "WASI")
-TRIPLE_OS(WASIp3, "wasip3", "WASI")
-TRIPLE_OS(WASI, "wasi", "WASI")
-TRIPLE_OS(Emscripten, "emscripten", "Emscripten")
-TRIPLE_OS(ShaderModel, "shadermodel", "Generic")
-TRIPLE_OS(LiteOS, "liteos", "Generic")
-TRIPLE_OS(Serenity, "serenity", "SerenityOS")
-TRIPLE_OS(Vulkan, "vulkan", "Generic")
-TRIPLE_OS(CheriotRTOS, "cheriotrtos", "Generic")
-TRIPLE_OS(OpenCL, "opencl", "Generic")
-TRIPLE_OS(ChipStar, "chipstar", "Generic")
-TRIPLE_OS(Firmware, "firmware", "Generic")
-TRIPLE_OS(QURT, "qurt", "Generic")
-TRIPLE_OS(H2, "h2", "Generic")
+TRIPLE_OS(Mesa3D, "mesa3d")
+TRIPLE_OS(AMDPAL, "amdpal")
+TRIPLE_OS(HermitCore, "hermit")
+TRIPLE_OS(Hurd, "hurd")
+TRIPLE_OS(WASIp1, "wasip1")
+TRIPLE_OS(WASIp2, "wasip2")
+TRIPLE_OS(WASIp3, "wasip3")
+TRIPLE_OS(WASI, "wasi")
+TRIPLE_OS(Emscripten, "emscripten")
+TRIPLE_OS(ShaderModel, "shadermodel")
+TRIPLE_OS(LiteOS, "liteos")
+TRIPLE_OS(Serenity, "serenity")
+TRIPLE_OS(Vulkan, "vulkan")
+TRIPLE_OS(CheriotRTOS, "cheriotrtos")
+TRIPLE_OS(OpenCL, "opencl")
+TRIPLE_OS(ChipStar, "chipstar")
+TRIPLE_OS(Firmware, "firmware")
+TRIPLE_OS(QURT, "qurt")
+TRIPLE_OS(H2, "h2")
 
 #undef TRIPLE_OS
 #undef TRIPLE_OS_ALIAS
@@ -94,73 +88,71 @@ TRIPLE_OS(H2, "h2", "Generic")
 //===----------------------------------------------------------------------===//
 // Environment names.
 //
-// TRIPLE_ENV(Enum, Name, CMakeOverride)
-//   Enum          - the Triple::EnvironmentType enumerator.
-//   Name          - the canonical string
-//   CMakeOverride - a CMake system name this environment forces regardless of
-//                   the OS, or "" for no override
+// TRIPLE_ENV(Enum, Name)
+//   Enum - the Triple::EnvironmentType enumerator.
+//   Name - the canonical string
 //
 // Order is significant for the same prefix-matching reason as OS (eabihf before
 // eabi; the gnu*/musl* variants before gnu/musl).
 //===----------------------------------------------------------------------===//
 
 #ifndef TRIPLE_ENV
-#define TRIPLE_ENV(Enum, Name, CMakeOverride)
+#define TRIPLE_ENV(Enum, Name)
 #endif
 
-TRIPLE_ENV(EABIHF, "eabihf", "")
-TRIPLE_ENV(EABI, "eabi", "")
-TRIPLE_ENV(GNUABIN32, "gnuabin32", "")
-TRIPLE_ENV(GNUABI64, "gnuabi64", "")
-TRIPLE_ENV(GNUEABIHFT64, "gnueabihft64", "")
-TRIPLE_ENV(GNUEABIHF, "gnueabihf", "")
-TRIPLE_ENV(GNUEABIT64, "gnueabit64", "")
-TRIPLE_ENV(GNUEABI, "gnueabi", "")
-TRIPLE_ENV(GNUF32, "gnuf32", "")
-TRIPLE_ENV(GNUF64, "gnuf64", "")
-TRIPLE_ENV(GNUSF, "gnusf", "")
-TRIPLE_ENV(GNUX32, "gnux32", "")
-TRIPLE_ENV(GNUILP32, "gnu_ilp32", "")
-TRIPLE_ENV(CODE16, "code16", "")
-TRIPLE_ENV(GNUT64, "gnut64", "")
-TRIPLE_ENV(GNU, "gnu", "")
-TRIPLE_ENV(Android, "android", "Android")
-TRIPLE_ENV(MuslABIN32, "muslabin32", "")
-TRIPLE_ENV(MuslABI64, "muslabi64", "")
-TRIPLE_ENV(MuslEABIHF, "musleabihf", "")
-TRIPLE_ENV(MuslEABI, "musleabi", "")
-TRIPLE_ENV(MuslF32, "muslf32", "")
-TRIPLE_ENV(MuslSF, "muslsf", "")
-TRIPLE_ENV(MuslX32, "muslx32", "")
-TRIPLE_ENV(MuslWALI, "muslwali", "")
-TRIPLE_ENV(Musl, "musl", "")
-TRIPLE_ENV(MSVC, "msvc", "")
-TRIPLE_ENV(Itanium, "itanium", "")
-TRIPLE_ENV(Cygnus, "cygnus", "CYGWIN")
-TRIPLE_ENV(CoreCLR, "coreclr", "")
-TRIPLE_ENV(Simulator, "simulator", "")
-TRIPLE_ENV(MacABI, "macabi", "")
-TRIPLE_ENV(Pixel, "pixel", "")
-TRIPLE_ENV(Vertex, "vertex", "")
-TRIPLE_ENV(Geometry, "geometry", "")
-TRIPLE_ENV(Hull, "hull", "")
-TRIPLE_ENV(Domain, "domain", "")
-TRIPLE_ENV(Compute, "compute", "")
-TRIPLE_ENV(Library, "library", "")
-TRIPLE_ENV(RayGeneration, "raygeneration", "")
-TRIPLE_ENV(Intersection, "intersection", "")
-TRIPLE_ENV(AnyHit, "anyhit", "")
-TRIPLE_ENV(ClosestHit, "closesthit", "")
-TRIPLE_ENV(Miss, "miss", "")
-TRIPLE_ENV(Callable, "callable", "")
-TRIPLE_ENV(Mesh, "mesh", "")
-TRIPLE_ENV(Amplification, "amplification", "")
-TRIPLE_ENV(RootSignature, "rootsignature", "")
-TRIPLE_ENV(OpenHOS, "ohos", "")
-TRIPLE_ENV(PAuthTest, "pauthtest", "")
-TRIPLE_ENV(LLVM, "llvm", "")
-TRIPLE_ENV(Mlibc, "mlibc", "")
-TRIPLE_ENV(MTIA, "mtia", "")
+TRIPLE_ENV(EABIHF, "eabihf")
+TRIPLE_ENV(EABI, "eabi")
+TRIPLE_ENV(GNUABIN32, "gnuabin32")
+TRIPLE_ENV(GNUABI64, "gnuabi64")
+TRIPLE_ENV(GNUEABIHFT64, "gnueabihft64")
+TRIPLE_ENV(GNUEABIHF, "gnueabihf")
+TRIPLE_ENV(GNUEABIT64, "gnueabit64")
+TRIPLE_ENV(GNUEABI, "gnueabi")
+TRIPLE_ENV(GNUF32, "gnuf32")
+TRIPLE_ENV(GNUF64, "gnuf64")
+TRIPLE_ENV(GNUSF, "gnusf")
+TRIPLE_ENV(GNUX32, "gnux32")
+TRIPLE_ENV(GNUILP32, "gnu_ilp32")
+TRIPLE_ENV(CODE16, "code16")
+TRIPLE_ENV(GNUT64, "gnut64")
+TRIPLE_ENV(GNU, "gnu")
+TRIPLE_ENV(Android, "android")
+TRIPLE_ENV(MuslABIN32, "muslabin32")
+TRIPLE_ENV(MuslABI64, "muslabi64")
+TRIPLE_ENV(MuslEABIHF, "musleabihf")
+TRIPLE_ENV(MuslEABI, "musleabi")
+TRIPLE_ENV(MuslF32, "muslf32")
+TRIPLE_ENV(MuslSF, "muslsf")
+TRIPLE_ENV(MuslX32, "muslx32")
+TRIPLE_ENV(MuslWALI, "muslwali")
+TRIPLE_ENV(Musl, "musl")
+TRIPLE_ENV(MSVC, "msvc")
+TRIPLE_ENV(Itanium, "itanium")
+TRIPLE_ENV(Cygnus, "cygnus")
+TRIPLE_ENV(CoreCLR, "coreclr")
+TRIPLE_ENV(Simulator, "simulator")
+TRIPLE_ENV(MacABI, "macabi")
+TRIPLE_ENV(Pixel, "pixel")
+TRIPLE_ENV(Vertex, "vertex")
+TRIPLE_ENV(Geometry, "geometry")
+TRIPLE_ENV(Hull, "hull")
+TRIPLE_ENV(Domain, "domain")
+TRIPLE_ENV(Compute, "compute")
+TRIPLE_ENV(Library, "library")
+TRIPLE_ENV(RayGeneration, "raygeneration")
+TRIPLE_ENV(Intersection, "intersection")
+TRIPLE_ENV(AnyHit, "anyhit")
+TRIPLE_ENV(ClosestHit, "closesthit")
+TRIPLE_ENV(Miss, "miss")
+TRIPLE_ENV(Callable, "callable")
+TRIPLE_ENV(Mesh, "mesh")
+TRIPLE_ENV(Amplification, "amplification")
+TRIPLE_ENV(RootSignature, "rootsignature")
+TRIPLE_ENV(OpenHOS, "ohos")
+TRIPLE_ENV(PAuthTest, "pauthtest")
+TRIPLE_ENV(LLVM, "llvm")
+TRIPLE_ENV(Mlibc, "mlibc")
+TRIPLE_ENV(MTIA, "mtia")
 
 #undef TRIPLE_ENV
 
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index fb54408c0729f..b9b6a04f04137 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -393,7 +393,7 @@ StringRef Triple::getOSTypeName(OSType Kind) {
   switch (Kind) {
   case UnknownOS:
     return "unknown";
-#define TRIPLE_OS(Enum, Name, CMakeName)                                       \
+#define TRIPLE_OS(Enum, Name)                                                  \
   case Enum:                                                                   \
     return Name;
 #include "llvm/TargetParser/TripleName.def"
@@ -406,7 +406,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) {
   switch (Kind) {
   case UnknownEnvironment:
     return "unknown";
-#define TRIPLE_ENV(Enum, Name, CMakeOverride)                                  \
+#define TRIPLE_ENV(Enum, Name)                                                 \
   case Enum:                                                                   \
     return Name;
 #include "llvm/TargetParser/TripleName.def"
@@ -705,7 +705,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) {
 
 static Triple::OSType parseOS(StringRef OSName) {
   return StringSwitch<Triple::OSType>(OSName)
-#define TRIPLE_OS(Enum, Name, CMakeName) .StartsWith(Name, Triple::Enum)
+#define TRIPLE_OS(Enum, Name) .StartsWith(Name, Triple::Enum)
 #define TRIPLE_OS_ALIAS(Enum, AliasName) .StartsWith(AliasName, Triple::Enum)
 #include "llvm/TargetParser/TripleName.def"
       .Default(Triple::UnknownOS);
@@ -713,7 +713,7 @@ static Triple::OSType parseOS(StringRef OSName) {
 
 static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) {
   return StringSwitch<Triple::EnvironmentType>(EnvironmentName)
-#define TRIPLE_ENV(Enum, Name, CMakeOverride) .StartsWith(Name, Triple::Enum)
+#define TRIPLE_ENV(Enum, Name) .StartsWith(Name, Triple::Enum)
 #include "llvm/TargetParser/TripleName.def"
       .Default(Triple::UnknownEnvironment);
 }
diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py
index d8913b1fbdc87..0adde7144b0d9 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -239,6 +239,7 @@ def get_asan_rtlib():
     ToolSubst("%llvm-bitcode-strip", FindTool("llvm-bitcode-strip")),
     ToolSubst("%llvm-extract-bundle-entry", FindTool("llvm-extract-bundle-entry")),
     ToolSubst("%split-file", FindTool("split-file")),
+    ToolSubst("%cmake", config.cmake_command, unresolved="ignore"),
 ]
 
 # FIXME: Why do we have both `lli` and `%lli` that do slightly different things?
diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in
index 60b22ef5a7a85..d3fa24b243bd0 100644
--- a/llvm/test/lit.site.cfg.py.in
+++ b/llvm/test/lit.site.cfg.py.in
@@ -17,6 +17,7 @@ config.llvm_exe_ext = "@EXEEXT@"
 config.lit_tools_dir = path(r"@LLVM_LIT_TOOLS_DIR@")
 config.errc_messages = "@LLVM_LIT_ERRC_MESSAGES@"
 config.python_executable = "@Python3_EXECUTABLE@"
+config.cmake_command = "@CMAKE_COMMAND@"
 config.gold_executable = "@GOLD_EXECUTABLE@"
 config.ld_bfd_executable = "@LD_BFD_EXECUTABLE@"
 config.ld64_executable = "@LD64_EXECUTABLE@"
diff --git a/llvm/test/tools/TargetParser/get-triple-cmake-system-name.cmake b/llvm/test/tools/TargetParser/get-triple-cmake-system-name.cmake
new file mode 100644
index 0000000000000..ac75a38901f2b
--- /dev/null
+++ b/llvm/test/tools/TargetParser/get-triple-cmake-system-name.cmake
@@ -0,0 +1,208 @@
+#===--------------------------------------------------------------------===//
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===--------------------------------------------------------------------===//
+
+# Unit test for cmake/Modules/GetTripleCMakeSystemName.cmake. Run via:
+#   cmake -P get-triple-cmake-system-name.cmake
+#
+# _get_triple_cmake_system_name_raw must classify the same OS that
+# Triple::normalize picks, including for the unnormalized/legacy triple
+# shapes the runtimes build may feed in. The final block guards against the
+# OS/environment tables drifting out of sync with TripleName.def.
+
+cmake_minimum_required(VERSION 3.20)
+
+# This script lives in llvm/test/tools/TargetParser/; the module is under the
+# top-level cmake/, and TripleName.def under llvm/include/.
+get_filename_component(_llvm_dir "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
+get_filename_component(_project_dir "${_llvm_dir}/.." ABSOLUTE)
+
+include("${_project_dir}/cmake/Modules/GetTripleCMakeSystemName.cmake")
+
+# Accumulate failures in a global property so it survives function scopes; the
+# final OK marker is only printed when it stays zero. This matters because the
+# lit test pipes into FileCheck, which would otherwise miss a non-zero exit.
+set_property(GLOBAL PROPERTY _gtcsn_failures 0)
+
+function(_fail msg)
+  message(SEND_ERROR "${msg}")
+  get_property(_n GLOBAL PROPERTY _gtcsn_failures)
+  math(EXPR _n "${_n} + 1")
+  set_property(GLOBAL PROPERTY _gtcsn_failures "${_n}")
+endfunction()
+
+# Assert the classifier maps triple to expected.
+function(expect triple expected)
+  _get_triple_cmake_system_name_raw("${triple}" got)
+  if(NOT got STREQUAL expected)
+    _fail("'${triple}': got '${got}', expected '${expected}'")
+  endif()
+endfunction()
+
+# Canonical triples, one per interesting mapping.
+expect("x86_64-unknown-linux-gnu" "Linux")
+expect("arm64-apple-darwin" "Darwin")
+expect("s390x-ibm-zos" "OS390")
+expect("aarch64-unknown-linux-android" "Android")
+expect("x86_64-pc-windows-cygnus" "CYGWIN")
+expect("wasm32-unknown-wasip1" "WASI")
+expect("arm64-apple-ios" "iOS")
+expect("riscv64-unknown-elf" "Generic")
+
+# TRIPLE_OS_ALIAS rows resolve to their target OS's CMake name.
+expect("x86_64-apple-macos" "Darwin")   # -> MacOSX
+expect("x86_64-pc-win32" "Windows")     # -> Win32
+expect("arm64-apple-visionos" "visionOS") # -> XROS
+
+# Vendor omitted / OS or env out of the fixed position, version suffixes, and
+# GCC-legacy spellings.
+expect("aarch64-linux-android21" "Android")
+expect("aarch64-unknown-linux-android21" "Android")
+expect("arm-linux-androideabi" "Android")
+expect("armv7a-linux-androideabi29" "Android")
+expect("x86_64-linux-gnu" "Linux")
+expect("riscv64-linux-gnu" "Linux")
+expect("x86_64-apple-macosx10.15" "Darwin")
+expect("armv7-apple-ios13.0" "iOS")
+expect("x86_64-pc-freebsd14" "FreeBSD")
+
+# The "real-world funky triples" from TripleTest.cpp's Normalization test.
+expect("i386-mingw32" "Windows")   # -> i386-unknown-windows-gnu
+expect("i486-linux-gnu" "Linux")   # -> i486-unknown-linux-gnu
+expect("i386-redhat-linux" "Linux")
+expect("i686-linux" "Linux")
+expect("arm-none-eabi" "Generic")  # no OS
+expect("ve-linux" "Linux")
+expect("wasm32-wasi" "WASI")
+expect("wasm64-wasi" "WASI")
+expect("x86_64-pc-cygwin" "CYGWIN")   # -> windows-cygnus
+expect("x86_64-pc-msys" "CYGWIN")     # -> windows-cygnus
+expect("x86_64-w64-mingw32" "Windows")
+expect("i686-w64-mingw32" "Windows")
+
+# OS/environment special-cases that Triple::normalize applies.
+expect("x86_64-pc-windows" "Windows")
+expect("x86_64-pc-windows-msvc" "Windows")
+expect("x86_64-pc-windows-gnu" "Windows")
+expect("x86_64-apple-macosx" "Darwin")
+expect("arm-apple-darwin" "Darwin")
+expect("arm-apple-ios" "iOS")
+expect("arm-apple-tvos" "tvOS")
+expect("arm-apple-watchos" "watchOS")
+expect("arm-apple-xros" "visionOS")
+expect("arm-apple-driverkit" "Darwin")
+expect("arm-apple-bridgeos" "Darwin")
+expect("arm-apple-firmware" "Darwin")
+
+# firmware has no dedicated CMake name and only maps to Darwin for the apple
+# vendor; any other vendor is Generic.
+expect("arm-none-firmware" "Generic")
+expect("arm-unknown-firmware" "Generic")
+expect("arm-pc-firmware" "Generic")
+
+# driverkit and bridgeos are always Apple, so they map to Darwin regardless of
+# the vendor component.
+foreach(_os driverkit bridgeos)
+  foreach(_vendor apple none unknown pc)
+    expect("arm-${_vendor}-${_os}" "Darwin")
+  endforeach()
+endforeach()
+
+# A lone OS component with no arch is a valid clang target (e.g.
+# --target=darwin -> unknown-unknown-darwin), so it classifies by the first
+# (and only) component.
+expect("darwin" "Darwin")
+expect("linux" "Linux")
+expect("ios" "iOS")
+expect("freebsd" "FreeBSD")
+expect("wasi" "WASI")
+expect("zos" "OS390")
+expect("mingw32" "Windows")
+expect("cygwin" "CYGWIN")
+
+# Only when no component classifies as an OS does the classifier return empty
+# (the caller then falls back to the host system name).
+expect("x86_64" "")
+expect("arm-none" "")
+
+# Data-driven: a canonical arch-unknown-<os> triple maps to the CMake name the
+# module declares for every OS/alias row.
+_gtcsn_populate_tables()
+list(LENGTH _GTCSN_OS_NAMES _nos)
+math(EXPR _last_os "${_nos} - 1")
+foreach(_i RANGE ${_last_os})
+  list(GET _GTCSN_OS_NAMES ${_i} _name)
+  list(GET _GTCSN_OS_CMAKE ${_i} _cmake)
+  expect("arch-unknown-${_name}" "${_cmake}")
+endforeach()
+
+# A name that is a prefix of a LATER name would shadow it under prefix matching,
+# so within each table a name must never be a prefix of an earlier one.
+function(check_prefix_order)
+  foreach(_list _GTCSN_OS_NAMES _GTCSN_ENV_NAMES)
+    set(_names "${${_list}}")
+    list(LENGTH _names _n)
+    math(EXPR _last "${_n} - 1")
+    foreach(_i RANGE ${_last})
+      list(GET _names ${_i} _short)
+      math(EXPR _next "${_i} + 1")
+      if(_next GREATER _last)
+        continue()
+      endif()
+      foreach(_j RANGE ${_next} ${_last})
+        list(GET _names ${_j} _longer)
+        string(FIND "${_longer}" "${_short}" _pos)
+        if(_pos EQUAL 0 AND NOT _longer STREQUAL _short)
+          _fail("${_list}: '${_short}' precedes and shadows '${_longer}'")
+        endif()
+      endforeach()
+    endforeach()
+  endforeach()
+endfunction()
+check_prefix_order()
+
+# Drift guard: every OS/alias name in TripleName.def must have a mapping entry
+# in the module, and every environment override the module relies on must still
+# name a real environment in the .def. The CMake system names themselves live
+# only in the module (they are a CMake property, not part of llvm::Triple), so
+# the .def is only cross-checked for the set of recognized names.
+set(_def "${_llvm_dir}/include/llvm/TargetParser/TripleName.def")
+if(NOT EXISTS "${_def}")
+  message(FATAL_ERROR "TripleName.def not found at ${_def}")
+endif()
+
+file(STRINGS "${_def}" _os_lines REGEX "^[ \t]*TRIPLE_OS(_ALIAS)?\\(")
+foreach(_line IN LISTS _os_lines)
+  if(_line MATCHES "\"([^\"]+)\"")
+    set(_name "${CMAKE_MATCH_1}")
+    if(NOT _name IN_LIST _GTCSN_OS_NAMES)
+      _fail("TripleName.def OS '${_name}' has no CMake system-name mapping "
+            "in GetTripleCMakeSystemName.cmake")
+    endif()
+  endif()
+endforeach()
+
+file(STRINGS "${_def}" _env_lines REGEX "^[ \t]*TRIPLE_ENV\\(")
+set(_def_env_names "")
+foreach(_line IN LISTS _env_lines)
+  if(_line MATCHES "\"([^\"]+)\"")
+    list(APPEND _def_env_names "${CMAKE_MATCH_1}")
+  endif()
+endforeach()
+foreach(_name IN LISTS _GTCSN_ENV_NAMES)
+  if(NOT _name IN_LIST _def_env_names)
+    _fail("GetTripleCMakeSystemName.cmake environment override '${_name}' "
+          "is no longer an environment in TripleName.def")
+  endif()
+endforeach()
+
+get_property(_failures GLOBAL PROPERTY _gtcsn_failures)
+if(_failures GREATER 0)
+  message(FATAL_ERROR "${_failures} case(s) failed")
+endif()
+
+message(STATUS "get-triple-cmake-system-name: OK")
diff --git a/llvm/test/tools/TargetParser/get-triple-system-name.test b/llvm/test/tools/TargetParser/get-triple-system-name.test
index db1d0cb3aa92e..001c073dcfc23 100644
--- a/llvm/test/tools/TargetParser/get-triple-system-name.test
+++ b/llvm/test/tools/TargetParser/get-triple-system-name.test
@@ -1,6 +1,7 @@
-# Run the unit tests for get_triple_system_name.py, which parses
-# TripleName.def and must stay in sync with llvm::Triple.
+# Unit test for cmake/Modules/GetTripleCMakeSystemName.cmake, which maps a
+# target triple to a CMake system name and must stay in sync with the OS and
+# environment tables in TripleName.def.
 
-# RUN: %python %S/get_triple_system_name_test.py 2>&1 | FileCheck %s
+# RUN: %cmake -P %S/get-triple-cmake-system-name.cmake 2>&1 | FileCheck %s
 
-# CHECK: OK
+# CHECK: get-triple-cmake-system-name: OK
diff --git a/llvm/test/tools/TargetParser/get_triple_system_name_test.py b/llvm/test/tools/TargetParser/get_triple_system_name_test.py
deleted file mode 100644
index c6ffd1c7fbe6d..0000000000000
--- a/llvm/test/tools/TargetParser/get_triple_system_name_test.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# ===----------------------------------------------------------------------===##
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-# ===----------------------------------------------------------------------===##
-"""Tests for get_triple_system_name.
-
-The parser must stay in sync with TripleName.def, and system_name() must
-classify the same OS that Triple::normalize picks, including for the
-unnormalized/legacy triple shapes the runtimes build may feed in.
-"""
-
-import os
-import sys
-import unittest
-
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "utils"))
-
-import get_triple_system_name as g
-
-
-class Test(unittest.TestCase):
-    def setUp(self):
-        self.names = g.parse(g.find_def_file())
-
-    def test_all_def_rows_parsed(self):
-        # Guard against the regex silently dropping a .def row the C++ accepts.
-        with open(g.find_def_file()) as f:
-            lines = [l for l in f if "#define" not in l]
-
-        def count(macro):
-            return sum(1 for l in lines if l.lstrip().startswith(macro + "("))
-
-        self.assertEqual(
-            len(self.names.os), count("TRIPLE_OS") + count("TRIPLE_OS_ALIAS")
-        )
-        self.assertEqual(len(self.names.env), count("TRIPLE_ENV"))
-
-    def test_prefix_ordering(self):
-        # A name that is a prefix of a LATER name would shadow it under the
-        # StartsWith matching both the C++ and this script rely on.
-        for table in (self.names.os, self.names.env):
-            names = [n for n, _ in table]
-            for i, short in enumerate(names):
-                for longer in names[i + 1 :]:
-                    self.assertFalse(
-                        longer.startswith(short) and longer != short,
-                        f"'{short}' precedes and shadows '{longer}'",
-                    )
-
-    def test_every_os_row(self):
-        # Data-driven: a canonical arch-unknown-<os> triple must map to the
-        # CMake name the .def declares for every OS (and alias) row. This is
-        # the exhaustive counterpart to the hand-picked cases below; it fails
-        # automatically when a new OS is added without a CMake mapping.
-        for name, cmake_name in self.names.os:
-            # firmware/driverkit/bridgeos also have vendor-specific behavior
-            # exercised separately; here the plain arch-unknown form suffices.
-            triple = f"arch-unknown-{name}"
-            self.assertEqual(g.system_name(self.names, triple), cmake_name, triple)
-
-    def test_known_triples(self):
-        cases = {
-            "x86_64-unknown-linux-gnu": "Linux",
-            "arm64-apple-darwin": "Darwin",
-            "s390x-ibm-zos": "OS390",
-            "aarch64-unknown-linux-android": "Android",
-            "x86_64-pc-windows-cygnus": "CYGWIN",
-            "wasm32-unknown-wasip1": "WASI",
-            "arm64-apple-ios": "iOS",
-            "riscv64-unknown-elf": "Generic",
-        }
-        for triple, want in cases.items():
-            self.assertEqual(g.system_name(self.names, triple), want, triple)
-
-    def test_os_aliases(self):
-        # The TRIPLE_OS_ALIAS rows resolve to their target OS's CMake name.
-        cases = {
-            "x86_64-apple-macos": "Darwin",  # -> MacOSX
-            "x86_64-pc-win32": "Windows",  # -> Win32
-            "arm64-apple-visionos": "visionOS",  # -> XROS
-        }
-        for triple, want in cases.items():
-            self.assertEqual(g.system_name(self.names, triple), want, triple)
-
-    def test_non_canonical_triples(self):
-        # Vendor omitted / non-standard, os or env not in the fixed position,
-        # version suffixes, and GCC-legacy spellings.
-        cases = {
-            "aarch64-linux-android21": "Android",
-            "aarch64-unknown-linux-android21": "Android",
-            "arm-linux-androideabi": "Android",
-            "armv7a-linux-androideabi29": "Android",
-            # Vendor omitted, os in the vendor slot.
-            "x86_64-linux-gnu": "Linux",
-            "riscv64-linux-gnu": "Linux",
-            # OS version suffix.
-            "x86_64-apple-macosx10.15": "Darwin",
-            "armv7-apple-ios13.0": "iOS",
-            # Non-standard vendor, still resolvable by os component.
-            "x86_64-pc-freebsd14": "FreeBSD",
-        }
-        for triple, want in cases.items():
-            self.assertEqual(g.system_name(self.names, triple), want, triple)
-
-    def test_matches_normalize_funky_triples(self):
-        # The "real-world funky triples" from TripleTest.cpp's Normalization
-        # test. system_name must classify the same OS that Triple::normalize
-        # picks, including os-in-vendor-slot and GCC-legacy windows spellings
-        # (mingw* -> windows-gnu, cygwin*/msys -> windows-cygnus).
-        cases = {
-            "i386-mingw32": "Windows",  # -> i386-unknown-windows-gnu
-            "x86_64-linux-gnu": "Linux",  # -> x86_64-unknown-linux-gnu
-            "i486-linux-gnu": "Linux",  # -> i486-unknown-linux-gnu
-            "i386-redhat-linux": "Linux",  # -> i386-redhat-linux
-            "i686-linux": "Linux",  # -> i686-unknown-linux
-            "arm-none-eabi": "Generic",  # -> arm-unknown-none-eabi (no OS)
-            "ve-linux": "Linux",  # -> ve-unknown-linux
-            "wasm32-wasi": "WASI",  # -> wasm32-unknown-wasi
-            "wasm64-wasi": "WASI",  # -> wasm64-unknown-wasi
-            "x86_64-pc-cygwin": "CYGWIN",  # -> x86_64-pc-windows-cygnus
-            "x86_64-pc-msys": "CYGWIN",  # -> x86_64-pc-windows-cygnus
-            "x86_64-w64-mingw32": "Windows",  # -> x86_64-w64-windows-gnu
-            "i686-w64-mingw32": "Windows",
-        }
-        for triple, want in cases.items():
-            self.assertEqual(g.system_name(self.names, triple), want, triple)
-
-    def test_normalize_special_cases(self):
-        # The OS/environment special-cases that Triple::normalize applies, one
-        # per category, to ensure the script tracks each rewrite it performs.
-        cases = {
-            # Win32 normalizes to "windows" regardless of the incoming spelling
-            # or msvc/gnu environment.
-            "x86_64-pc-windows": "Windows",
-            "x86_64-pc-windows-msvc": "Windows",
-            "x86_64-pc-windows-gnu": "Windows",
-            # mingw* -> windows-gnu; cygwin*/msys -> windows-cygnus.
-            "x86_64-w64-mingw32": "Windows",
-            "x86_64-pc-cygwin": "CYGWIN",
-            "x86_64-pc-msys": "CYGWIN",
-            # androideabi keeps the Android environment override.
-            "arm-linux-androideabi": "Android",
-            # The full Apple OS family. driverkit/bridgeos map to Darwin
-            # directly in the table (they are always Apple); firmware has no
-            # dedicated CMake name and maps to Darwin via the apple-vendor
-            # catch-all.
-            "x86_64-apple-macosx": "Darwin",
-            "arm-apple-darwin": "Darwin",
-            "arm-apple-ios": "iOS",
-            "arm-apple-tvos": "tvOS",
-            "arm-apple-watchos": "watchOS",
-            "arm-apple-xros": "visionOS",
-            "arm64-apple-visionos": "visionOS",
-            "arm-apple-driverkit": "Darwin",
-            "arm-apple-bridgeos": "Darwin",
-            "arm-apple-firmware": "Darwin",
-        }
-        for triple, want in cases.items():
-            self.assertEqual(g.system_name(self.names, triple), want, triple)
-
-    def test_firmware_requires_apple_vendor(self):
-        # firmware has no dedicated CMake name and only maps to Darwin for the
-        # apple vendor. With any other vendor it is Generic. (For a non-apple
-        # vendor Triple::normalize actually fatal-errors; here we only need to
-        # ensure we never claim Darwin.)
-        for vendor in ("none", "unknown", "pc"):
-            triple = f"arm-{vendor}-firmware"
-            self.assertEqual(g.system_name(self.names, triple), "Generic", triple)
-
-    def test_driverkit_bridgeos_always_darwin(self):
-        # driverkit and bridgeos are always Apple, so they map to Darwin
-        # directly in the table regardless of the vendor component.
-        for os_name in ("driverkit", "bridgeos"):
-            for vendor in ("apple", "none", "unknown", "pc"):
-                triple = f"arm-{vendor}-{os_name}"
-                self.assertEqual(g.system_name(self.names, triple), "Darwin", triple)
-
-    def test_bare_os_no_arch(self):
-        # A lone os component with no arch is a valid clang target (e.g.
-        # --target=darwin -> unknown-unknown-darwin), so it must classify by
-        # the first (and only) component rather than being skipped as the arch.
-        cases = {
-            "darwin": "Darwin",
-            "linux": "Linux",
-            "ios": "iOS",
-            "freebsd": "FreeBSD",
-            "wasi": "WASI",
-            "zos": "OS390",
-            "mingw32": "Windows",
-            "cygwin": "CYGWIN",
-        }
-        for triple, want in cases.items():
-            self.assertEqual(g.system_name(self.names, triple), want, triple)
-
-    def test_no_classifiable_os_falls_back(self):
-        # Only when no component classifies as an OS does the caller fall back
-        # to the host system name.
-        self.assertIsNone(g.system_name(self.names, "x86_64"))
-        self.assertIsNone(g.system_name(self.names, "arm-none"))
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/llvm/utils/get_triple_system_name.py b/llvm/utils/get_triple_system_name.py
deleted file mode 100755
index 369c57ada4285..0000000000000
--- a/llvm/utils/get_triple_system_name.py
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/env python3
-"""Derive a CMake system name from a target triple.
-
-The recognized OS and environment names are defined in
-llvm/include/llvm/TargetParser/TripleName.def. This script parses that
-file so the CMake runtimes build can map a (possibly unnormalized)
-triple to a CMake system name without running a compiled tool. CMake
-invokes it once per target with --triple and reads the printed name.
-
-Modes:
-  --triple TRIPLE   Print the CMake system name for TRIPLE (empty if unknown or
-                    the triple has too few components; the caller then falls back
-                    to the host system name).
-
-Options:
-  --def-file PATH   Path to TripleName.def to parse instead of the copy located
-                    relative to this script (in llvm/include/llvm/TargetParser).
-
-"""
-
-import argparse
-import os
-import re
-import sys
-
-_OS_RE = re.compile(r'^\s*TRIPLE_OS\(\s*(\w+)\s*,\s*"([^"]*)"\s*,\s*"([^"]*)"\s*\)')
-_OS_ALIAS_RE = re.compile(r'^\s*TRIPLE_OS_ALIAS\(\s*(\w+)\s*,\s*"([^"]*)"\s*\)')
-_ENV_RE = re.compile(r'^\s*TRIPLE_ENV\(\s*(\w+)\s*,\s*"([^"]*)"\s*,\s*"([^"]*)"\s*\)')
-
-
-class TripleNames:
-    def __init__(self):
-        # Ordered lists of (prefix, value) preserving .def order, which matters
-        # for prefix matching (longer prefixes precede shorter ones).
-        self.os = []  # (name, cmake_name)
-        self.env = []  # (name, cmake_override)
-
-
-def find_def_file():
-    # This script lives in llvm/utils/, the .def in llvm/include/...
-    llvm_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-    return os.path.join(llvm_dir, "include", "llvm", "TargetParser", "TripleName.def")
-
-
-def parse(def_path):
-    names = TripleNames()
-    with open(def_path) as f:
-        lines = f.readlines()
-
-    # First pass: map each OS enum to its CMake name so aliases can reuse it.
-    os_cmake = {}
-    for line in lines:
-        if m := _OS_RE.match(line):
-            enum, _name, cmake_name = m.groups()
-            os_cmake[enum] = cmake_name
-
-    # Second pass: build the ordered lists (order matters for prefix matching).
-    for line in lines:
-        if m := _OS_RE.match(line):
-            _enum, name, cmake_name = m.groups()
-            names.os.append((name, cmake_name))
-        elif m := _OS_ALIAS_RE.match(line):
-            enum, alias = m.groups()
-            names.os.append((alias, os_cmake.get(enum, "Generic")))
-        elif m := _ENV_RE.match(line):
-            _enum, name, override = m.groups()
-            names.env.append((name, override))
-    return names
-
-
-def system_name(names, triple):
-    # Mirror the component classification of Triple::normalize: do not
-    # trust fixed positions. A triple may omit the vendor
-    # (aarch64-linux-android), put the os in the vendor slot
-    # (wasm32-wasi, i686-linux), or even be a bare os with no arch at
-    # all (clang accepts --target=darwin as unknown-unknown-darwin),
-    # so scan every component and use the first that classifies. No
-    # arch name is a prefix of any os/env name, so scanning the first
-    # component too cannot misclassify a real arch. This makes the
-    # result match what normalize would produce even for unnormalized
-    # inputs.
-    parts = triple.split("-")
-
-    # Environment override takes precedence over the OS mapping
-    # (e.g. android wins over the linux in aarch64-linux-android), so
-    # scan for it first.
-    for comp in parts:
-        for name, override in names.env:
-            if override and comp.startswith(name):
-                return override
-
-    # Find the first component that classifies as an OS. A specific
-    # (non-Generic) name wins immediately. A "Generic" match means the
-    # component is a recognized OS with no CMake equivalent.
-    found_generic_os = False
-    for comp in parts:
-        matched = False
-        for name, cmake_name in names.os:
-            if comp.startswith(name):
-                if cmake_name != "Generic":
-                    return cmake_name
-                found_generic_os = True
-                matched = True
-                break
-        if matched:
-            break
-
-    # Handle special case legacy os spellings that normalize rewrites
-    # to windows.
-    for comp in parts:
-        if comp.startswith("mingw"):
-            return "Windows"
-        if comp.startswith("cygwin") or comp.startswith("msys"):
-            return "CYGWIN"
-
-    # Apple vendor triples with no specific CMake OS name (e.g.
-    # firmware) map to Darwin.
-    if len(parts) > 1 and parts[1] == "apple":
-        return "Darwin"
-
-    if found_generic_os:
-        return "Generic"
-
-    # No OS could be identified. Too few components to have one -> let
-    # the caller fall back to the host system name.
-    if len(parts) < 3:
-        return None
-    return "Generic"
-
-
-def main():
-    ap = argparse.ArgumentParser(description=__doc__)
-    ap.add_argument("--def-file", default=None, help="Path to TripleName.def")
-    ap.add_argument(
-        "--triple", required=True, help="Print the CMake system name for this triple"
-    )
-    args = ap.parse_args()
-
-    def_path = args.def_file or find_def_file()
-    names = parse(def_path)
-
-    result = system_name(names, args.triple)
-    print(result if result is not None else "")
-    return 0
-
-
-if __name__ == "__main__":
-    sys.exit(main())



More information about the llvm-commits mailing list