148 lines
5.2 KiB
Python
Executable file
148 lines
5.2 KiB
Python
Executable file
#!/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())
|