diff --git a/var/spack/repos/builtin/packages/llvm/package.py b/var/spack/repos/builtin/packages/llvm/package.py index ae907cd50d..e770b2c11d 100644 --- a/var/spack/repos/builtin/packages/llvm/package.py +++ b/var/spack/repos/builtin/packages/llvm/package.py @@ -936,7 +936,9 @@ def cmake_args(self): cmake_args.append(from_variant("LIBOMP_TSAN_SUPPORT", "libomp_tsan")) - if self.compiler.name == "gcc": + # From clang 16 onwards we use a more precise --gcc-install-dir flag in post-install + # generated config files. + if self.spec.satisfies("@:15 %gcc"): cmake_args.append(define("GCC_INSTALL_PREFIX", self.compiler.prefix)) if self.spec.satisfies("~code_signing platform=darwin"): @@ -976,12 +978,24 @@ def cmake_args(self): runtimes_order.index(x) if x in runtimes_order else len(runtimes_order) ) ) + + # CMake args passed just to runtimes + runtime_cmake_args = [define("CMAKE_INSTALL_RPATH_USE_LINK_PATH", True)] + + # When building runtimes, just-built clang has to know where GCC is. + gcc_install_dir_flag = get_gcc_install_dir_flag(spec, self.compiler) + if gcc_install_dir_flag: + runtime_cmake_args.extend( + [ + define("CMAKE_C_FLAGS", gcc_install_dir_flag), + define("CMAKE_CXX_FLAGS", gcc_install_dir_flag), + ] + ) + cmake_args.extend( [ define("LLVM_ENABLE_RUNTIMES", runtimes), - define( - "RUNTIMES_CMAKE_ARGS", [define("CMAKE_INSTALL_RPATH_USE_LINK_PATH", True)] - ), + define("RUNTIMES_CMAKE_ARGS", runtime_cmake_args), ] ) @@ -1031,6 +1045,19 @@ def post_install(self): with working_dir(self.build_directory): install_tree("bin", join_path(self.prefix, "libexec", "llvm")) + cfg_files = [] + if spec.satisfies("+clang"): + cfg_files.extend(("clang.cfg", "clang++.cfg")) + if spec.satisfies("@19: +flang"): + # The config file is `flang.cfg` even though the executable is `flang-new`. + # `--gcc-install-dir` / `--gcc-toolchain` support was only added in LLVM 19. + cfg_files.append("flang.cfg") + gcc_install_dir_flag = get_gcc_install_dir_flag(spec, self.compiler) + if gcc_install_dir_flag: + for cfg in cfg_files: + with open(os.path.join(self.prefix.bin, cfg), "w") as f: + print(gcc_install_dir_flag, file=f) + def llvm_config(self, *args, **kwargs): lc = Executable(self.prefix.bin.join("llvm-config")) if not kwargs.get("output"): @@ -1042,6 +1069,18 @@ def llvm_config(self, *args, **kwargs): return ret +def get_gcc_install_dir_flag(spec: Spec, compiler) -> Optional[str]: + """Get the --gcc-install-dir=... flag, so that clang does not do a system scan for GCC.""" + if not spec.satisfies("@16: %gcc"): + return None + gcc = Executable(compiler.cc) + libgcc_path = gcc("-print-file-name=libgcc.a", output=str, fail_on_error=False).strip() + if not os.path.isabs(libgcc_path): + return None + libgcc_dir = os.path.dirname(libgcc_path) + return f"--gcc-install-dir={libgcc_dir}" if os.path.exists(libgcc_dir) else None + + def get_llvm_targets_to_build(spec): targets = spec.variants["targets"].value