# A cross `llvm-config`. The target llvm-config is a glibc binary that can't run # on the (musl) build host, so instead of executing it we emulate the queries # meson/mesa make, reporting paths inside the sysroot. Self-configuring: it reads # the LLVM version, library soname, and built targets from the installed sysroot, # so it works for any LLVM consumer (mesa now, rust/etc. later) with no hardcoding. _LLVM_CONFIG_EMULATOR = r'''#!/usr/bin/env python3 import glob, re, sys SYSROOT = "/sysroot" LIBDIR = SYSROOT + "/usr/lib" INCDIR = SYSROOT + "/usr/include" _major = "" for _p in sorted(glob.glob(LIBDIR + "/libLLVM-*.so*")): _m = re.search(r"libLLVM-(\d+)", _p) if _m: _major = _m.group(1) break _version = (_major + ".0.0") if _major else "0.0.0" try: with open(INCDIR + "/llvm/Config/llvm-config.h") as _f: _m = re.search(r'LLVM_VERSION_STRING\s+"([^"]+)"', _f.read()) if _m: _version = _m.group(1) except OSError: pass _targets = [] try: with open(INCDIR + "/llvm/Config/Targets.def") as _f: _targets = re.findall(r"LLVM_TARGET\((\w+)\)", _f.read()) except OSError: pass if not _targets: _targets = ["X86", "AMDGPU"] _GENERIC = ( "aggressiveinstcombine all all-targets analysis asmparser asmprinter " "binaryformat bitreader bitstreamreader bitwriter cfguard codegen " "codegentypes core coroutines coverage debuginfocodeview debuginfodwarf " "debuginfomsf debuginfopdb demangle dlltooldriver engine executionengine " "extensions frontenddriver frontendhlsl frontendoffloading frontendopenmp " "fuzzmutate globalisel instcombine instrumentation interpreter ipo irreader " "irprinter jitlink libdriver lineeditor linker lto mc mca mcdisassembler " "mcjit mcparser native nativecodegen object objectyaml option orcjit " "orcshared orctargetprocess passes profiledata remarks runtimedyld " "scalaropts selectiondag support symbolize target targetparser textapi " "transformutils vectorize windowsdriver windowsmanifest" ).split() def _components(): comps = list(_GENERIC) for t in _targets: tl = t.lower() comps += [tl, tl + "asmparser", tl + "codegen", tl + "desc", tl + "disassembler", tl + "info", tl + "targetmca", tl + "utils"] return " ".join(sorted(set(comps))) _H = { "--version": lambda: _version, "--components": _components, "--targets-built": lambda: " ".join(_targets), "--prefix": lambda: SYSROOT + "/usr", "--bindir": lambda: SYSROOT + "/usr/bin", "--includedir": lambda: INCDIR, "--libdir": lambda: LIBDIR, "--cmakedir": lambda: LIBDIR + "/cmake/llvm", "--has-rtti": lambda: "YES", "--shared-mode": lambda: "shared", "--libs": lambda: "-lLLVM-" + _major, "--system-libs": lambda: "", "--cflags": lambda: "-I" + INCDIR, "--cppflags": lambda: ("-I" + INCDIR + " -D__STDC_CONSTANT_MACROS" + " -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS"), "--cxxflags": lambda: ("-I" + INCDIR + " -D__STDC_CONSTANT_MACROS" + " -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS"), "--ldflags": lambda: "-L" + LIBDIR, } for _a in sys.argv[1:]: if _a in _H: print(_H[_a]()) ''' def meson_cross_file(self): cross = self.build_dir / "meson-cross.ini" llvm_config = self.build_dir / "llvm-config" self.write_text(llvm_config, _LLVM_CONFIG_EMULATOR) self.run("chmod", "+x", llvm_config) self.write_text( cross, f"""\ [binaries] c = '{self.triple}-gcc' cpp = '{self.triple}-g++' ar = '{self.triple}-gcc-ar' nm = '{self.triple}-nm' objcopy = '{self.triple}-objcopy' ranlib = '{self.triple}-ranlib' strip = '{self.triple}-strip' pkg-config = '{self.triple}-pkg-config' cmake = '/usr/bin/cmake' llvm-config = '{llvm_config}' [host_machine] system = 'linux' cpu_family = '{self.arch}' cpu = '{self.arch}' endian = 'little' """, ) return cross def meson_configure( self, extra_args=(), extra_env=None, *, source_dir=None, flags=True, host=False ): p = self.options env = {} if flags: env.update( { "CFLAGS": p.get("cflags", ""), "CXXFLAGS": p.get("cxxflags", ""), "LDFLAGS": p.get("ldflags", ""), } ) if extra_env: env.update(extra_env) cross_args = [] if host else ["--cross-file", meson_cross_file(self)] self.run( "meson", "setup", source_dir or self.source_dir, *cross_args, f"--prefix={p.get('prefix', '/usr')}", f"--sysconfdir={p.get('sysconfdir', '/etc')}", f"--localstatedir={p.get('localstatedir', '/var')}", "--libdir=lib", "--sbindir=bin", "--bindir=bin", "--datadir=share", "--buildtype=release", "-Ddefault_library=shared", *extra_args, env=env, ) def meson_build(self, extra_args=()): self.run("meson", "compile", f"-j{self.jobs}", *extra_args) def meson_install(self, extra_args=()): self.run( "meson", "install", "--no-rebuild", *extra_args, env={"DESTDIR": str(self.dest_dir)}, ) def meson(*, configure_args=(), configure_env=None, build_args=(), install_args=()): def _configure(self): meson_configure(self, configure_args, configure_env) def _build(self): meson_build(self, build_args) def _install(self): meson_install(self, install_args) return _configure, _build, _install