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]
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
environment. For each set of compilers found, this returns
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(
lambda t: cmp_cls._find_matches_in_path(*t),
[(cmp_cls.cc_names, cmp_cls.cc_version) + tuple(path),
(cmp_cls.cxx_names, cmp_cls.cxx_version) + tuple(path),
(cmp_cls.f77_names, cmp_cls.f77_version) + tuple(path),
(cmp_cls.fc_names, cmp_cls.fc_version) + tuple(path)])
[('cc',) + tuple(search_paths), ('cxx',) + tuple(search_paths),
('f77',) + tuple(search_paths), ('fc',) + tuple(search_paths)])
all_keys = set()
for d in dicts:
all_keys.update(d)
all_keys = set(key for d in dicts for key in 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 = {}
for k in all_keys:
ver, pre, suf = k
for k in valid_keys:
ver, _, _ = k
# Skip compilers with unknown version.
if ver == 'unknown':
continue
paths = tuple(pn[k] if k in pn else None for pn in dicts)
paths = tuple(pn.get(k, None) for pn in dicts)
spec = spack.spec.CompilerSpec(cmp_cls.name, ver)
if ver in compilers:

View File

@ -249,37 +249,58 @@ def fc_version(cls, fc):
return cls.default_version(fc)
@classmethod
def _find_matches_in_path(cls, compiler_names, detect_version, *path):
"""Finds compilers in the paths supplied.
def _find_matches_in_path(cls, compiler_language, *search_paths):
"""Finds compilers for a given language in the paths supplied.
Looks for all combinations of ``compiler_names`` with the
``prefixes`` and ``suffixes`` defined for this compiler
class. If any compilers match the compiler_names,
prefixes, or suffixes, uses ``detect_version`` to figure
out what version the compiler is.
Looks for all combinations of ``compiler_names`` with the
``prefixes`` and ``suffixes`` defined for this compiler
class. If any compilers match the compiler_names,
prefixes, or suffixes, uses ``detect_version`` to figure
out what version the compiler is.
This returns a dict with compilers grouped by (prefix,
suffix, version) tuples. This can be further organized by
find().
Args:
compiler_language (str): language of the compiler (either
'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
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 = []
for directory in path:
if not (os.path.isdir(directory) and
os.access(directory, os.R_OK | os.X_OK)):
continue
files = os.listdir(directory)
for exe in files:
full_path = os.path.join(directory, exe)
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)
for d in search_directories:
# Only select actual files, use the full path
files = filter(
os.path.isfile, [os.path.join(d, f) for f in os.listdir(d)]
)
for full_path in files:
file = os.path.basename(full_path)
for regexp in search_regexps:
match = regexp.match(file)
if match:
key = (full_path,) + match.groups() + (detect_version,)
checks.append(key)