Refactored _find_matches_in_path

Now the function takes a compiler language and computes the compiler
names and detection function.

Skipping values while iterating has been changed to filter input values
+ iterate without jumps.
This commit is contained in:
Massimiliano Culpo 2018-12-20 14:30:23 +01:00
parent 0a8f4ad42e
commit cae7e075a6
No known key found for this signature in database
GPG Key ID: D1ADB1014FF1118C
2 changed files with 60 additions and 39 deletions

View File

@ -255,7 +255,7 @@ def find_compilers(self, *path_hints):
clist = [comp for cl in compiler_lists for comp in cl] clist = [comp for cl in compiler_lists for comp in cl]
return clist return clist
def find_compiler(self, cmp_cls, *path): def find_compiler(self, cmp_cls, *search_paths):
"""Try to find the given type of compiler in the user's """Try to find the given type of compiler in the user's
environment. For each set of compilers found, this returns environment. For each set of compilers found, this returns
compiler objects with the cc, cxx, f77, fc paths and the compiler objects with the cc, cxx, f77, fc paths and the
@ -268,24 +268,24 @@ def find_compiler(self, cmp_cls, *path):
""" """
dicts = mp.parmap( dicts = mp.parmap(
lambda t: cmp_cls._find_matches_in_path(*t), lambda t: cmp_cls._find_matches_in_path(*t),
[(cmp_cls.cc_names, cmp_cls.cc_version) + tuple(path), [('cc',) + tuple(search_paths), ('cxx',) + tuple(search_paths),
(cmp_cls.cxx_names, cmp_cls.cxx_version) + tuple(path), ('f77',) + tuple(search_paths), ('fc',) + tuple(search_paths)])
(cmp_cls.f77_names, cmp_cls.f77_version) + tuple(path),
(cmp_cls.fc_names, cmp_cls.fc_version) + tuple(path)])
all_keys = set() all_keys = set(key for d in dicts for key in d)
for d in dicts:
all_keys.update(d) # Skip compilers with unknown version
def has_known_version(x):
"""Returns True if the key has not an unknown version."""
version, _, _ = x
return version != 'unknown'
valid_keys = filter(has_known_version, all_keys)
compilers = {} compilers = {}
for k in all_keys: for k in valid_keys:
ver, pre, suf = k ver, _, _ = k
# Skip compilers with unknown version. paths = tuple(pn.get(k, None) for pn in dicts)
if ver == 'unknown':
continue
paths = tuple(pn[k] if k in pn else None for pn in dicts)
spec = spack.spec.CompilerSpec(cmp_cls.name, ver) spec = spack.spec.CompilerSpec(cmp_cls.name, ver)
if ver in compilers: if ver in compilers:

View File

@ -249,37 +249,58 @@ def fc_version(cls, fc):
return cls.default_version(fc) return cls.default_version(fc)
@classmethod @classmethod
def _find_matches_in_path(cls, compiler_names, detect_version, *path): def _find_matches_in_path(cls, compiler_language, *search_paths):
"""Finds compilers in the paths supplied. """Finds compilers for a given language in the paths supplied.
Looks for all combinations of ``compiler_names`` with the Looks for all combinations of ``compiler_names`` with the
``prefixes`` and ``suffixes`` defined for this compiler ``prefixes`` and ``suffixes`` defined for this compiler
class. If any compilers match the compiler_names, class. If any compilers match the compiler_names,
prefixes, or suffixes, uses ``detect_version`` to figure prefixes, or suffixes, uses ``detect_version`` to figure
out what version the compiler is. out what version the compiler is.
This returns a dict with compilers grouped by (prefix, Args:
suffix, version) tuples. This can be further organized by compiler_language (str): language of the compiler (either
find(). 'cc', 'cxx', 'f77' or 'fc')
*search_paths (list of paths): paths where to look for a
compiler
Returns:
Dictionary with compilers grouped by (version, prefix, suffix)
tuples.
""" """
def is_accessible_dir(x):
"""Returns True if the argument is an accessible directory."""
return os.path.isdir(x) and os.access(x, os.R_OK | os.X_OK)
# Select accessible directories
search_directories = filter(is_accessible_dir, search_paths)
# Get compiler names and the callback to detect their versions
compiler_names = getattr(cls, '{0}_names'.format(compiler_language))
detect_version = getattr(cls, '{0}_version'.format(compiler_language))
# Compile all the regular expressions used for files beforehand
prefixes = [''] + cls.prefixes prefixes = [''] + cls.prefixes
suffixes = [''] + cls.suffixes suffixes = [''] + cls.suffixes
regexp_fmt = r'^({0}){1}({2})$'
search_regexps = [
re.compile(regexp_fmt.format(prefix, re.escape(name), suffix))
for prefix, name, suffix in
itertools.product(prefixes, compiler_names, suffixes)
]
# Select only the files matching a regexp
checks = [] checks = []
for directory in path: for d in search_directories:
if not (os.path.isdir(directory) and # Only select actual files, use the full path
os.access(directory, os.R_OK | os.X_OK)): files = filter(
continue os.path.isfile, [os.path.join(d, f) for f in os.listdir(d)]
)
files = os.listdir(directory) for full_path in files:
for exe in files: file = os.path.basename(full_path)
full_path = os.path.join(directory, exe) for regexp in search_regexps:
match = regexp.match(file)
prod = itertools.product(prefixes, compiler_names, suffixes)
for pre, name, suf in prod:
regex = r'^(%s)%s(%s)$' % (pre, re.escape(name), suf)
match = re.match(regex, exe)
if match: if match:
key = (full_path,) + match.groups() + (detect_version,) key = (full_path,) + match.groups() + (detect_version,)
checks.append(key) checks.append(key)