diff --git a/lib/spack/spack/architecture.py b/lib/spack/spack/architecture.py index 4c16a80bec0..d1d7e9f5f50 100644 --- a/lib/spack/spack/architecture.py +++ b/lib/spack/spack/architecture.py @@ -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: diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py index eef64234865..3ad6e5b0db8 100644 --- a/lib/spack/spack/compiler.py +++ b/lib/spack/spack/compiler.py @@ -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)