Simplified compiler finding logic and caching.
This commit is contained in:
		@@ -34,6 +34,7 @@
 | 
			
		||||
import spack.spec
 | 
			
		||||
import spack.config
 | 
			
		||||
from spack.compilation import get_path
 | 
			
		||||
from spack.spec import CompilerSpec
 | 
			
		||||
 | 
			
		||||
description = "Manage compilers"
 | 
			
		||||
 | 
			
		||||
@@ -50,8 +51,13 @@ def setup_parser(subparser):
 | 
			
		||||
 | 
			
		||||
    list_parser   = sp.add_parser('list', help='list available compilers')
 | 
			
		||||
 | 
			
		||||
    info_parser   = sp.add_parser('info', help='Show compiler paths.')
 | 
			
		||||
    info_parser.add_argument('compiler_spec')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def compiler_add(args):
 | 
			
		||||
    """Search either $PATH or a list of paths for compilers and add them
 | 
			
		||||
       to Spack's configuration."""
 | 
			
		||||
    paths = args.add_paths
 | 
			
		||||
    if not paths:
 | 
			
		||||
        paths = get_path('PATH')
 | 
			
		||||
@@ -64,9 +70,24 @@ def compiler_remove(args):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def compiler_info(args):
 | 
			
		||||
    """Print info about all compilers matching a spec."""
 | 
			
		||||
    cspec = CompilerSpec(args.compiler_spec)
 | 
			
		||||
    compilers = spack.compilers.compilers_for_spec(cspec)
 | 
			
		||||
 | 
			
		||||
    if not compilers:
 | 
			
		||||
        tty.error("No compilers match spec %s." % cspec)
 | 
			
		||||
    else:
 | 
			
		||||
        for c in compilers:
 | 
			
		||||
            print str(c.spec) + ":"
 | 
			
		||||
            print "\tcc  = %s" % c.cc
 | 
			
		||||
            print "\tcxx = %s" % c.cxx
 | 
			
		||||
            print "\tf77 = %s" % c.f77
 | 
			
		||||
            print "\tfc  = %s" % c.fc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def compiler_list(args):
 | 
			
		||||
    tty.msg("Available compilers")
 | 
			
		||||
 | 
			
		||||
    index = index_by(spack.compilers.all_compilers(), 'name')
 | 
			
		||||
    for name, compilers in index.items():
 | 
			
		||||
        tty.hline(name, char='-', color=spack.spec.compiler_color)
 | 
			
		||||
@@ -76,6 +97,6 @@ def compiler_list(args):
 | 
			
		||||
def compiler(parser, args):
 | 
			
		||||
    action = { 'add'    : compiler_add,
 | 
			
		||||
               'remove' : compiler_remove,
 | 
			
		||||
               'info'   : compiler_info,
 | 
			
		||||
               'list'   : compiler_list }
 | 
			
		||||
    action[args.compiler_command](args)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ def get_compiler_version(compiler_path, version_arg, regex='(.*)'):
 | 
			
		||||
        output = compiler(version_arg, return_output=True, error=None)
 | 
			
		||||
 | 
			
		||||
        match = re.search(regex, output)
 | 
			
		||||
        _version_cache[compiler_path] = match.group(1) if match else None
 | 
			
		||||
        _version_cache[compiler_path] = match.group(1) if match else 'unknown'
 | 
			
		||||
 | 
			
		||||
    return _version_cache[compiler_path]
 | 
			
		||||
 | 
			
		||||
@@ -95,7 +95,7 @@ class Compiler(object):
 | 
			
		||||
    arg_rpath   = '-Wl,-rpath,%s'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __init__(self, cc, cxx, f77, fc, version=None):
 | 
			
		||||
    def __init__(self, cspec, cc, cxx, f77, fc):
 | 
			
		||||
        def check(exe):
 | 
			
		||||
            if exe is None:
 | 
			
		||||
                return None
 | 
			
		||||
