diff options
Diffstat (limited to 'tools/find_llvm.py')
| -rw-r--r-- | tools/find_llvm.py | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/tools/find_llvm.py b/tools/find_llvm.py new file mode 100644 index 0000000..a0420bf --- /dev/null +++ b/tools/find_llvm.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# Locate an LLVM install that ships the LLDB headers, mirroring the search order +# the old premake5.lua used. Meson calls this at configure time and parses the +# KEY=value lines below; run it by hand to see what would be picked. +# +# Precedence: -Dllvm_prefix (argv[1]) -> $LLVM_PREFIX -> vendored ext/llvm -> +# `llvm-config --prefix` -> per-platform well-known locations. A candidate only +# counts if it actually contains include/lldb. +# +# Output (stdout), only when a usable prefix is found: +# prefix=<dir> +# incdir=<dir>/include +# libdir=<dir>/lib +# lib=<full path to liblldb> +# dll=<path> (zero or more, Windows runtime libraries only) +# Exit status is non-zero when nothing usable was found. + +import glob +import os +import platform +import subprocess +import sys + +REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +VENDORED = os.path.join(REPO_ROOT, "ext", "llvm") + + +def norm(path): + # forward slashes so the value can be baked into a C string literal without + # a backslash being read as an escape (matters for HSDBG_LLVM_PREFIX) + return os.path.abspath(path).replace("\\", "/") + + +def usable(candidate): + if not candidate: + return None + candidate = candidate.strip() + if not candidate: + return None + prefix = norm(candidate) + if os.path.isdir(os.path.join(prefix, "include", "lldb")): + return prefix + return None + + +def command_output(*args): + try: + out = subprocess.run( + args, capture_output=True, text=True, check=False + ) + except OSError: + return None + if out.returncode != 0: + return None + return out.stdout.strip() or None + + +def newest_of(pattern): + matches = sorted(glob.glob(pattern)) + for candidate in reversed(matches): + prefix = usable(candidate) + if prefix: + return prefix + return None + + +def find_prefix(override): + prefix = usable(override) or usable(os.environ.get("LLVM_PREFIX")) + if prefix: + return prefix + + prefix = usable(VENDORED) + if prefix: + return prefix + + prefix = usable(command_output("llvm-config", "--prefix")) + if prefix: + return prefix + + host = platform.system() + + if host == "Windows": + program_files = os.environ.get("ProgramFiles") + if program_files: + prefix = usable(os.path.join(program_files, "LLVM")) + if prefix: + return prefix + return newest_of("C:/Program Files/LLVM*") + + if host == "Darwin": + return usable(command_output("brew", "--prefix", "llvm")) + + if host == "Linux": + return newest_of("/usr/lib/llvm-*") or newest_of("/usr/local/llvm*") + + return None + + +def lldb_library(libdir): + host = platform.system() + if host == "Windows": + names = ["liblldb.lib"] + elif host == "Darwin": + names = ["liblldb.dylib"] + else: + names = ["liblldb.so"] + + for name in names: + candidate = os.path.join(libdir, name) + if os.path.isfile(candidate): + return norm(candidate) + + versioned = sorted(glob.glob(os.path.join(libdir, "liblldb.so.*"))) + if versioned: + return norm(versioned[-1]) + + # nothing on disk yet (e.g. a cross setup); hand back the expected path so + # the caller gets a clear link-time error rather than a silent misconfigure + return norm(os.path.join(libdir, names[0])) + + +def windows_dlls(prefix): + bindir = os.path.join(prefix, "bin") + runtimes = glob.glob(os.path.join(bindir, "liblldb.dll")) + runtimes += glob.glob(os.path.join(bindir, "python*.dll")) + if not runtimes: + runtimes = [os.path.join(bindir, "liblldb.dll")] + return [norm(path) for path in runtimes] + + +def main(): + override = sys.argv[1] if len(sys.argv) > 1 else "" + prefix = find_prefix(override) + + if not prefix: + sys.stderr.write("no llvm with lldb headers found\n") + return 1 + + incdir = norm(os.path.join(prefix, "include")) + libdir = norm(os.path.join(prefix, "lib")) + + print("prefix=" + prefix) + print("incdir=" + incdir) + print("libdir=" + libdir) + print("lib=" + lldb_library(libdir)) + + if platform.system() == "Windows": + for dll in windows_dlls(prefix): + print("dll=" + dll) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) |
