From ecf4829de7b9683a680176e9dff85ba11c0f03d9 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 13 Aug 2020 16:03:09 +0200 Subject: llvm: added external detection capabilities (#17989) * llvm: added external detection capabilities * Added comment with reference to external package detection docs * Fix typo in a comment --- var/spack/repos/builtin/packages/llvm/package.py | 109 ++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/llvm/package.py b/var/spack/repos/builtin/packages/llvm/package.py index 9573c5d715..95ffcc51fd 100644 --- a/var/spack/repos/builtin/packages/llvm/package.py +++ b/var/spack/repos/builtin/packages/llvm/package.py @@ -2,10 +2,13 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - -from spack import * +import os.path +import re import sys +import llnl.util.tty as tty +import spack.util.executable + class Llvm(CMakePackage, CudaPackage): """The LLVM Project is a collection of modular and reusable compiler and @@ -204,6 +207,108 @@ class Llvm(CMakePackage, CudaPackage): # https://bugs.llvm.org/show_bug.cgi?id=39696 patch("thread-p9.patch", when="@develop+libcxx") + # The functions and attributes below implement external package + # detection for LLVM. See: + # + # https://spack.readthedocs.io/en/latest/packaging_guide.html#making-a-package-discoverable-with-spack-external-find + executables = ['clang', 'ld.lld', 'lldb'] + + @classmethod + def filter_detected_exes(cls, prefix, exes_in_prefix): + result = [] + for exe in exes_in_prefix: + # Executables like lldb-vscode-X are daemon listening + # on some port and would hang Spack during detection. + # clang-cl and clang-cpp are dev tools that we don't + # need to test + if any(x in exe for x in ('vscode', 'cpp', '-cl', '-gpu')): + continue + result.append(exe) + return result + + @classmethod + def determine_version(cls, exe): + version_regex = re.compile( + # Normal clang compiler versions are left as-is + r'clang version ([^ )]+)-svn[~.\w\d-]*|' + # Don't include hyphenated patch numbers in the version + # (see https://github.com/spack/spack/pull/14365 for details) + r'clang version ([^ )]+?)-[~.\w\d-]*|' + r'clang version ([^ )]+)|' + # LLDB + r'lldb version ([^ )\n]+)|' + # LLD + r'LLD ([^ )\n]+) \(compatible with GNU linkers\)' + ) + try: + compiler = Executable(exe) + output = compiler('--version', output=str, error=str) + if 'Apple' in output: + return None + match = version_regex.search(output) + if match: + return match.group(match.lastindex) + except spack.util.executable.ProcessError: + pass + except Exception as e: + tty.debug(e) + + return None + + @classmethod + def determine_variants(cls, exes, version_str): + variants, compilers = ['+clang'], {} + lld_found, lldb_found = False, False + for exe in exes: + if 'clang++' in exe: + compilers['cxx'] = exe + elif 'clang' in exe: + compilers['c'] = exe + elif 'ld.lld' in exe: + lld_found = True + compilers['ld'] = exe + elif 'lldb' in exe: + lldb_found = True + compilers['lldb'] = exe + + variants.append('+lld' if lld_found else '~lld') + variants.append('+lldb' if lldb_found else '~lldb') + + return ''.join(variants), {'compilers': compilers} + + @classmethod + def validate_detected_spec(cls, spec, extra_attributes): + # For LLVM 'compilers' is a mandatory attribute + msg = ('the extra attribute "compilers" must be set for ' + 'the detected spec "{0}"'.format(spec)) + assert 'compilers' in extra_attributes, msg + compilers = extra_attributes['compilers'] + for key in ('c', 'cxx'): + msg = '{0} compiler not found for {1}' + assert key in compilers, msg.format(key, spec) + + @property + def cc(self): + msg = "cannot retrieve C compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes['compilers'].get('c', None) + result = None + if '+clang' in self.spec: + result = os.path.join(self.spec.prefix.bin, 'clang') + return result + + @property + def cxx(self): + msg = "cannot retrieve C++ compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes['compilers'].get('cxx', None) + result = None + if '+clang' in self.spec: + result = os.path.join(self.spec.prefix.bin, 'clang++') + return result + @run_before('cmake') def codesign_check(self): if self.spec.satisfies("+code_signing"): -- cgit v1.2.3-60-g2f50