@@ -107,55 +107,20 @@ def check(exe):
 | 
			
		||||
        self.f77 = check(f77)
 | 
			
		||||
        self.fc  = check(fc)
 | 
			
		||||
 | 
			
		||||
        # Allow versions to be memoized so we don't have to run
 | 
			
		||||
        # compilers many times.  Record them in the version cache if
 | 
			
		||||
        # we get them in a constructor
 | 
			
		||||
        #
 | 
			
		||||
        # TODO: what to do if compilers have different versions?
 | 
			
		||||
        #
 | 
			
		||||
        self._version = version
 | 
			
		||||
        self._cache_version()
 | 
			
		||||
        self.spec = cspec
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def version(self):
 | 
			
		||||
        if not self._version:
 | 
			
		||||
            v = self.cc_version(self.cc)
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self._version = v
 | 
			
		||||
                return Version(v)
 | 
			
		||||
 | 
			
		||||
            v = self.cxx_version(self.cxx)
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self._version = v
 | 
			
		||||
                return Version(v)
 | 
			
		||||
 | 
			
		||||
            v = self.f77_version(self.f77)
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self._version = v
 | 
			
		||||
                return Version(v)
 | 
			
		||||
 | 
			
		||||
            v = self.fc_version(self.fc)
 | 
			
		||||
            if v is not None:
 | 
			
		||||
                self._version = v
 | 
			
		||||
                return Version(v)
 | 
			
		||||
 | 
			
		||||
            raise InvalidCompilerError()
 | 
			
		||||
 | 
			
		||||
        return Version(self._version)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _cache_version(self):
 | 
			
		||||
        _version_cache[self.cc] = self._version
 | 
			
		||||
        _version_cache[self.cxx] = self._version
 | 
			
		||||
        _version_cache[self.f77] = self._version
 | 
			
		||||
        _version_cache[self.fc] = self._version
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def spec(self):
 | 
			
		||||
        return spack.spec.CompilerSpec(self.name, self.version)
 | 
			
		||||
        return self.spec.version
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # Compiler classes have methods for querying the version of
 | 
			
		||||
    # specific compiler executables.  This is used when discovering compilers.
 | 
			
		||||
    #
 | 
			
		||||
    # Compiler *instances* are just data objects, and can only be
 | 
			
		||||
    # constructed from an actual set of executables.
 | 
			
		||||
    #
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def default_version(cls, cc):
 | 
			
		||||
@@ -237,16 +202,6 @@ def find(cls, *path):
 | 
			
		||||
           cxx_names, etc. and it will group them if they have common
 | 
			
		||||
           prefixes, suffixes, and versions.  e.g., gcc-mp-4.7 would
 | 
			
		||||
           be grouped with g++-mp-4.7 and gfortran-mp-4.7.
 | 
			
		||||
 | 
			
		||||
           Example return values::
 | 
			
		||||
 | 
			
		||||
               [ gcc('/usr/bin/gcc',      '/usr/bin/g++',
 | 
			
		||||
                     '/usr/bin/gfortran', '/usr/bin/gfortran',
 | 
			
		||||
                     Version('4.4.5')),
 | 
			
		||||
                 gcc('/usr/bin/gcc-mp-4.5',      '/usr/bin/g++-mp-4.5',
 | 
			
		||||
                     '/usr/bin/gfortran-mp-4.5', '/usr/bin/gfortran-mp-4.5',
 | 
			
		||||
                     Version('4.7.2')) ]
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        dicts = parmap(
 | 
			
		||||
            lambda t: cls._find_matches_in_path(*t),
 | 
			
		||||
@@ -263,8 +218,8 @@ def find(cls, *path):
 | 
			
		||||
        for k in all_keys:
 | 
			
		||||
            ver, pre, suf = k
 | 
			
		||||
            paths = tuple(pn[k] if k in pn else None for pn in dicts)
 | 
			
		||||
            args = paths + (ver,)
 | 
			
		||||
            compilers.append(cls(*args))
 | 
			
		||||
            spec = spack.spec.CompilerSpec(cls.name, ver)
 | 
			
		||||
            compilers.append(cls(spec, *paths))
 | 
			
		||||
 | 
			
		||||
        return compilers
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,6 @@ def find_compilers(*path):
 | 
			
		||||
    # ensure all the version calls we made are cached in the parent
 | 
			
		||||
    # process, as well.  This speeds up Spack a lot.
 | 
			
		||||
    clist = reduce(lambda x,y: x+y, compiler_lists)
 | 
			
		||||
    for c in clist: c._cache_version()
 | 
			
		||||
    return clist
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -191,8 +190,7 @@ def get_compiler(cspec):
 | 
			
		||||
            else:
 | 
			
		||||
                compiler_paths.append(None)
 | 
			
		||||
 | 
			
		||||
        args = tuple(compiler_paths) + (compiler_spec.version,)
 | 
			
		||||
        return cls(*args)
 | 
			
		||||
        return cls(cspec, *compiler_paths)
 | 
			
		||||
 | 
			
		||||
    matches = find(compiler_spec)
 | 
			
		||||
    return [get_compiler(cspec) for cspec in matches]
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
			
		||||
##############################################################################
 | 
			
		||||
from spack.compiler import Compiler
 | 
			
		||||
from spack.compiler import *
 | 
			
		||||
 | 
			
		||||
class Clang(Compiler):
 | 
			
		||||
    # Subclasses use possible names of C compiler
 | 
			
		||||
@@ -48,5 +48,4 @@ def default_version(self, comp):
 | 
			
		||||
               Thread model: posix
 | 
			
		||||
        """
 | 
			
		||||
        return get_compiler_version(
 | 
			
		||||
            comp, '--version', r'clang version ([^ ]+)')
 | 
			
		||||
 | 
			
		||||
            comp, '--version', r'(?:clang version|based on LLVM) ([^ )]+)')
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user