def find_compilers(self, *paths): # function-local so that cnl doesn't depend on spack.config import spack.compilers types = spack.compilers.all_compiler_types() compiler_lists = mp.parmap( lambda cmp_cls: self.find_compiler(cmp_cls, *paths), types) # ensure all the version calls we made are cached in the parent # process, as well. This speeds up Spack a lot. clist = [comp for cl in compiler_lists for comp in cl] return clist
def _find_matches_in_path(cls, compiler_names, detect_version, *path): """Finds compilers 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. This returns a dict with compilers grouped by (prefix, suffix, version) tuples. This can be further organized by find(). """ if not path: path = get_path('PATH') prefixes = [''] + cls.prefixes suffixes = [''] + cls.suffixes 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) if match: key = (full_path, ) + match.groups() + ( detect_version, ) checks.append(key) successful = [ k for k in mp.parmap(_get_versioned_tuple, checks) if k is not None ] # The 'successful' list is ordered like the input paths. # Reverse it here so that the dict creation (last insert wins) # does not spoil the intented precedence. successful.reverse() return dict(((v, p, s), path) for v, p, s, path in successful)
def find_compiler(self, cmp_cls, *path): """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 version filled in. This will search for compilers with the names in cc_names, 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. """ 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)]) all_keys = set() for d in dicts: all_keys.update(d) compilers = {} for k in all_keys: ver, pre, suf = k # Skip compilers with unknown version. 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) if ver in compilers: prev = compilers[ver] # prefer the one with more compilers. prev_paths = [prev.cc, prev.cxx, prev.f77, prev.fc] newcount = len([p for p in paths if p is not None]) prevcount = len([p for p in prev_paths if p is not None]) # Don't add if it's not an improvement over prev compiler. if newcount <= prevcount: continue compilers[ver] = cmp_cls(spec, self, py_platform.machine(), paths) return list(compilers.values())
def _find_matches_in_path(cls, compiler_names, detect_version, *path): """Finds compilers 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. This returns a dict with compilers grouped by (prefix, suffix, version) tuples. This can be further organized by find(). """ if not path: path = get_path('PATH') prefixes = [''] + cls.prefixes suffixes = [''] + cls.suffixes 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) if match: key = (full_path,) + match.groups() + (detect_version,) checks.append(key) successful = [k for k in mp.parmap(_get_versioned_tuple, checks) if k is not None] # The 'successful' list is ordered like the input paths. # Reverse it here so that the dict creation (last insert wins) # does not spoil the intented precedence. successful.reverse() return dict(((v, p, s), path) for v, p, s, path in successful)
def find_compilers(self, *paths): """ Return a list of compilers found in the supplied paths. This invokes the find() method for each Compiler class, and appends the compilers detected to a list. """ if not paths: paths = get_path('PATH') # Make sure path elements exist, and include /bin directories # under prefixes. filtered_path = [] for p in paths: # Eliminate symlinks and just take the real directories. p = os.path.realpath(p) if not os.path.isdir(p): continue filtered_path.append(p) # Check for a bin directory, add it if it exists bin = os.path.join(p, 'bin') if os.path.isdir(bin): filtered_path.append(os.path.realpath(bin)) # Once the paths are cleaned up, do a search for each type of # compiler. We can spawn a bunch of parallel searches to reduce # the overhead of spelunking all these directories. # NOTE: we import spack.compilers here to avoid init order cycles import spack.compilers types = spack.compilers.all_compiler_types() compiler_lists = mp.parmap( lambda cmp_cls: self.find_compiler(cmp_cls, *filtered_path), types) # ensure all the version calls we made are cached in the parent # process, as well. This speeds up Spack a lot. clist = [comp for cl in compiler_lists for comp in cl] return clist