aboutsummaryrefslogtreecommitdiff
path: root/tools/find_llvm.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/find_llvm.py')
-rw-r--r--tools/find_llvm.py155
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())