Simplified compiler finding logic and caching.

This commit is contained in:
Todd Gamblin 2014-06-23 08:53:08 -07:00
parent f7fe65102f
commit 8e066ebf2a
4 changed files with 39 additions and 66 deletions

View File

@ -34,6 +34,7 @@
import spack.spec import spack.spec
import spack.config import spack.config
from spack.compilation import get_path from spack.compilation import get_path
from spack.spec import CompilerSpec
description = "Manage compilers" description = "Manage compilers"
@ -50,8 +51,13 @@ def setup_parser(subparser):
list_parser = sp.add_parser('list', help='list available compilers') 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): 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 paths = args.add_paths
if not paths: if not paths:
paths = get_path('PATH') paths = get_path('PATH')
@ -64,9 +70,24 @@ def compiler_remove(args):
pass 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): def compiler_list(args):
tty.msg("Available compilers") tty.msg("Available compilers")
index = index_by(spack.compilers.all_compilers(), 'name') index = index_by(spack.compilers.all_compilers(), 'name')
for name, compilers in index.items(): for name, compilers in index.items():
tty.hline(name, char='-', color=spack.spec.compiler_color) tty.hline(name, char='-', color=spack.spec.compiler_color)
@ -76,6 +97,6 @@ def compiler_list(args):
def compiler(parser, args): def compiler(parser, args):
action = { 'add' : compiler_add, action = { 'add' : compiler_add,
'remove' : compiler_remove, 'remove' : compiler_remove,
'info' : compiler_info,
'list' : compiler_list } 'list' : compiler_list }
action[args.compiler_command](args) action[args.compiler_command](args)

View File

@ -54,7 +54,7 @@ def get_compiler_version(compiler_path, version_arg, regex='(.*)'):
output = compiler(version_arg, return_output=True, error=None) output = compiler(version_arg, return_output=True, error=None)
match = re.search(regex, output) 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] return _version_cache[compiler_path]
@ -95,7 +95,7 @@ class Compiler(object):
arg_rpath = '-Wl,-rpath,%s' 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): def check(exe):
if exe is None: if exe is None:
return None return None
@ -107,55 +107,20 @@ def check(exe):
self.f77 = check(f77) self.f77 = check(f77)
self.fc = check(fc) self.fc = check(fc)
# Allow versions to be memoized so we don't have to run self.spec = cspec
# 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()
@property @property
def version(self): def version(self):
if not self._version: return self.spec.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)
#
# 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 @classmethod
def default_version(cls, cc): 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 cxx_names, etc. and it will group them if they have common
prefixes, suffixes, and versions. e.g., gcc-mp-4.7 would prefixes, suffixes, and versions. e.g., gcc-mp-4.7 would
be grouped with g++-mp-4.7 and gfortran-mp-4.7. 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( dicts = parmap(
lambda t: cls._find_matches_in_path(*t), lambda t: cls._find_matches_in_path(*t),
@ -263,8 +218,8 @@ def find(cls, *path):
for k in all_keys: for k in all_keys:
ver, pre, suf = k ver, pre, suf = k
paths = tuple(pn[k] if k in pn else None for pn in dicts) paths = tuple(pn[k] if k in pn else None for pn in dicts)
args = paths + (ver,) spec = spack.spec.CompilerSpec(cls.name, ver)
compilers.append(cls(*args)) compilers.append(cls(spec, *paths))
return compilers return compilers

View File

@ -118,7 +118,6 @@ def find_compilers(*path):
# ensure all the version calls we made are cached in the parent # ensure all the version calls we made are cached in the parent
# process, as well. This speeds up Spack a lot. # process, as well. This speeds up Spack a lot.
clist = reduce(lambda x,y: x+y, compiler_lists) clist = reduce(lambda x,y: x+y, compiler_lists)
for c in clist: c._cache_version()
return clist return clist
@ -191,8 +190,7 @@ def get_compiler(cspec):
else: else:
compiler_paths.append(None) compiler_paths.append(None)
args = tuple(compiler_paths) + (compiler_spec.version,) return cls(cspec, *compiler_paths)
return cls(*args)
matches = find(compiler_spec) matches = find(compiler_spec)
return [get_compiler(cspec) for cspec in matches] return [get_compiler(cspec) for cspec in matches]

View File

@ -22,7 +22,7 @@
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
from spack.compiler import Compiler from spack.compiler import *
class Clang(Compiler): class Clang(Compiler):
# Subclasses use possible names of C compiler # Subclasses use possible names of C compiler
@ -48,5 +48,4 @@ def default_version(self, comp):
Thread model: posix Thread model: posix
""" """
return get_compiler_version( return get_compiler_version(
comp, '--version', r'clang version ([^ ]+)') comp, '--version', r'(?:clang version|based on LLVM) ([^ )]+)')