diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py deleted file mode 100644 index af04f3b5e55..00000000000 --- a/lib/spack/spack/compiler.py +++ /dev/null @@ -1,856 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import contextlib -import hashlib -import itertools -import json -import os -import platform -import re -import shutil -import sys -import tempfile -from typing import Dict, List, Optional, Sequence - -import llnl.path -import llnl.util.lang -import llnl.util.tty as tty -from llnl.util.filesystem import path_contains_subdirectory, paths_containing_libs - -import spack.caches -import spack.error -import spack.schema.environment -import spack.spec -import spack.util.executable -import spack.util.libc -import spack.util.module_cmd -import spack.version -from spack.util.environment import filter_system_paths -from spack.util.file_cache import FileCache - -__all__ = ["Compiler"] - -PATH_INSTANCE_VARS = ["cc", "cxx", "f77", "fc"] -FLAG_INSTANCE_VARS = ["cflags", "cppflags", "cxxflags", "fflags"] - - -@llnl.util.lang.memoized -def _get_compiler_version_output(compiler_path, version_arg, ignore_errors=()) -> str: - """Invokes the compiler at a given path passing a single - version argument and returns the output. - - Args: - compiler_path (path): path of the compiler to be invoked - version_arg (str): the argument used to extract version information - """ - compiler = spack.util.executable.Executable(compiler_path) - compiler_invocation_args = { - "output": str, - "error": str, - "ignore_errors": ignore_errors, - "timeout": 120, - "fail_on_error": True, - } - if version_arg: - output = compiler(version_arg, **compiler_invocation_args) - else: - output = compiler(**compiler_invocation_args) - return output - - -def get_compiler_version_output(compiler_path, *args, **kwargs) -> str: - """Wrapper for _get_compiler_version_output().""" - # This ensures that we memoize compiler output by *absolute path*, - # not just executable name. If we don't do this, and the path changes - # (e.g., during testing), we can get incorrect results. - if not os.path.isabs(compiler_path): - compiler_path = spack.util.executable.which_string(compiler_path, required=True) - - return _get_compiler_version_output(compiler_path, *args, **kwargs) - - -def tokenize_flags(flags_values, propagate=False): - """Given a compiler flag specification as a string, this returns a list - where the entries are the flags. For compiler options which set values - using the syntax "-flag value", this function groups flags and their - values together. Any token not preceded by a "-" is considered the - value of a prior flag.""" - tokens = flags_values.split() - if not tokens: - return [] - flag = tokens[0] - flags_with_propagation = [] - for token in tokens[1:]: - if not token.startswith("-"): - flag += " " + token - else: - flags_with_propagation.append((flag, propagate)) - flag = token - flags_with_propagation.append((flag, propagate)) - return flags_with_propagation - - -#: regex for parsing linker lines -_LINKER_LINE = re.compile(r"^( *|.*[/\\])" r"(link|ld|([^/\\]+-)?ld|collect2)" r"[^/\\]*( |$)") - -#: components of linker lines to ignore -_LINKER_LINE_IGNORE = re.compile(r"(collect2 version|^[A-Za-z0-9_]+=|/ldfe )") - -#: regex to match linker search paths -_LINK_DIR_ARG = re.compile(r"^-L(.:)?(?P[/\\].*)") - -#: regex to match linker library path arguments -_LIBPATH_ARG = re.compile(r"^[-/](LIBPATH|libpath):(?P.*)") - - -def _parse_link_paths(string): - """Parse implicit link paths from compiler debug output. - - This gives the compiler runtime library paths that we need to add to - the RPATH of generated binaries and libraries. It allows us to - ensure, e.g., that codes load the right libstdc++ for their compiler. - """ - lib_search_paths = False - raw_link_dirs = [] - for line in string.splitlines(): - if lib_search_paths: - if line.startswith("\t"): - raw_link_dirs.append(line[1:]) - continue - else: - lib_search_paths = False - elif line.startswith("Library search paths:"): - lib_search_paths = True - - if not _LINKER_LINE.match(line): - continue - if _LINKER_LINE_IGNORE.match(line): - continue - tty.debug(f"implicit link dirs: link line: {line}") - - next_arg = False - for arg in line.split(): - if arg in ("-L", "-Y"): - next_arg = True - continue - - if next_arg: - raw_link_dirs.append(arg) - next_arg = False - continue - - link_dir_arg = _LINK_DIR_ARG.match(arg) - if link_dir_arg: - link_dir = link_dir_arg.group("dir") - raw_link_dirs.append(link_dir) - - link_dir_arg = _LIBPATH_ARG.match(arg) - if link_dir_arg: - link_dir = link_dir_arg.group("dir") - raw_link_dirs.append(link_dir) - - implicit_link_dirs = list() - visited = set() - for link_dir in raw_link_dirs: - normalized_path = os.path.abspath(link_dir) - if normalized_path not in visited: - implicit_link_dirs.append(normalized_path) - visited.add(normalized_path) - - tty.debug(f"implicit link dirs: result: {', '.join(implicit_link_dirs)}") - return implicit_link_dirs - - -@llnl.path.system_path_filter -def _parse_non_system_link_dirs(string: str) -> List[str]: - """Parses link paths out of compiler debug output. - - Args: - string: compiler debug output as a string - - Returns: - Implicit link paths parsed from the compiler output - """ - link_dirs = _parse_link_paths(string) - - # Remove directories that do not exist. Some versions of the Cray compiler - # report nonexistent directories - link_dirs = [d for d in link_dirs if os.path.isdir(d)] - - # Return set of directories containing needed compiler libs, minus - # system paths. Note that 'filter_system_paths' only checks for an - # exact match, while 'in_system_subdirectory' checks if a path contains - # a system directory as a subdirectory - link_dirs = filter_system_paths(link_dirs) - return list(p for p in link_dirs if not in_system_subdirectory(p)) - - -def in_system_subdirectory(path): - system_dirs = [ - "/lib/", - "/lib64/", - "/usr/lib/", - "/usr/lib64/", - "/usr/local/lib/", - "/usr/local/lib64/", - ] - return any(path_contains_subdirectory(path, x) for x in system_dirs) - - -class Compiler: - """This class encapsulates a Spack "compiler", which includes C, - C++, and Fortran compilers. Subclasses should implement - support for specific compilers, their possible names, arguments, - and how to identify the particular type of compiler.""" - - # Optional prefix regexes for searching for this type of compiler. - # Prefixes are sometimes used for toolchains - prefixes: List[str] = [] - - # Optional suffix regexes for searching for this type of compiler. - # Suffixes are used by some frameworks, e.g. macports uses an '-mp-X.Y' - # version suffix for gcc. - suffixes = [r"-.*"] - - #: Compiler argument that produces version information - version_argument = "-dumpversion" - - #: Return values to ignore when invoking the compiler to get its version - ignore_version_errors: Sequence[int] = () - - #: Regex used to extract version from compiler's output - version_regex = "(.*)" - - # These libraries are anticipated to be required by all executables built - # by any compiler - _all_compiler_rpath_libraries = ["libc", "libc++", "libstdc++"] - - #: Platform matcher for Platform objects supported by compiler - is_supported_on_platform = lambda x: True - - # Default flags used by a compiler to set an rpath - @property - def cc_rpath_arg(self): - return "-Wl,-rpath," - - @property - def cxx_rpath_arg(self): - return "-Wl,-rpath," - - @property - def f77_rpath_arg(self): - return "-Wl,-rpath," - - @property - def fc_rpath_arg(self): - return "-Wl,-rpath," - - @property - def linker_arg(self): - """Flag that need to be used to pass an argument to the linker.""" - return "-Wl," - - @property - def disable_new_dtags(self): - if platform.system() == "Darwin": - return "" - return "--disable-new-dtags" - - @property - def enable_new_dtags(self): - if platform.system() == "Darwin": - return "" - return "--enable-new-dtags" - - @property - def debug_flags(self): - return ["-g"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3"] - - def __init__( - self, - cspec, - operating_system, - target, - paths, - modules: Optional[List[str]] = None, - alias=None, - environment=None, - extra_rpaths=None, - enable_implicit_rpaths=None, - **kwargs, - ): - self.spec = cspec - self.operating_system = str(operating_system) - self.target = target - self.modules = modules or [] - self.alias = alias - self.environment = environment or {} - self.extra_rpaths = extra_rpaths or [] - self.enable_implicit_rpaths = enable_implicit_rpaths - self.cache = COMPILER_CACHE - - self.cc = paths[0] - self.cxx = paths[1] - self.f77 = None - self.fc = None - if len(paths) > 2: - self.f77 = paths[2] - if len(paths) == 3: - self.fc = self.f77 - else: - self.fc = paths[3] - - # Unfortunately have to make sure these params are accepted - # in the same order they are returned by sorted(flags) - # in compilers/__init__.py - self.flags = spack.spec.FlagMap(self.spec) - for flag in self.flags.valid_compiler_flags(): - value = kwargs.get(flag, None) - if value is not None: - values_with_propagation = tokenize_flags(value, False) - for value, propagation in values_with_propagation: - self.flags.add_flag(flag, value, propagation) - - # caching value for compiler reported version - # used for version checks for API, e.g. C++11 flag - self._real_version = None - - def __eq__(self, other): - return ( - self.cc == other.cc - and self.cxx == other.cxx - and self.fc == other.fc - and self.f77 == other.f77 - and self.spec == other.spec - and self.operating_system == other.operating_system - and self.target == other.target - and self.flags == other.flags - and self.modules == other.modules - and self.environment == other.environment - and self.extra_rpaths == other.extra_rpaths - and self.enable_implicit_rpaths == other.enable_implicit_rpaths - ) - - def __hash__(self): - return hash( - ( - self.cc, - self.cxx, - self.fc, - self.f77, - self.spec, - self.operating_system, - self.target, - str(self.flags), - str(self.modules), - str(self.environment), - str(self.extra_rpaths), - self.enable_implicit_rpaths, - ) - ) - - def verify_executables(self): - """Raise an error if any of the compiler executables is not valid. - - This method confirms that for all of the compilers (cc, cxx, f77, fc) - that have paths, those paths exist and are executable by the current - user. - Raises a CompilerAccessError if any of the non-null paths for the - compiler are not accessible. - """ - - def accessible_exe(exe): - # compilers may contain executable names (on Cray or user edited) - if not os.path.isabs(exe): - exe = spack.util.executable.which_string(exe) - if not exe: - return False - return os.path.isfile(exe) and os.access(exe, os.X_OK) - - # setup environment before verifying in case we have executable names - # instead of absolute paths - with self.compiler_environment(): - missing = [ - cmp - for cmp in (self.cc, self.cxx, self.f77, self.fc) - if cmp and not accessible_exe(cmp) - ] - if missing: - raise CompilerAccessError(self, missing) - - @property - def version(self): - return self.spec.version - - @property - def real_version(self): - """Executable reported compiler version used for API-determinations - - E.g. C++11 flag checks. - """ - real_version_str = self.cache.get(self).real_version - if not real_version_str or real_version_str == "unknown": - return self.version - - return spack.version.StandardVersion.from_string(real_version_str) - - def implicit_rpaths(self) -> List[str]: - if self.enable_implicit_rpaths is False: - return [] - - output = self.compiler_verbose_output - - if not output: - return [] - - link_dirs = _parse_non_system_link_dirs(output) - - all_required_libs = list(self.required_libs) + Compiler._all_compiler_rpath_libraries - return list(paths_containing_libs(link_dirs, all_required_libs)) - - @property - def default_dynamic_linker(self) -> Optional[str]: - """Determine default dynamic linker from compiler link line""" - output = self.compiler_verbose_output - - if not output: - return None - - return spack.util.libc.parse_dynamic_linker(output) - - @property - def default_libc(self) -> Optional["spack.spec.Spec"]: - """Determine libc targeted by the compiler from link line""" - # technically this should be testing the target platform of the compiler, but we don't have - # that, so stick to host platform for now. - if sys.platform in ("darwin", "win32"): - return None - - dynamic_linker = self.default_dynamic_linker - - if not dynamic_linker: - return None - - return spack.util.libc.libc_from_dynamic_linker(dynamic_linker) - - @property - def required_libs(self): - """For executables created with this compiler, the compiler libraries - that would be generally required to run it. - """ - # By default every compiler returns the empty list - return [] - - @property - def compiler_verbose_output(self) -> Optional[str]: - """Verbose output from compiling a dummy C source file. Output is cached.""" - return self.cache.get(self).c_compiler_output - - def _compile_dummy_c_source(self) -> Optional[str]: - if self.cc: - cc = self.cc - ext = "c" - else: - cc = self.cxx - ext = "cc" - - if not cc or not self.verbose_flag: - return None - - try: - tmpdir = tempfile.mkdtemp(prefix="spack-implicit-link-info") - fout = os.path.join(tmpdir, "output") - fin = os.path.join(tmpdir, f"main.{ext}") - - with open(fin, "w", encoding="utf-8") as csource: - csource.write( - "int main(int argc, char* argv[]) { (void)argc; (void)argv; return 0; }\n" - ) - cc_exe = spack.util.executable.Executable(cc) - for flag_type in ["cflags" if cc == self.cc else "cxxflags", "cppflags", "ldflags"]: - cc_exe.add_default_arg(*self.flags.get(flag_type, [])) - - with self.compiler_environment(): - return cc_exe(self.verbose_flag, fin, "-o", fout, output=str, error=str) - except spack.util.executable.ProcessError as pe: - tty.debug("ProcessError: Command exited with non-zero status: " + pe.long_message) - return None - finally: - shutil.rmtree(tmpdir, ignore_errors=True) - - @property - def verbose_flag(self) -> Optional[str]: - """ - This property should be overridden in the compiler subclass if a - verbose flag is available. - - If it is not overridden, it is assumed to not be supported. - """ - - # This property should be overridden in the compiler subclass if - # OpenMP is supported by that compiler - @property - def openmp_flag(self): - # If it is not overridden, assume it is not supported and warn the user - raise UnsupportedCompilerFlag(self, "OpenMP", "openmp_flag") - - # This property should be overridden in the compiler subclass if - # C++98 is not the default standard for that compiler - @property - def cxx98_flag(self): - return "" - - # This property should be overridden in the compiler subclass if - # C++11 is supported by that compiler - @property - def cxx11_flag(self): - # If it is not overridden, assume it is not supported and warn the user - raise UnsupportedCompilerFlag(self, "the C++11 standard", "cxx11_flag") - - # This property should be overridden in the compiler subclass if - # C++14 is supported by that compiler - @property - def cxx14_flag(self): - # If it is not overridden, assume it is not supported and warn the user - raise UnsupportedCompilerFlag(self, "the C++14 standard", "cxx14_flag") - - # This property should be overridden in the compiler subclass if - # C++17 is supported by that compiler - @property - def cxx17_flag(self): - # If it is not overridden, assume it is not supported and warn the user - raise UnsupportedCompilerFlag(self, "the C++17 standard", "cxx17_flag") - - # This property should be overridden in the compiler subclass if - # C99 is supported by that compiler - @property - def c99_flag(self): - # If it is not overridden, assume it is not supported and warn the user - raise UnsupportedCompilerFlag(self, "the C99 standard", "c99_flag") - - # This property should be overridden in the compiler subclass if - # C11 is supported by that compiler - @property - def c11_flag(self): - # If it is not overridden, assume it is not supported and warn the user - raise UnsupportedCompilerFlag(self, "the C11 standard", "c11_flag") - - @property - def cc_pic_flag(self): - """Returns the flag used by the C compiler to produce - Position Independent Code (PIC).""" - return "-fPIC" - - @property - def cxx_pic_flag(self): - """Returns the flag used by the C++ compiler to produce - Position Independent Code (PIC).""" - return "-fPIC" - - @property - def f77_pic_flag(self): - """Returns the flag used by the F77 compiler to produce - Position Independent Code (PIC).""" - return "-fPIC" - - @property - def fc_pic_flag(self): - """Returns the flag used by the FC compiler to produce - Position Independent Code (PIC).""" - return "-fPIC" - - # Note: This is not a class method. The class methods are used to detect - # compilers on PATH based systems, and do not set up the run environment of - # the compiler. This method can be called on `module` based systems as well - def get_real_version(self) -> str: - """Query the compiler for its version. - - This is the "real" compiler version, regardless of what is in the - compilers.yaml file, which the user can change to name their compiler. - - Use the runtime environment of the compiler (modules and environment - modifications) to enable the compiler to run properly on any platform. - """ - cc = spack.util.executable.Executable(self.cc) - try: - with self.compiler_environment(): - output = cc( - self.version_argument, - output=str, - error=str, - ignore_errors=tuple(self.ignore_version_errors), - ) - return self.extract_version_from_output(output) - except spack.util.executable.ProcessError: - return "unknown" - - @property - def prefix(self): - """Query the compiler for its install prefix. This is the install - path as reported by the compiler. Note that paths for cc, cxx, etc - are not enough to find the install prefix of the compiler, since - the can be symlinks, wrappers, or filenames instead of absolute paths.""" - raise NotImplementedError("prefix is not implemented for this compiler") - - # - # 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 - def default_version(cls, cc): - """Override just this to override all compiler version functions.""" - output = get_compiler_version_output( - cc, cls.version_argument, tuple(cls.ignore_version_errors) - ) - return cls.extract_version_from_output(output) - - @classmethod - @llnl.util.lang.memoized - def extract_version_from_output(cls, output: str) -> str: - """Extracts the version from compiler's output.""" - match = re.search(cls.version_regex, output) - return match.group(1) if match else "unknown" - - @classmethod - def cc_version(cls, cc): - return cls.default_version(cc) - - @classmethod - def search_regexps(cls, language): - # Compile all the regular expressions used for files beforehand. - # This searches for any combination of - # defined for the compiler - compiler_names = getattr(cls, "{0}_names".format(language)) - prefixes = [""] + cls.prefixes - suffixes = [""] - if sys.platform == "win32": - ext = r"\.(?:exe|bat)" - cls_suf = [suf + ext for suf in cls.suffixes] - ext_suf = [ext] - suffixes = suffixes + cls.suffixes + cls_suf + ext_suf - else: - suffixes = suffixes + cls.suffixes - regexp_fmt = r"^({0}){1}({2})$" - return [ - re.compile(regexp_fmt.format(prefix, re.escape(name), suffix)) - for prefix, name, suffix in itertools.product(prefixes, compiler_names, suffixes) - ] - - def setup_custom_environment(self, pkg, env): - """Set any environment variables necessary to use the compiler.""" - pass - - def __repr__(self): - """Return a string representation of the compiler toolchain.""" - return self.__str__() - - def __str__(self): - """Return a string representation of the compiler toolchain.""" - return "%s(%s)" % ( - self.name, - "\n ".join( - ( - str(s) - for s in ( - self.cc, - self.cxx, - self.f77, - self.fc, - self.modules, - str(self.operating_system), - ) - ) - ), - ) - - @contextlib.contextmanager - def compiler_environment(self): - # Avoid modifying os.environ if possible. - if not self.modules and not self.environment: - yield - return - - # store environment to replace later - backup_env = os.environ.copy() - - try: - # load modules and set env variables - for module in self.modules: - spack.util.module_cmd.load_module(module) - - # apply other compiler environment changes - spack.schema.environment.parse(self.environment).apply_modifications() - - yield - finally: - # Restore environment regardless of whether inner code succeeded - os.environ.clear() - os.environ.update(backup_env) - - def to_dict(self): - flags_dict = {fname: " ".join(fvals) for fname, fvals in self.flags.items()} - flags_dict.update( - {attr: getattr(self, attr, None) for attr in FLAG_INSTANCE_VARS if hasattr(self, attr)} - ) - result = { - "spec": str(self.spec), - "paths": {attr: getattr(self, attr, None) for attr in PATH_INSTANCE_VARS}, - "flags": flags_dict, - "operating_system": str(self.operating_system), - "target": str(self.target), - "modules": self.modules or [], - "environment": self.environment or {}, - "extra_rpaths": self.extra_rpaths or [], - } - - if self.enable_implicit_rpaths is not None: - result["implicit_rpaths"] = self.enable_implicit_rpaths - - if self.alias: - result["alias"] = self.alias - - return result - - -class CompilerAccessError(spack.error.SpackError): - def __init__(self, compiler, paths): - msg = "Compiler '%s' has executables that are missing" % compiler.spec - msg += " or are not executable: %s" % paths - super().__init__(msg) - - -class InvalidCompilerError(spack.error.SpackError): - def __init__(self): - super().__init__("Compiler has no executables.") - - -class UnsupportedCompilerFlag(spack.error.SpackError): - def __init__(self, compiler, feature, flag_name, ver_string=None): - super().__init__( - "{0} ({1}) does not support {2} (as compiler.{3}).".format( - compiler.name, ver_string if ver_string else compiler.version, feature, flag_name - ), - "If you think it should, please edit the compiler.{0} subclass to".format( - compiler.name - ) - + " implement the {0} property and submit a pull request or issue.".format(flag_name), - ) - - -class CompilerCacheEntry: - """Deserialized cache entry for a compiler""" - - __slots__ = ("c_compiler_output", "real_version") - - def __init__(self, c_compiler_output: Optional[str], real_version: str): - self.c_compiler_output = c_compiler_output - self.real_version = real_version - - @property - def empty(self) -> bool: - """Sometimes the compiler is temporarily broken, preventing us from getting output. The - call site determines if that is a problem.""" - return self.c_compiler_output is None - - @classmethod - def from_dict(cls, data: Dict[str, Optional[str]]): - if not isinstance(data, dict): - raise ValueError(f"Invalid {cls.__name__} data") - c_compiler_output = data.get("c_compiler_output") - real_version = data.get("real_version") - if not isinstance(real_version, str) or not isinstance( - c_compiler_output, (str, type(None)) - ): - raise ValueError(f"Invalid {cls.__name__} data") - return cls(c_compiler_output, real_version) - - -class CompilerCache: - """Base class for compiler output cache. Default implementation does not cache anything.""" - - def value(self, compiler: Compiler) -> Dict[str, Optional[str]]: - return { - "c_compiler_output": compiler._compile_dummy_c_source(), - "real_version": compiler.get_real_version(), - } - - def get(self, compiler: Compiler) -> CompilerCacheEntry: - return CompilerCacheEntry.from_dict(self.value(compiler)) - - -class FileCompilerCache(CompilerCache): - """Cache for compiler output, which is used to determine implicit link paths, the default libc - version, and the compiler version.""" - - name = os.path.join("compilers", "compilers.json") - - def __init__(self, cache: "FileCache") -> None: - self.cache = cache - self.cache.init_entry(self.name) - self._data: Dict[str, Dict[str, Optional[str]]] = {} - - def _get_entry(self, key: str, *, allow_empty: bool) -> Optional[CompilerCacheEntry]: - try: - entry = CompilerCacheEntry.from_dict(self._data[key]) - return entry if allow_empty or not entry.empty else None - except ValueError: - del self._data[key] - except KeyError: - pass - return None - - def get(self, compiler: Compiler) -> CompilerCacheEntry: - # Cache hit - try: - with self.cache.read_transaction(self.name) as f: - assert f is not None - self._data = json.loads(f.read()) - assert isinstance(self._data, dict) - except (json.JSONDecodeError, AssertionError): - self._data = {} - - key = self._key(compiler) - value = self._get_entry(key, allow_empty=False) - if value is not None: - return value - - # Cache miss - with self.cache.write_transaction(self.name) as (old, new): - try: - assert old is not None - self._data = json.loads(old.read()) - assert isinstance(self._data, dict) - except (json.JSONDecodeError, AssertionError): - self._data = {} - - # Use cache entry that may have been created by another process in the meantime. - entry = self._get_entry(key, allow_empty=True) - - # Finally compute the cache entry - if entry is None: - self._data[key] = self.value(compiler) - entry = CompilerCacheEntry.from_dict(self._data[key]) - - new.write(json.dumps(self._data, separators=(",", ":"))) - - return entry - - def _key(self, compiler: Compiler) -> str: - as_bytes = json.dumps(compiler.to_dict(), separators=(",", ":")).encode("utf-8") - return hashlib.sha256(as_bytes).hexdigest() - - -def _make_compiler_cache(): - return FileCompilerCache(spack.caches.MISC_CACHE) - - -COMPILER_CACHE: CompilerCache = llnl.util.lang.Singleton(_make_compiler_cache) # type: ignore diff --git a/lib/spack/spack/compilers/aocc.py b/lib/spack/spack/compilers/aocc.py deleted file mode 100644 index 0d6c908df65..00000000000 --- a/lib/spack/spack/compilers/aocc.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os -import re - -import llnl.util.lang - -from spack.compiler import Compiler -from spack.version import ver - - -class Aocc(Compiler): - version_argument = "--version" - - @property - def debug_flags(self): - return [ - "-gcodeview", - "-gdwarf-2", - "-gdwarf-3", - "-gdwarf-4", - "-gdwarf-5", - "-gline-tables-only", - "-gmodules", - "-g", - ] - - @property - def opt_flags(self): - return ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os", "-Oz", "-Og", "-O", "-O4"] - - @property - def link_paths(self): - link_paths = { - "cc": os.path.join("aocc", "clang"), - "cxx": os.path.join("aocc", "clang++"), - "f77": os.path.join("aocc", "flang"), - "fc": os.path.join("aocc", "flang"), - } - - return link_paths - - @property - def verbose_flag(self): - return "-v" - - @property - def openmp_flag(self): - return "-fopenmp" - - @property - def cxx11_flag(self): - return "-std=c++11" - - @property - def cxx14_flag(self): - return "-std=c++14" - - @property - def cxx17_flag(self): - return "-std=c++17" - - @property - def c99_flag(self): - return "-std=c99" - - @property - def c11_flag(self): - return "-std=c11" - - @property - def cc_pic_flag(self): - return "-fPIC" - - @property - def cxx_pic_flag(self): - return "-fPIC" - - @property - def f77_pic_flag(self): - return "-fPIC" - - @property - def fc_pic_flag(self): - return "-fPIC" - - required_libs = ["libclang"] - - @classmethod - @llnl.util.lang.memoized - def extract_version_from_output(cls, output): - match = re.search(r"AOCC_(\d+)[._](\d+)[._](\d+)", output) - if match: - return ".".join(match.groups()) - return "unknown" - - @property - def stdcxx_libs(self): - return ("-lstdc++",) - - @property - def cflags(self): - return self._handle_default_flag_addtions() - - @property - def cxxflags(self): - return self._handle_default_flag_addtions() - - @property - def fflags(self): - return self._handle_default_flag_addtions() - - def _handle_default_flag_addtions(self): - # This is a known issue for AOCC 3.0 see: - # https://developer.amd.com/wp-content/resources/AOCC-3.0-Install-Guide.pdf - if self.version.satisfies(ver("3.0.0")): - return "-Wno-unused-command-line-argument " "-mllvm -eliminate-similar-expr=false" diff --git a/lib/spack/spack/compilers/apple_clang.py b/lib/spack/spack/compilers/apple_clang.py deleted file mode 100644 index 7962639b6fd..00000000000 --- a/lib/spack/spack/compilers/apple_clang.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) -import re - -import llnl.util.lang - -import spack.compiler -import spack.compilers.clang -from spack.version import Version - - -class AppleClang(spack.compilers.clang.Clang): - openmp_flag = "-Xpreprocessor -fopenmp" - - @classmethod - @llnl.util.lang.memoized - def extract_version_from_output(cls, output): - ver = "unknown" - match = re.search( - # Apple's LLVM compiler has its own versions, so suffix them. - r"^Apple (?:LLVM|clang) version ([^ )]+)", - output, - # Multi-line, since 'Apple clang' may not be on the first line - # in particular, when run as gcc, it seems to output - # "Configured with: --prefix=..." as the first line - re.M, - ) - if match: - ver = match.group(match.lastindex) - return ver - - # C++ flags based on CMake Modules/Compiler/AppleClang-CXX.cmake - - @property - def cxx11_flag(self): - # Spack's AppleClang detection only valid from Xcode >= 4.6 - if self.real_version < Version("4.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++11 standard", "cxx11_flag", "Xcode < 4.0" - ) - return "-std=c++11" - - @property - def cxx14_flag(self): - if self.real_version < Version("5.1"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++14 standard", "cxx14_flag", "Xcode < 5.1" - ) - elif self.real_version < Version("6.1"): - return "-std=c++1y" - - return "-std=c++14" - - @property - def cxx17_flag(self): - if self.real_version < Version("6.1"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++17 standard", "cxx17_flag", "Xcode < 6.1" - ) - elif self.real_version < Version("10.0"): - return "-std=c++1z" - return "-std=c++17" - - @property - def cxx20_flag(self): - if self.real_version < Version("10.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++20 standard", "cxx20_flag", "Xcode < 10.0" - ) - elif self.real_version < Version("13.0"): - return "-std=c++2a" - return "-std=c++20" - - @property - def cxx23_flag(self): - if self.real_version < Version("13.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++23 standard", "cxx23_flag", "Xcode < 13.0" - ) - return "-std=c++2b" - - # C flags based on CMake Modules/Compiler/AppleClang-C.cmake - - @property - def c99_flag(self): - if self.real_version < Version("4.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C99 standard", "c99_flag", "< 4.0" - ) - return "-std=c99" - - @property - def c11_flag(self): - if self.real_version < Version("4.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C11 standard", "c11_flag", "< 4.0" - ) - return "-std=c11" - - @property - def c17_flag(self): - if self.real_version < Version("11.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C17 standard", "c17_flag", "< 11.0" - ) - return "-std=c17" - - @property - def c23_flag(self): - if self.real_version < Version("11.0.3"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C23 standard", "c23_flag", "< 11.0.3" - ) - return "-std=c2x" diff --git a/lib/spack/spack/compilers/arm.py b/lib/spack/spack/compilers/arm.py deleted file mode 100644 index 880c82b321d..00000000000 --- a/lib/spack/spack/compilers/arm.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -import spack.compiler - - -class Arm(spack.compiler.Compiler): - # Named wrapper links within lib/spack/env - link_paths = { - "cc": os.path.join("arm", "armclang"), - "cxx": os.path.join("arm", "armclang++"), - "f77": os.path.join("arm", "armflang"), - "fc": os.path.join("arm", "armflang"), - } - - # The ``--version`` option seems to be the most consistent one for - # arm compilers. Output looks like this: - # - # $ armlang --version - # Arm C/C++/Fortran Compiler version 19.0 (build number 73) (based on LLVM 7.0.2) - # Target: aarch64--linux-gnu - # Thread model: posix - # InstalledDir: - # /opt/arm/arm-hpc-compiler-19.0_Generic-AArch64_RHEL-7_aarch64-linux/bin - version_argument = "--version" - version_regex = r"Arm C\/C\+\+\/Fortran Compiler version ([\d\.]+) " - - @property - def verbose_flag(self): - return "-v" - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast"] - - @property - def openmp_flag(self): - return "-fopenmp" - - @property - def cxx11_flag(self): - return "-std=c++11" - - @property - def cxx14_flag(self): - return "-std=c++14" - - @property - def cxx17_flag(self): - return "-std=c++1z" - - @property - def c99_flag(self): - return "-std=c99" - - @property - def c11_flag(self): - return "-std=c11" - - @property - def cc_pic_flag(self): - return "-fPIC" - - @property - def cxx_pic_flag(self): - return "-fPIC" - - @property - def f77_pic_flag(self): - return "-fPIC" - - @property - def fc_pic_flag(self): - return "-fPIC" - - required_libs = ["libclang", "libflang"] diff --git a/lib/spack/spack/compilers/cce.py b/lib/spack/spack/compilers/cce.py deleted file mode 100644 index a127ec9d4fe..00000000000 --- a/lib/spack/spack/compilers/cce.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) -import os - -from spack.compiler import Compiler, UnsupportedCompilerFlag -from spack.version import Version - - -class Cce(Compiler): - """Cray compiler environment compiler.""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # For old cray compilers on module based systems we replace - # ``version_argument`` with the old value. Cannot be a property - # as the new value is used in classmethods for path-based detection - if not self.is_clang_based: - self.version_argument = "-V" - - # MacPorts builds gcc versions with prefixes and -mp-X.Y suffixes. - suffixes = [r"-mp-\d\.\d"] - - @property - def link_paths(self): - if any("PrgEnv-cray" in m for m in self.modules): - # Old module-based interface to cray compilers - return { - "cc": os.path.join("cce", "cc"), - "cxx": os.path.join("case-insensitive", "CC"), - "f77": os.path.join("cce", "ftn"), - "fc": os.path.join("cce", "ftn"), - } - - return { - "cc": os.path.join("cce", "craycc"), - "cxx": os.path.join("cce", "case-insensitive", "crayCC"), - "f77": os.path.join("cce", "crayftn"), - "fc": os.path.join("cce", "crayftn"), - } - - @property - def is_clang_based(self): - version = self._real_version or self.version - return version >= Version("9.0") and "classic" not in str(version) - - version_argument = "--version" - version_regex = r"[Cc]ray (?:clang|C :|C\+\+ :|Fortran :) [Vv]ersion.*?(\d+(\.\d+)+)" - - @property - def verbose_flag(self): - return "-v" - - @property - def debug_flags(self): - return ["-g", "-G0", "-G1", "-G2", "-Gfast"] - - @property - def openmp_flag(self): - if self.is_clang_based: - return "-fopenmp" - return "-h omp" - - @property - def cxx11_flag(self): - if self.is_clang_based: - return "-std=c++11" - return "-h std=c++11" - - @property - def cxx14_flag(self): - if self.is_clang_based: - return "-std=c++14" - return "-h std=c++14" - - @property - def cxx17_flag(self): - if self.is_clang_based: - return "-std=c++17" - - @property - def c99_flag(self): - if self.is_clang_based: - return "-std=c99" - elif self.real_version >= Version("8.4"): - return "-h std=c99,noconform,gnu" - elif self.real_version >= Version("8.1"): - return "-h c99,noconform,gnu" - raise UnsupportedCompilerFlag(self, "the C99 standard", "c99_flag", "< 8.1") - - @property - def c11_flag(self): - if self.is_clang_based: - return "-std=c11" - elif self.real_version >= Version("8.5"): - return "-h std=c11,noconform,gnu" - raise UnsupportedCompilerFlag(self, "the C11 standard", "c11_flag", "< 8.5") - - @property - def cc_pic_flag(self): - if self.is_clang_based: - return "-fPIC" - return "-h PIC" - - @property - def cxx_pic_flag(self): - if self.is_clang_based: - return "-fPIC" - return "-h PIC" - - @property - def f77_pic_flag(self): - if self.is_clang_based: - return "-fPIC" - return "-h PIC" - - @property - def fc_pic_flag(self): - if self.is_clang_based: - return "-fPIC" - return "-h PIC" - - @property - def stdcxx_libs(self): - # Cray compiler wrappers link to the standard C++ library - # without additional flags. - return () diff --git a/lib/spack/spack/compilers/clang.py b/lib/spack/spack/compilers/clang.py deleted file mode 100644 index 0e0e827de5e..00000000000 --- a/lib/spack/spack/compilers/clang.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os -import re - -import llnl.util.lang - -from spack.compiler import Compiler, UnsupportedCompilerFlag -from spack.version import Version - -#: compiler symlink mappings for mixed f77 compilers -f77_mapping = [ - ("gfortran", os.path.join("clang", "gfortran")), - ("xlf_r", os.path.join("xl_r", "xlf_r")), - ("xlf", os.path.join("xl", "xlf")), - ("ifort", os.path.join("intel", "ifort")), -] - -#: compiler symlink mappings for mixed f90/fc compilers -fc_mapping = [ - ("gfortran", os.path.join("clang", "gfortran")), - ("xlf90_r", os.path.join("xl_r", "xlf90_r")), - ("xlf90", os.path.join("xl", "xlf90")), - ("ifort", os.path.join("intel", "ifort")), -] - - -class Clang(Compiler): - version_argument = "--version" - - @property - def debug_flags(self): - return [ - "-gcodeview", - "-gdwarf-2", - "-gdwarf-3", - "-gdwarf-4", - "-gdwarf-5", - "-gline-tables-only", - "-gmodules", - "-g", - ] - - @property - def opt_flags(self): - return ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os", "-Oz", "-Og", "-O", "-O4"] - - # Clang has support for using different fortran compilers with the - # clang executable. - @property - def link_paths(self): - # clang links are always the same - link_paths = { - "cc": os.path.join("clang", "clang"), - "cxx": os.path.join("clang", "clang++"), - } - - # fortran links need to look at the actual compiler names from - # compilers.yaml to figure out which named symlink to use - for compiler_name, link_path in f77_mapping: - if self.f77 and compiler_name in self.f77: - link_paths["f77"] = link_path - break - else: - link_paths["f77"] = os.path.join("clang", "flang") - - for compiler_name, link_path in fc_mapping: - if self.fc and compiler_name in self.fc: - link_paths["fc"] = link_path - break - else: - link_paths["fc"] = os.path.join("clang", "flang") - - return link_paths - - @property - def verbose_flag(self): - return "-v" - - openmp_flag = "-fopenmp" - - # C++ flags based on CMake Modules/Compiler/Clang.cmake - - @property - def cxx11_flag(self): - if self.real_version < Version("3.3"): - raise UnsupportedCompilerFlag(self, "the C++11 standard", "cxx11_flag", "< 3.3") - return "-std=c++11" - - @property - def cxx14_flag(self): - if self.real_version < Version("3.4"): - raise UnsupportedCompilerFlag(self, "the C++14 standard", "cxx14_flag", "< 3.5") - elif self.real_version < Version("3.5"): - return "-std=c++1y" - - return "-std=c++14" - - @property - def cxx17_flag(self): - if self.real_version < Version("3.5"): - raise UnsupportedCompilerFlag(self, "the C++17 standard", "cxx17_flag", "< 3.5") - elif self.real_version < Version("5.0"): - return "-std=c++1z" - - return "-std=c++17" - - @property - def cxx20_flag(self): - if self.real_version < Version("5.0"): - raise UnsupportedCompilerFlag(self, "the C++20 standard", "cxx20_flag", "< 5.0") - elif self.real_version < Version("11.0"): - return "-std=c++2a" - else: - return "-std=c++20" - - @property - def cxx23_flag(self): - if self.real_version < Version("12.0"): - raise UnsupportedCompilerFlag(self, "the C++23 standard", "cxx23_flag", "< 12.0") - elif self.real_version < Version("17.0"): - return "-std=c++2b" - else: - return "-std=c++23" - - @property - def c99_flag(self): - return "-std=c99" - - @property - def c11_flag(self): - if self.real_version < Version("3.0"): - raise UnsupportedCompilerFlag(self, "the C11 standard", "c11_flag", "< 3.0") - if self.real_version < Version("3.1"): - return "-std=c1x" - return "-std=c11" - - @property - def c17_flag(self): - if self.real_version < Version("6.0"): - raise UnsupportedCompilerFlag(self, "the C17 standard", "c17_flag", "< 6.0") - return "-std=c17" - - @property - def c23_flag(self): - if self.real_version < Version("9.0"): - raise UnsupportedCompilerFlag(self, "the C23 standard", "c23_flag", "< 9.0") - elif self.real_version < Version("18.0"): - return "-std=c2x" - else: - return "-std=c23" - - @property - def cc_pic_flag(self): - return "-fPIC" - - @property - def cxx_pic_flag(self): - return "-fPIC" - - @property - def f77_pic_flag(self): - return "-fPIC" - - @property - def fc_pic_flag(self): - return "-fPIC" - - required_libs = ["libclang"] - - @classmethod - @llnl.util.lang.memoized - def extract_version_from_output(cls, output): - ver = "unknown" - if ("Apple" in output) or ("AMD" in output): - return ver - - match = re.search( - # Normal clang compiler versions are left as-is - r"(?:clang|flang-new) version ([^ )\n]+)-svn[~.\w\d-]*|" - # Don't include hyphenated patch numbers in the version - # (see https://github.com/spack/spack/pull/14365 for details) - r"(?:clang|flang-new) version ([^ )\n]+?)-[~.\w\d-]*|" - r"(?:clang|flang-new) version ([^ )\n]+)", - output, - ) - if match: - ver = match.group(match.lastindex) - return ver diff --git a/lib/spack/spack/compilers/fj.py b/lib/spack/spack/compilers/fj.py deleted file mode 100644 index 85c94130d49..00000000000 --- a/lib/spack/spack/compilers/fj.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -import spack.compiler - - -class Fj(spack.compiler.Compiler): - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("fj", "fcc"), - "cxx": os.path.join("fj", "case-insensitive", "FCC"), - "f77": os.path.join("fj", "frt"), - "fc": os.path.join("fj", "frt"), - } - - version_argument = "--version" - version_regex = r"\((?:FCC|FRT)\) ([a-z\d.]+)" - - required_libs = ["libfj90i", "libfj90f", "libfjsrcinfo"] - - @property - def verbose_flag(self): - return "-v" - - @property - def debug_flags(self): - return "-g" - - @property - def opt_flags(self): - return ["-O0", "-O1", "-O2", "-O3", "-Ofast"] - - @property - def openmp_flag(self): - return "-Kopenmp" - - @property - def cxx98_flag(self): - return "-std=c++98" - - @property - def cxx11_flag(self): - return "-std=c++11" - - @property - def cxx14_flag(self): - return "-std=c++14" - - @property - def cxx17_flag(self): - return "-std=c++17" - - @property - def c99_flag(self): - return "-std=c99" - - @property - def c11_flag(self): - return "-std=c11" - - @property - def cc_pic_flag(self): - return "-KPIC" - - @property - def cxx_pic_flag(self): - return "-KPIC" - - @property - def f77_pic_flag(self): - return "-KPIC" - - @property - def fc_pic_flag(self): - return "-KPIC" diff --git a/lib/spack/spack/compilers/gcc.py b/lib/spack/spack/compilers/gcc.py deleted file mode 100644 index db1f9eec26a..00000000000 --- a/lib/spack/spack/compilers/gcc.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -from llnl.util.filesystem import ancestor - -import spack.compiler -import spack.compilers.apple_clang as apple_clang -import spack.util.executable -from spack.version import Version - - -class Gcc(spack.compiler.Compiler): - # MacPorts builds gcc versions with prefixes and -mp-X or -mp-X.Y suffixes. - # Homebrew and Linuxbrew may build gcc with -X, -X.Y suffixes. - # Old compatibility versions may contain XY suffixes. - suffixes = [r"-mp-\d+(?:\.\d+)?", r"-\d+(?:\.\d+)?", r"\d\d"] - - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("gcc", "gcc"), - "cxx": os.path.join("gcc", "g++"), - "f77": os.path.join("gcc", "gfortran"), - "fc": os.path.join("gcc", "gfortran"), - } - - @property - def verbose_flag(self): - return "-v" - - @property - def debug_flags(self): - return ["-g", "-gstabs+", "-gstabs", "-gxcoff+", "-gxcoff", "-gvms"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-Os", "-Ofast", "-Og"] - - @property - def openmp_flag(self): - return "-fopenmp" - - @property - def cxx98_flag(self): - if self.real_version < Version("6.0"): - return "" - else: - return "-std=c++98" - - @property - def cxx11_flag(self): - if self.real_version < Version("4.3"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++11 standard", "cxx11_flag", " < 4.3" - ) - elif self.real_version < Version("4.7"): - return "-std=c++0x" - else: - return "-std=c++11" - - @property - def cxx14_flag(self): - if self.real_version < Version("4.8"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++14 standard", "cxx14_flag", "< 4.8" - ) - elif self.real_version < Version("4.9"): - return "-std=c++1y" - else: - return "-std=c++14" - - @property - def cxx17_flag(self): - if self.real_version < Version("5.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++17 standard", "cxx17_flag", "< 5.0" - ) - elif self.real_version < Version("6.0"): - return "-std=c++1z" - else: - return "-std=c++17" - - @property - def cxx20_flag(self): - if self.real_version < Version("8.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++20 standard", "cxx20_flag", "< 8.0" - ) - elif self.real_version < Version("11.0"): - return "-std=c++2a" - else: - return "-std=c++20" - - @property - def cxx23_flag(self): - if self.real_version < Version("11.0"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C++23 standard", "cxx23_flag", "< 11.0" - ) - elif self.real_version < Version("14.0"): - return "-std=c++2b" - else: - return "-std=c++23" - - @property - def c99_flag(self): - if self.real_version < Version("4.5"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C99 standard", "c99_flag", "< 4.5" - ) - return "-std=c99" - - @property - def c11_flag(self): - if self.real_version < Version("4.7"): - raise spack.compiler.UnsupportedCompilerFlag( - self, "the C11 standard", "c11_flag", "< 4.7" - ) - return "-std=c11" - - @property - def cc_pic_flag(self): - return "-fPIC" - - @property - def cxx_pic_flag(self): - return "-fPIC" - - @property - def f77_pic_flag(self): - return "-fPIC" - - @property - def fc_pic_flag(self): - return "-fPIC" - - required_libs = ["libgcc", "libgfortran"] - - @classmethod - def default_version(cls, cc): - """Older versions of gcc use the ``-dumpversion`` option. - Output looks like this:: - - 4.4.7 - - In GCC 7, this option was changed to only return the major - version of the compiler:: - - 7 - - A new ``-dumpfullversion`` option was added that gives us - what we want:: - - 7.2.0 - """ - # Apple's gcc is actually apple clang, so skip it. Returning - # "unknown" ensures this compiler is not detected by default. - # Users can add it manually to compilers.yaml at their own risk. - if apple_clang.AppleClang.default_version(cc) != "unknown": - return "unknown" - - version = super(Gcc, cls).default_version(cc) - if Version(version) >= Version("7"): - output = spack.compiler.get_compiler_version_output(cc, "-dumpfullversion") - version = cls.extract_version_from_output(output) - return version - - @property - def stdcxx_libs(self): - return ("-lstdc++",) - - @property - def prefix(self): - # GCC reports its install prefix when running ``-print-search-dirs`` - # on the first line ``install: ``. - cc = spack.util.executable.Executable(self.cc) - with self.compiler_environment(): - gcc_output = cc("-print-search-dirs", output=str, error=str) - - for line in gcc_output.splitlines(): - if line.startswith("install:"): - gcc_prefix = line.split(":")[1].strip() - # Go from /lib/gcc/// to - return ancestor(gcc_prefix, 4) - - raise RuntimeError( - "could not find install prefix of GCC from output:\n\t{}".format(gcc_output) - ) diff --git a/lib/spack/spack/compilers/intel.py b/lib/spack/spack/compilers/intel.py deleted file mode 100644 index f20e263d051..00000000000 --- a/lib/spack/spack/compilers/intel.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os -import sys - -from spack.compiler import Compiler, UnsupportedCompilerFlag -from spack.version import Version - - -class Intel(Compiler): - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("intel", "icc"), - "cxx": os.path.join("intel", "icpc"), - "f77": os.path.join("intel", "ifort"), - "fc": os.path.join("intel", "ifort"), - } - - if sys.platform == "win32": - version_argument = "/QV" - else: - version_argument = "--version" - - if sys.platform == "win32": - version_regex = r"([1-9][0-9]*\.[0-9]*\.[0-9]*)" - else: - version_regex = r"\((?:IFORT|ICC)\) ([^ ]+)" - - @property - def verbose_flag(self): - return "-v" - - required_libs = ["libirc", "libifcore", "libifcoremt", "libirng"] - - @property - def debug_flags(self): - return ["-debug", "-g", "-g0", "-g1", "-g2", "-g3"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os"] - - @property - def openmp_flag(self): - if self.real_version < Version("16.0"): - return "-openmp" - else: - return "-qopenmp" - - @property - def cxx11_flag(self): - if self.real_version < Version("11.1"): - raise UnsupportedCompilerFlag(self, "the C++11 standard", "cxx11_flag", "< 11.1") - - elif self.real_version < Version("13"): - return "-std=c++0x" - else: - return "-std=c++11" - - @property - def cxx14_flag(self): - # Adapted from CMake's Intel-CXX rules. - if self.real_version < Version("15"): - raise UnsupportedCompilerFlag(self, "the C++14 standard", "cxx14_flag", "< 15") - elif self.real_version < Version("15.0.2"): - return "-std=c++1y" - else: - return "-std=c++14" - - @property - def cxx17_flag(self): - # https://www.intel.com/content/www/us/en/developer/articles/news/c17-features-supported-by-c-compiler.html - if self.real_version < Version("19"): - raise UnsupportedCompilerFlag(self, "the C++17 standard", "cxx17_flag", "< 19") - else: - return "-std=c++17" - - @property - def c99_flag(self): - if self.real_version < Version("12"): - raise UnsupportedCompilerFlag(self, "the C99 standard", "c99_flag", "< 12") - else: - return "-std=c99" - - @property - def c11_flag(self): - if self.real_version < Version("16"): - raise UnsupportedCompilerFlag(self, "the C11 standard", "c11_flag", "< 16") - else: - return "-std=c1x" - - @property - def c18_flag(self): - # c18 supported since oneapi 2022, which is classic version 2021.5.0 - if self.real_version < Version("21.5.0"): - raise UnsupportedCompilerFlag(self, "the C18 standard", "c18_flag", "< 21.5.0") - else: - return "-std=c18" - - @property - def cc_pic_flag(self): - return "-fPIC" - - @property - def cxx_pic_flag(self): - return "-fPIC" - - @property - def f77_pic_flag(self): - return "-fPIC" - - @property - def fc_pic_flag(self): - return "-fPIC" - - @property - def stdcxx_libs(self): - return ("-cxxlib",) - - def setup_custom_environment(self, pkg, env): - # Edge cases for Intel's oneAPI compilers when using the legacy classic compilers: - # Always pass flags to disable deprecation warnings, since these warnings can - # confuse tools that parse the output of compiler commands (e.g. version checks). - if self.real_version >= Version("2021") and self.real_version < Version("2024"): - env.append_flags("SPACK_ALWAYS_CFLAGS", "-diag-disable=10441") - env.append_flags("SPACK_ALWAYS_CXXFLAGS", "-diag-disable=10441") - if self.real_version >= Version("2021") and self.real_version < Version("2025"): - env.append_flags("SPACK_ALWAYS_FFLAGS", "-diag-disable=10448") diff --git a/lib/spack/spack/compilers/msvc.py b/lib/spack/spack/compilers/msvc.py deleted file mode 100644 index 34d95606808..00000000000 --- a/lib/spack/spack/compilers/msvc.py +++ /dev/null @@ -1,393 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os -import re -import subprocess -import sys -import tempfile -from typing import Dict - -import archspec.cpu - -import spack.compiler -import spack.operating_systems.windows_os -import spack.platforms -import spack.util.executable -from spack.compiler import Compiler -from spack.error import SpackError -from spack.version import Version, VersionRange - -FC_PATH: Dict[str, str] = dict() - - -class CmdCall: - """Compose a call to `cmd` for an ordered series of cmd commands/scripts""" - - def __init__(self, *cmds): - if not cmds: - raise RuntimeError( - """Attempting to run commands from CMD without specifying commands. - Please add commands to be run.""" - ) - self._cmds = cmds - - def __call__(self): - out = subprocess.check_output(self.cmd_line, stderr=subprocess.STDOUT) # novermin - return out.decode("utf-16le", errors="replace") # novermin - - @property - def cmd_line(self): - base_call = "cmd /u /c " - commands = " && ".join([x.command_str() for x in self._cmds]) - # If multiple commands are being invoked by a single subshell - # they must be encapsulated by a double quote. Always double - # quote to be sure of proper handling - # cmd will properly resolve nested double quotes as needed - # - # `set`` writes out the active env to the subshell stdout, - # and in this context we are always trying to obtain env - # state so it should always be appended - return base_call + f'"{commands} && set"' - - -class VarsInvocation: - def __init__(self, script): - self._script = script - - def command_str(self): - return f'"{self._script}"' - - @property - def script(self): - return self._script - - -class VCVarsInvocation(VarsInvocation): - def __init__(self, script, arch, msvc_version): - super(VCVarsInvocation, self).__init__(script) - self._arch = arch - self._msvc_version = msvc_version - - @property - def sdk_ver(self): - """Accessor for Windows SDK version property - - Note: This property may not be set by - the calling context and as such this property will - return an empty string - - This property will ONLY be set if the SDK package - is a dependency somewhere in the Spack DAG of the package - for which we are constructing an MSVC compiler env. - Otherwise this property should be unset to allow the VCVARS - script to use its internal heuristics to determine appropriate - SDK version - """ - if getattr(self, "_sdk_ver", None): - return self._sdk_ver + ".0" - return "" - - @sdk_ver.setter - def sdk_ver(self, val): - self._sdk_ver = val - - @property - def arch(self): - return self._arch - - @property - def vcvars_ver(self): - return f"-vcvars_ver={self._msvc_version}" - - def command_str(self): - script = super(VCVarsInvocation, self).command_str() - return f"{script} {self.arch} {self.sdk_ver} {self.vcvars_ver}" - - -def get_valid_fortran_pth(): - """Assign maximum available fortran compiler version""" - # TODO (johnwparent): validate compatibility w/ try compiler - # functionality when added - sort_fn = lambda fc_ver: Version(fc_ver) - sort_fc_ver = sorted(list(FC_PATH.keys()), key=sort_fn) - return FC_PATH[sort_fc_ver[-1]] if sort_fc_ver else None - - -class Msvc(Compiler): - # Named wrapper links within build_env_path - # Due to the challenges of supporting compiler wrappers - # in Windows, we leave these blank, and dynamically compute - # based on proper versions of MSVC from there - # pending acceptance of #28117 for full support using - # compiler wrappers - link_paths = {"cc": "", "cxx": "", "f77": "", "fc": ""} - - #: Compiler argument that produces version information - version_argument = "" - - # For getting ifx's version, call it with version_argument - # and ignore the error code - ignore_version_errors = [1] - - #: Regex used to extract version from compiler's output - version_regex = r"([1-9][0-9]*\.[0-9]*\.[0-9]*)" - # The MSVC compiler class overrides this to prevent instances - # of erroneous matching on executable names that cannot be msvc - # compilers - suffixes = [] - - is_supported_on_platform = lambda x: isinstance(x, spack.platforms.Windows) - - def __init__(self, *args, **kwargs): - # This positional argument "paths" is later parsed and process by the base class - # via the call to `super` later in this method - paths = args[3] - latest_fc = get_valid_fortran_pth() - new_pth = [pth if pth else latest_fc for pth in paths[2:]] - paths[2:] = new_pth - # Initialize, deferring to base class but then adding the vcvarsallfile - # file based on compiler executable path. - super().__init__(*args, **kwargs) - # To use the MSVC compilers, VCVARS must be invoked - # VCVARS is located at a fixed location, referencable - # idiomatically by the following relative path from the - # compiler. - # Spack first finds the compilers via VSWHERE - # and stores their path, but their respective VCVARS - # file must be invoked before useage. - env_cmds = [] - compiler_root = os.path.join(os.path.dirname(self.cc), "../../../../../..") - vcvars_script_path = os.path.join(compiler_root, "Auxiliary", "Build", "vcvars64.bat") - # get current platform architecture and format for vcvars argument - arch = spack.platforms.real_host().default.lower() - arch = arch.replace("-", "_") - if str(archspec.cpu.host().family) == "x86_64": - arch = "amd64" - - self.vcvars_call = VCVarsInvocation(vcvars_script_path, arch, self.msvc_version) - env_cmds.append(self.vcvars_call) - # Below is a check for a valid fortran path - # paths has c, cxx, fc, and f77 paths in that order - # paths[2] refers to the fc path and is a generic check - # for a fortran compiler - if paths[2]: - - def get_oneapi_root(pth: str): - """From within a prefix known to be a oneAPI path - determine the oneAPI root path from arbitrary point - under root - - Args: - pth: path prefixed within oneAPI root - """ - if not pth: - return "" - while os.path.basename(pth) and os.path.basename(pth) != "oneAPI": - pth = os.path.dirname(pth) - return pth - - # If this found, it sets all the vars - oneapi_root = get_oneapi_root(self.fc) - if not oneapi_root: - raise RuntimeError(f"Non-oneAPI Fortran compiler {self.fc} assigned to MSVC") - oneapi_root_setvars = os.path.join(oneapi_root, "setvars.bat") - # some oneAPI exes return a version more precise than their - # install paths specify, so we determine path from - # the install path rather than the fc executable itself - numver = r"\d+\.\d+(?:\.\d+)?" - pattern = f"((?:{numver})|(?:latest))" - version_from_path = re.search(pattern, self.fc).group(1) - oneapi_version_setvars = os.path.join( - oneapi_root, "compiler", version_from_path, "env", "vars.bat" - ) - # order matters here, the specific version env must be invoked first, - # otherwise it will be ignored if the root setvars sets up the oneapi - # env first - env_cmds.extend( - [VarsInvocation(oneapi_version_setvars), VarsInvocation(oneapi_root_setvars)] - ) - self.msvc_compiler_environment = CmdCall(*env_cmds) - - @property - def cxx11_flag(self): - return "/std:c++11" - - @property - def cxx14_flag(self): - return "/std:c++14" - - @property - def cxx17_flag(self): - return "/std:c++17" - - @property - def cxx20_flag(self): - return "/std:c++20" - - @property - def c11_flag(self): - return "/std:c11" - - @property - def c17_flag(self): - return "/std:c17" - - @property - def msvc_version(self): - """This is the VCToolset version *NOT* the actual version of the cl compiler - For CL version, query `Msvc.cl_version`""" - return Version(re.search(Msvc.version_regex, self.cc).group(1)) - - @property - def short_msvc_version(self): - """This is the shorthand VCToolset version of form - MSVC - """ - return "MSVC" + self.vc_toolset_ver - - @property - def vc_toolset_ver(self): - """ - The toolset version is the version of the combined set of cl and link - This typically relates directly to VS version i.e. VS 2022 is v143 - VS 19 is v142, etc. - This value is defined by the first three digits of the major + minor - version of the VS toolset (143 for 14.3x.bbbbb). Traditionally the - minor version has remained a static two digit number for a VS release - series, however, as of VS22, this is no longer true, both - 14.4x.bbbbb and 14.3x.bbbbb are considered valid VS22 VC toolset - versions due to a change in toolset minor version sentiment. - - This is *NOT* the full version, for that see - Msvc.msvc_version or MSVC.platform_toolset_ver for the - raw platform toolset version - - """ - ver = self.msvc_version[:2].joined.string[:3] - return ver - - @property - def platform_toolset_ver(self): - """ - This is the platform toolset version of current MSVC compiler - i.e. 142. The platform toolset is the targeted MSVC library/compiler - versions by compilation (this is different from the VC Toolset) - - - This is different from the VC toolset version as established - by `short_msvc_version`, but typically are represented by the same - three digit value - """ - # Typically VS toolset version and platform toolset versions match - # VS22 introduces the first divergence of VS toolset version - # (144 for "recent" releases) and platform toolset version (143) - # so it needs additional handling until MS releases v144 - # (assuming v144 is also for VS22) - # or adds better support for detection - # TODO: (johnwparent) Update this logic for the next platform toolset - # or VC toolset version update - toolset_ver = self.vc_toolset_ver - vs22_toolset = Version(toolset_ver) > Version("142") - return toolset_ver if not vs22_toolset else "143" - - @property - def visual_studio_version(self): - """The four digit Visual Studio version (i.e. 2019 or 2022) - - Note: This differs from the msvc version or toolset version as - those properties track the compiler and build tools version - respectively, whereas this tracks the VS release associated - with a given MSVC compiler. - """ - return re.search(r"[0-9]{4}", self.cc).group(0) - - def _compiler_version(self, compiler): - """Returns version object for given compiler""" - # ignore_errors below is true here due to ifx's - # non zero return code if it is not provided - # and input file - return Version( - re.search( - Msvc.version_regex, - spack.compiler.get_compiler_version_output( - compiler, version_arg=None, ignore_errors=True - ), - ).group(1) - ) - - @property - def cl_version(self): - """Cl toolset version""" - return self._compiler_version(self.cc) - - @property - def ifx_version(self): - """Ifx compiler version associated with this version of MSVC""" - return self._compiler_version(self.fc) - - @property - def vs_root(self): - # The MSVC install root is located at a fix level above the compiler - # and is referenceable idiomatically via the pattern below - # this should be consistent accross versions - return os.path.abspath(os.path.join(self.cc, "../../../../../../../..")) - - def setup_custom_environment(self, pkg, env): - """Set environment variables for MSVC using the - Microsoft-provided script.""" - # Set the build environment variables for spack. Just using - # subprocess.call() doesn't work since that operates in its own - # environment which is destroyed (along with the adjusted variables) - # once the process terminates. So go the long way around: examine - # output, sort into dictionary, use that to make the build - # environment. - - # vcvars can target specific sdk versions, force it to pick up concretized sdk - # version, if needed by spec - if pkg.name != "win-sdk" and "win-sdk" in pkg.spec: - self.vcvars_call.sdk_ver = pkg.spec["win-sdk"].version.string - - out = self.msvc_compiler_environment() - int_env = dict( - (key, value) - for key, _, value in (line.partition("=") for line in out.splitlines()) - if key and value - ) - - for env_var in int_env: - if os.pathsep not in int_env[env_var]: - env.set(env_var, int_env[env_var]) - else: - env.set_path(env_var, int_env[env_var].split(os.pathsep)) - - # certain versions of ifx (2021.3.0:2023.1.0) do not play well with env:TMP - # that has a "." character in the path - # Work around by pointing tmp to the stage for the duration of the build - if self.fc and Version(self.fc_version(self.fc)).satisfies( - VersionRange("2021.3.0", "2023.1.0") - ): - new_tmp = tempfile.mkdtemp(dir=pkg.stage.path) - env.set("TMP", new_tmp) - - env.set("CC", self.cc) - env.set("CXX", self.cxx) - env.set("FC", self.fc) - env.set("F77", self.f77) - - @classmethod - def fc_version(cls, fc): - if not sys.platform == "win32": - return "unknown" - fc_ver = cls.default_version(fc) - FC_PATH[fc_ver] = fc - try: - sps = spack.operating_systems.windows_os.WindowsOs().compiler_search_paths - except AttributeError: - raise SpackError( - "Windows compiler search paths not established, " - "please report this behavior to github.com/spack/spack" - ) - clp = spack.util.executable.which_string("cl", path=sps) - return cls.default_version(clp) if clp else fc_ver diff --git a/lib/spack/spack/compilers/nag.py b/lib/spack/spack/compilers/nag.py deleted file mode 100644 index 7b78b06eaa3..00000000000 --- a/lib/spack/spack/compilers/nag.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os -import re - -import llnl.util.lang - -import spack.compiler - - -class Nag(spack.compiler.Compiler): - # Named wrapper links within build_env_path - # Use default wrappers for C and C++, in case provided in compilers.yaml - link_paths = { - "cc": "cc", - "cxx": "c++", - "f77": os.path.join("nag", "nagfor"), - "fc": os.path.join("nag", "nagfor"), - } - - version_argument = "-V" - - @classmethod - @llnl.util.lang.memoized - def extract_version_from_output(cls, output): - match = re.search(r"NAG Fortran Compiler Release (\d+).(\d+)\(.*\) Build (\d+)", output) - if match: - return ".".join(match.groups()) - - @property - def verbose_flag(self): - # NAG does not support a flag that would enable verbose output and - # compilation/linking at the same time (with either '-#' or '-dryrun' - # the compiler only prints the commands but does not run them). - # Therefore, the only thing we can do is to pass the '-v' argument to - # the underlying GCC. In order to get verbose output from the latter - # at both compile and linking stages, we need to call NAG with two - # additional flags: '-Wc,-v' and '-Wl,-v'. However, we return only - # '-Wl,-v' for the following reasons: - # 1) the interface of this method does not support multiple flags in - # the return value and, at least currently, verbose output at the - # linking stage has a higher priority for us; - # 2) NAG is usually mixed with GCC compiler, which also accepts - # '-Wl,-v' and produces meaningful result with it: '-v' is passed - # to the linker and the latter produces verbose output for the - # linking stage ('-Wc,-v', however, would break the compilation - # with a message from GCC that the flag is not recognized). - # - # This way, we at least enable the implicit rpath detection, which is - # based on compilation of a C file (see method - # spack.compiler._compile_dummy_c_source): in the case of a mixed - # NAG/GCC toolchain, the flag will be passed to g++ (e.g. - # 'g++ -Wl,-v ./main.c'), otherwise, the flag will be passed to nagfor - # (e.g. 'nagfor -Wl,-v ./main.c' - note that nagfor recognizes '.c' - # extension and treats the file accordingly). The list of detected - # rpaths will contain only GCC-related directories and rpaths to - # NAG-related directories are injected by nagfor anyway. - return "-Wl,-v" - - @property - def openmp_flag(self): - return "-openmp" - - @property - def debug_flags(self): - return ["-g", "-gline", "-g90"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-O4"] - - @property - def cxx11_flag(self): - # NAG does not have a C++ compiler - # However, it can be mixed with a compiler that does support it - return "-std=c++11" - - @property - def f77_pic_flag(self): - return "-PIC" - - @property - def fc_pic_flag(self): - return "-PIC" - - # Unlike other compilers, the NAG compiler passes options to GCC, which - # then passes them to the linker. Therefore, we need to doubly wrap the - # options with '-Wl,-Wl,,' - @property - def f77_rpath_arg(self): - return "-Wl,-Wl,,-rpath,," - - @property - def fc_rpath_arg(self): - return "-Wl,-Wl,,-rpath,," - - @property - def linker_arg(self): - return "-Wl,-Wl,," - - @property - def disable_new_dtags(self): - # Disable RPATH/RUNPATH forcing for NAG/GCC mixed toolchains: - return "" - - @property - def enable_new_dtags(self): - # Disable RPATH/RUNPATH forcing for NAG/GCC mixed toolchains: - return "" diff --git a/lib/spack/spack/compilers/nvhpc.py b/lib/spack/spack/compilers/nvhpc.py deleted file mode 100644 index 1c8e159f190..00000000000 --- a/lib/spack/spack/compilers/nvhpc.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -from spack.compiler import Compiler - - -class Nvhpc(Compiler): - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("nvhpc", "nvc"), - "cxx": os.path.join("nvhpc", "nvc++"), - "f77": os.path.join("nvhpc", "nvfortran"), - "fc": os.path.join("nvhpc", "nvfortran"), - } - - version_argument = "--version" - version_regex = r"nv[^ ]* (?:[^ ]+ Dev-r)?([0-9.]+)(?:-[0-9]+)?" - - @property - def verbose_flag(self): - return "-v" - - @property - def debug_flags(self): - return ["-g", "-gopt"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-O4"] - - @property - def openmp_flag(self): - return "-mp" - - @property - def cc_pic_flag(self): - return "-fpic" - - @property - def cxx_pic_flag(self): - return "-fpic" - - @property - def f77_pic_flag(self): - return "-fpic" - - @property - def fc_pic_flag(self): - return "-fpic" - - @property - def c99_flag(self): - return "-c99" - - @property - def c11_flag(self): - return "-c11" - - @property - def cxx11_flag(self): - return "--c++11" - - @property - def cxx14_flag(self): - return "--c++14" - - @property - def cxx17_flag(self): - return "--c++17" - - @property - def stdcxx_libs(self): - return ("-c++libs",) - - required_libs = ["libnvc", "libnvf"] diff --git a/lib/spack/spack/compilers/oneapi.py b/lib/spack/spack/compilers/oneapi.py deleted file mode 100644 index 255705c67be..00000000000 --- a/lib/spack/spack/compilers/oneapi.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os -from os.path import dirname, join - -from llnl.util import tty -from llnl.util.filesystem import ancestor - -import spack.util.executable -from spack.compiler import Compiler -from spack.version import Version - - -class Oneapi(Compiler): - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("oneapi", "icx"), - "cxx": os.path.join("oneapi", "icpx"), - "f77": os.path.join("oneapi", "ifx"), - "fc": os.path.join("oneapi", "ifx"), - } - - version_argument = "--version" - version_regex = r"(?:(?:oneAPI DPC\+\+(?:\/C\+\+)? Compiler)|(?:\(IFORT\))|(?:\(IFX\))) (\S+)" - - @property - def verbose_flag(self): - return "-v" - - required_libs = [ - "libirc", - "libifcore", - "libifcoremt", - "libirng", - "libsvml", - "libintlc", - "libimf", - "libsycl", - "libOpenCL", - ] - - @property - def debug_flags(self): - return ["-debug", "-g", "-g0", "-g1", "-g2", "-g3"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os"] - - @property - def openmp_flag(self): - return "-fiopenmp" - - # There may be some additional options here for offload, e.g. : - # -fopenmp-simd Emit OpenMP code only for SIMD-based constructs. - # -fopenmp-targets= - # -fopenmp-version= - # -fopenmp Parse OpenMP pragmas and generate parallel code. - # -qno-openmp Disable OpenMP support - # -qopenmp-link= Choose whether to link with the static or - # dynamic OpenMP libraries. Default is dynamic. - # -qopenmp-simd Emit OpenMP code only for SIMD-based constructs. - # -qopenmp-stubs enables the user to compile OpenMP programs in - # sequential mode. The OpenMP directives are - # ignored and a stub OpenMP library is linked. - # -qopenmp-threadprivate= - # -qopenmp Parse OpenMP pragmas and generate parallel code. - # -static-openmp Use the static host OpenMP runtime while - # linking. - # -Xopenmp-target= - # -Xopenmp-target Pass to the target offloading toolchain. - # Source: icx --help output - - @property - def cxx11_flag(self): - return "-std=c++11" - - @property - def cxx14_flag(self): - return "-std=c++14" - - @property - def cxx17_flag(self): - return "-std=c++17" - - @property - def cxx20_flag(self): - return "-std=c++20" - - @property - def c99_flag(self): - return "-std=c99" - - @property - def c11_flag(self): - return "-std=c1x" - - @property - def cc_pic_flag(self): - return "-fPIC" - - @property - def cxx_pic_flag(self): - return "-fPIC" - - @property - def f77_pic_flag(self): - return "-fPIC" - - @property - def fc_pic_flag(self): - return "-fPIC" - - @property - def stdcxx_libs(self): - return ("-cxxlib",) - - @property - def prefix(self): - # OneAPI reports its install prefix when running ``--version`` - # on the line ``InstalledDir: /bin/compiler``. - cc = spack.util.executable.Executable(self.cc) - with self.compiler_environment(): - oneapi_output = cc("--version", output=str, error=str) - - for line in oneapi_output.splitlines(): - if line.startswith("InstalledDir:"): - oneapi_prefix = line.split(":")[1].strip() - # Go from /bin/compiler to - return ancestor(oneapi_prefix, 2) - - raise RuntimeError( - "could not find install prefix of OneAPI from output:\n\t{}".format(oneapi_output) - ) - - def setup_custom_environment(self, pkg, env): - # workaround bug in icpx driver where it requires sycl-post-link is on the PATH - # It is located in the same directory as the driver. Error message: - # clang++: error: unable to execute command: - # Executable "sycl-post-link" doesn't exist! - # also ensures that shared objects and libraries required by the compiler, - # e.g. libonnx, can be found succesfully - # due to a fix, this is no longer required for OneAPI versions >= 2024.2 - if self.cxx and pkg.spec.satisfies("%oneapi@:2024.1"): - env.prepend_path("PATH", dirname(self.cxx)) - env.prepend_path("LD_LIBRARY_PATH", join(dirname(dirname(self.cxx)), "lib")) - - # Edge cases for Intel's oneAPI compilers when using the legacy classic compilers: - # Always pass flags to disable deprecation warnings, since these warnings can - # confuse tools that parse the output of compiler commands (e.g. version checks). - # This is really only needed for Fortran, since oneapi@ should be using either - # icx+icpx+ifx or icx+icpx+ifort. But to be on the safe side (some users may - # want to try to swap icpx against icpc, for example), and since the Intel LLVM - # compilers accept these diag-disable flags, we apply them for all compilers. - if self.real_version >= Version("2021") and self.real_version < Version("2024"): - env.append_flags("SPACK_ALWAYS_CFLAGS", "-diag-disable=10441") - env.append_flags("SPACK_ALWAYS_CXXFLAGS", "-diag-disable=10441") - if self.real_version >= Version("2021") and self.real_version < Version("2025"): - env.append_flags("SPACK_ALWAYS_FFLAGS", "-diag-disable=10448") - - # 2024 release bumped the libsycl version because of an ABI - # change, 2024 compilers are required. You will see this - # error: - # - # /usr/bin/ld: warning: libsycl.so.7, needed by ...., not found - if pkg.spec.satisfies("%oneapi@:2023"): - for c in ["dnn"]: - if pkg.spec.satisfies(f"^intel-oneapi-{c}@2024:"): - tty.warn(f"intel-oneapi-{c}@2024 SYCL APIs requires %oneapi@2024:") diff --git a/lib/spack/spack/compilers/rocmcc.py b/lib/spack/spack/compilers/rocmcc.py deleted file mode 100644 index e397dc90795..00000000000 --- a/lib/spack/spack/compilers/rocmcc.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import re - -import llnl.util.lang - -import spack.compilers.clang - - -class Rocmcc(spack.compilers.clang.Clang): - @property - def link_paths(self): - link_paths = { - "cc": "rocmcc/amdclang", - "cxx": "rocmcc/amdclang++", - "f77": "rocmcc/amdflang", - "fc": "rocmcc/amdflang", - } - - return link_paths - - @property - def cxx11_flag(self): - return "-std=c++11" - - @property - def cxx14_flag(self): - return "-std=c++14" - - @property - def cxx17_flag(self): - return "-std=c++17" - - @property - def c99_flag(self): - return "-std=c99" - - @property - def c11_flag(self): - return "-std=c11" - - @classmethod - @llnl.util.lang.memoized - def extract_version_from_output(cls, output): - match = re.search(r"llvm-project roc-(\d+)[._](\d+)[._](\d+)", output) - if match: - return ".".join(match.groups()) - - @property - def stdcxx_libs(self): - return ("-lstdc++",) diff --git a/lib/spack/spack/compilers/xl.py b/lib/spack/spack/compilers/xl.py deleted file mode 100644 index 8bdec9586b7..00000000000 --- a/lib/spack/spack/compilers/xl.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -from spack.compiler import Compiler, UnsupportedCompilerFlag -from spack.version import Version - - -class Xl(Compiler): - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("xl", "xlc"), - "cxx": os.path.join("xl", "xlc++"), - "f77": os.path.join("xl", "xlf"), - "fc": os.path.join("xl", "xlf90"), - } - - version_argument = "-qversion" - version_regex = r"([0-9]?[0-9]\.[0-9])" - - @property - def verbose_flag(self): - return "-V" - - @property - def debug_flags(self): - return ["-g", "-g0", "-g1", "-g2", "-g8", "-g9"] - - @property - def opt_flags(self): - return ["-O", "-O0", "-O1", "-O2", "-O3", "-O4", "-O5", "-Ofast"] - - @property - def openmp_flag(self): - return "-qsmp=omp" - - @property - def cxx11_flag(self): - if self.real_version < Version("13.1"): - raise UnsupportedCompilerFlag(self, "the C++11 standard", "cxx11_flag", "< 13.1") - else: - return "-qlanglvl=extended0x" - - @property - def c99_flag(self): - if self.real_version >= Version("13.1.1"): - return "-std=gnu99" - if self.real_version >= Version("10.1"): - return "-qlanglvl=extc99" - raise UnsupportedCompilerFlag(self, "the C99 standard", "c99_flag", "< 10.1") - - @property - def c11_flag(self): - if self.real_version >= Version("13.1.2"): - return "-std=gnu11" - if self.real_version >= Version("12.1"): - return "-qlanglvl=extc1x" - raise UnsupportedCompilerFlag(self, "the C11 standard", "c11_flag", "< 12.1") - - @property - def cxx14_flag(self): - # .real_version does not have the "y.z" component of "w.x.y.z", which - # is required to distinguish whether support is available - if self.version >= Version("16.1.1.8"): - return "-std=c++14" - raise UnsupportedCompilerFlag(self, "the C++14 standard", "cxx14_flag", "< 16.1.1.8") - - @property - def cc_pic_flag(self): - return "-qpic" - - @property - def cxx_pic_flag(self): - return "-qpic" - - @property - def f77_pic_flag(self): - return "-qpic" - - @property - def fc_pic_flag(self): - return "-qpic" - - @property - def fflags(self): - # The -qzerosize flag is effective only for the Fortran 77 - # compilers and allows the use of zero size objects. - # For Fortran 90 and beyond, it is set by default and has not impact. - # Its use has no negative side effects. - return "-qzerosize" diff --git a/lib/spack/spack/compilers/xl_r.py b/lib/spack/spack/compilers/xl_r.py deleted file mode 100644 index 2ed31fff453..00000000000 --- a/lib/spack/spack/compilers/xl_r.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -import spack.compilers.xl - - -class XlR(spack.compilers.xl.Xl): - # Named wrapper links within build_env_path - link_paths = { - "cc": os.path.join("xl_r", "xlc_r"), - "cxx": os.path.join("xl_r", "xlc++_r"), - "f77": os.path.join("xl_r", "xlf_r"), - "fc": os.path.join("xl_r", "xlf90_r"), - } diff --git a/lib/spack/spack/test/compilers/__init__.py b/lib/spack/spack/test/compilers/__init__.py deleted file mode 100644 index c4ecc87fb8a..00000000000 --- a/lib/spack/spack/test/compilers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) diff --git a/lib/spack/spack/test/compilers/basics.py b/lib/spack/spack/test/compilers/basics.py deleted file mode 100644 index 0e5a28be4ca..00000000000 --- a/lib/spack/spack/test/compilers/basics.py +++ /dev/null @@ -1,778 +0,0 @@ -# Copyright Spack Project Developers. See COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) -"""Test basic behavior of compilers in Spack""" -import json -import os -from copy import copy -from typing import Optional - -import pytest - -import llnl.util.filesystem as fs - -import spack.compiler -import spack.compilers -import spack.config -import spack.spec -import spack.util.module_cmd -from spack.compiler import Compiler -from spack.util.executable import Executable -from spack.util.file_cache import FileCache - - -# FIXME (compiler as nodes): revisit this test -# def test_multiple_conflicting_compiler_definitions(mutable_config): -# compiler_def = { -# "compiler": { -# "flags": {}, -# "modules": [], -# "paths": {"cc": "cc", "cxx": "cxx", "f77": "null", "fc": "null"}, -# "extra_rpaths": [], -# "operating_system": "test", -# "target": "test", -# "environment": {}, -# "spec": "clang@0.0.0", -# } -# } -# -# compiler_config = [compiler_def, compiler_def] -# compiler_config[0]["compiler"]["paths"]["f77"] = "f77" -# mutable_config.update_config("compilers", compiler_config) -# -# arch_spec = spack.spec.ArchSpec(("test", "test", "test")) -# cmp = spack.compilers.compiler_for_spec("clang@=0.0.0", arch_spec) -# assert cmp.f77 == "f77" - - -def test_compiler_flags_from_config_are_grouped(): - compiler_entry = { - "spec": "intel@17.0.2", - "operating_system": "foo-os", - "paths": {"cc": "cc-path", "cxx": "cxx-path", "fc": None, "f77": None}, - "flags": {"cflags": "-O0 -foo-flag foo-val"}, - "modules": None, - } - - compiler = spack.compilers.compiler_from_dict(compiler_entry) - assert any(x == "-foo-flag foo-val" for x in compiler.flags["cflags"]) - - -# Test behavior of flags and UnsupportedCompilerFlag. - -# Utility function to test most flags. -default_compiler_entry = { - "spec": "apple-clang@2.0.0", - "operating_system": "foo-os", - "paths": {"cc": "cc-path", "cxx": "cxx-path", "fc": "fc-path", "f77": "f77-path"}, - "flags": {}, - "modules": None, -} - - -# Fake up a mock compiler where everything is defaulted. -class MockCompiler(Compiler): - def __init__(self): - super().__init__( - cspec="badcompiler@1.0.0", - operating_system=default_compiler_entry["operating_system"], - target=None, - paths=[ - default_compiler_entry["paths"]["cc"], - default_compiler_entry["paths"]["cxx"], - default_compiler_entry["paths"]["fc"], - default_compiler_entry["paths"]["f77"], - ], - environment={}, - ) - - @property - def name(self): - return "mockcompiler" - - @property - def version(self): - return "1.0.0" - - _verbose_flag = "--verbose" - - @property - def verbose_flag(self): - return self._verbose_flag - - required_libs = ["libgfortran"] - - -@pytest.mark.not_on_windows("Not supported on Windows (yet)") -def test_implicit_rpaths(dirs_with_libfiles, monkeypatch): - lib_to_dirs, all_dirs = dirs_with_libfiles - monkeypatch.setattr( - MockCompiler, - "_compile_dummy_c_source", - lambda self: "ld " + " ".join(f"-L{d}" for d in all_dirs), - ) - retrieved_rpaths = MockCompiler().implicit_rpaths() - assert set(retrieved_rpaths) == set(lib_to_dirs["libstdc++"] + lib_to_dirs["libgfortran"]) - - -without_flag_output = "ld -L/path/to/first/lib -L/path/to/second/lib64" -with_flag_output = "ld -L/path/to/first/with/flag/lib -L/path/to/second/lib64" - - -def call_compiler(exe, *args, **kwargs): - # This method can replace Executable.__call__ to emulate a compiler that - # changes libraries depending on a flag. - if "--correct-flag" in exe.exe: - return with_flag_output - return without_flag_output - - -@pytest.mark.not_on_windows("Not supported on Windows (yet)") -@pytest.mark.parametrize( - "exe,flagname", - [ - ("cxx", "cxxflags"), - ("cxx", "cppflags"), - ("cxx", "ldflags"), - ("cc", "cflags"), - ("cc", "cppflags"), - ], -) -@pytest.mark.enable_compiler_execution -def test_compile_dummy_c_source_adds_flags(monkeypatch, exe, flagname): - # create fake compiler that emits mock verbose output - compiler = MockCompiler() - monkeypatch.setattr(Executable, "__call__", call_compiler) - - if exe == "cxx": - compiler.cc = None - compiler.fc = None - compiler.f77 = None - elif exe == "cc": - compiler.cxx = None - compiler.fc = None - compiler.f77 = None - else: - assert False - - # Test without flags - assert compiler._compile_dummy_c_source() == without_flag_output - - if flagname: - # set flags and test - compiler.flags = {flagname: ["--correct-flag"]} - assert compiler._compile_dummy_c_source() == with_flag_output - - -@pytest.mark.enable_compiler_execution -def test_compile_dummy_c_source_no_path(): - compiler = MockCompiler() - compiler.cc = None - compiler.cxx = None - assert compiler._compile_dummy_c_source() is None - - -@pytest.mark.enable_compiler_execution -def test_compile_dummy_c_source_no_verbose_flag(): - compiler = MockCompiler() - compiler._verbose_flag = None - assert compiler._compile_dummy_c_source() is None - - -@pytest.mark.not_on_windows("Not supported on Windows (yet)") -@pytest.mark.enable_compiler_execution -def test_compile_dummy_c_source_load_env(working_env, monkeypatch, tmpdir): - gcc = str(tmpdir.join("gcc")) - with open(gcc, "w", encoding="utf-8") as f: - f.write( - f"""#!/bin/sh -if [ "$ENV_SET" = "1" ] && [ "$MODULE_LOADED" = "1" ]; then - printf '{without_flag_output}' -fi -""" - ) - fs.set_executable(gcc) - - # Set module load to turn compiler on - def module(*args): - if args[0] == "show": - return "" - elif args[0] == "load": - os.environ["MODULE_LOADED"] = "1" - - monkeypatch.setattr(spack.util.module_cmd, "module", module) - - compiler = MockCompiler() - compiler.cc = gcc - compiler.environment = {"set": {"ENV_SET": "1"}} - compiler.modules = ["turn_on"] - - assert compiler._compile_dummy_c_source() == without_flag_output - - -# Get the desired flag from the specified compiler spec. -def flag_value(flag, spec): - compiler = None - if spec is None: - compiler = MockCompiler() - else: - compiler_entry = copy(default_compiler_entry) - compiler_entry["spec"] = spec - compiler = spack.compilers.compiler_from_dict(compiler_entry) - - return getattr(compiler, flag) - - -# Utility function to verify that the expected exception is thrown for -# an unsupported flag. -def unsupported_flag_test(flag, spec=None): - caught_exception = None - try: - flag_value(flag, spec) - except spack.compiler.UnsupportedCompilerFlag: - caught_exception = True - - assert caught_exception and "Expected exception not thrown." - - -# Verify the expected flag value for the give compiler spec. -def supported_flag_test(flag, flag_value_ref, spec=None): - assert flag_value(flag, spec) == flag_value_ref - - -# Tests for UnsupportedCompilerFlag exceptions from default -# implementations of flags. -def test_default_flags(): - supported_flag_test("cc_rpath_arg", "-Wl,-rpath,") - supported_flag_test("cxx_rpath_arg", "-Wl,-rpath,") - supported_flag_test("f77_rpath_arg", "-Wl,-rpath,") - supported_flag_test("fc_rpath_arg", "-Wl,-rpath,") - supported_flag_test("linker_arg", "-Wl,") - unsupported_flag_test("openmp_flag") - unsupported_flag_test("cxx11_flag") - unsupported_flag_test("cxx14_flag") - unsupported_flag_test("cxx17_flag") - supported_flag_test("cxx98_flag", "") - unsupported_flag_test("c99_flag") - unsupported_flag_test("c11_flag") - supported_flag_test("cc_pic_flag", "-fPIC") - supported_flag_test("cxx_pic_flag", "-fPIC") - supported_flag_test("f77_pic_flag", "-fPIC") - supported_flag_test("fc_pic_flag", "-fPIC") - supported_flag_test("debug_flags", ["-g"]) - supported_flag_test("opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3"]) - - -# Verify behavior of particular compiler definitions. -def test_arm_flags(): - supported_flag_test("openmp_flag", "-fopenmp", "arm@1.0") - supported_flag_test("cxx11_flag", "-std=c++11", "arm@1.0") - supported_flag_test("cxx14_flag", "-std=c++14", "arm@1.0") - supported_flag_test("cxx17_flag", "-std=c++1z", "arm@1.0") - supported_flag_test("c99_flag", "-std=c99", "arm@1.0") - supported_flag_test("c11_flag", "-std=c11", "arm@1.0") - supported_flag_test("cc_pic_flag", "-fPIC", "arm@1.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "arm@1.0") - supported_flag_test("f77_pic_flag", "-fPIC", "arm@1.0") - supported_flag_test("fc_pic_flag", "-fPIC", "arm@1.0") - supported_flag_test("opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast"], "arm@1.0") - - -def test_cce_flags(): - supported_flag_test("version_argument", "--version", "cce@9.0.1") - supported_flag_test("version_argument", "-V", "cce@9.0.1-classic") - supported_flag_test("openmp_flag", "-fopenmp", "cce@9.0.1") - supported_flag_test("openmp_flag", "-h omp", "cce@9.0.1-classic") - supported_flag_test("openmp_flag", "-h omp", "cce@1.0") - supported_flag_test("cxx11_flag", "-std=c++11", "cce@9.0.1") - supported_flag_test("cxx11_flag", "-h std=c++11", "cce@9.0.1-classic") - supported_flag_test("cxx11_flag", "-h std=c++11", "cce@1.0") - unsupported_flag_test("c99_flag", "cce@8.0") - supported_flag_test("c99_flag", "-std=c99", "cce@9.0.1") - supported_flag_test("c99_flag", "-h c99,noconform,gnu", "cce@8.1") - supported_flag_test("c99_flag", "-h std=c99,noconform,gnu", "cce@8.4") - unsupported_flag_test("c11_flag", "cce@8.4") - supported_flag_test("c11_flag", "-std=c11", "cce@9.0.1") - supported_flag_test("c11_flag", "-h std=c11,noconform,gnu", "cce@8.5") - supported_flag_test("cc_pic_flag", "-h PIC", "cce@1.0") - supported_flag_test("cxx_pic_flag", "-h PIC", "cce@1.0") - supported_flag_test("f77_pic_flag", "-h PIC", "cce@1.0") - supported_flag_test("fc_pic_flag", "-h PIC", "cce@1.0") - supported_flag_test("cc_pic_flag", "-fPIC", "cce@9.1.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "cce@9.1.0") - supported_flag_test("f77_pic_flag", "-fPIC", "cce@9.1.0") - supported_flag_test("fc_pic_flag", "-fPIC", "cce@9.1.0") - supported_flag_test("stdcxx_libs", (), "cce@1.0") - supported_flag_test("debug_flags", ["-g", "-G0", "-G1", "-G2", "-Gfast"], "cce@1.0") - - -def test_apple_clang_flags(): - supported_flag_test("openmp_flag", "-Xpreprocessor -fopenmp", "apple-clang@2.0.0") - unsupported_flag_test("cxx11_flag", "apple-clang@2.0.0") - supported_flag_test("cxx11_flag", "-std=c++11", "apple-clang@4.0.0") - unsupported_flag_test("cxx14_flag", "apple-clang@5.0.0") - supported_flag_test("cxx14_flag", "-std=c++1y", "apple-clang@5.1.0") - supported_flag_test("cxx14_flag", "-std=c++14", "apple-clang@6.1.0") - unsupported_flag_test("cxx17_flag", "apple-clang@6.0.0") - supported_flag_test("cxx17_flag", "-std=c++1z", "apple-clang@6.1.0") - supported_flag_test("c99_flag", "-std=c99", "apple-clang@6.1.0") - unsupported_flag_test("c11_flag", "apple-clang@3.0.0") - supported_flag_test("c11_flag", "-std=c11", "apple-clang@6.1.0") - supported_flag_test("cc_pic_flag", "-fPIC", "apple-clang@2.0.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "apple-clang@2.0.0") - supported_flag_test("f77_pic_flag", "-fPIC", "apple-clang@2.0.0") - supported_flag_test("fc_pic_flag", "-fPIC", "apple-clang@2.0.0") - - -def test_clang_flags(): - supported_flag_test("version_argument", "--version", "clang@foo.bar") - supported_flag_test("openmp_flag", "-fopenmp", "clang@3.3") - unsupported_flag_test("cxx11_flag", "clang@3.2") - supported_flag_test("cxx11_flag", "-std=c++11", "clang@3.3") - unsupported_flag_test("cxx14_flag", "clang@3.3") - supported_flag_test("cxx14_flag", "-std=c++1y", "clang@3.4") - supported_flag_test("cxx14_flag", "-std=c++14", "clang@3.5") - unsupported_flag_test("cxx17_flag", "clang@3.4") - supported_flag_test("cxx17_flag", "-std=c++1z", "clang@3.5") - supported_flag_test("cxx17_flag", "-std=c++17", "clang@5.0") - unsupported_flag_test("cxx20_flag", "clang@4.0") - supported_flag_test("cxx20_flag", "-std=c++2a", "clang@5.0") - supported_flag_test("cxx20_flag", "-std=c++20", "clang@11.0") - unsupported_flag_test("cxx23_flag", "clang@11.0") - supported_flag_test("cxx23_flag", "-std=c++2b", "clang@12.0") - supported_flag_test("cxx23_flag", "-std=c++23", "clang@17.0") - supported_flag_test("c99_flag", "-std=c99", "clang@3.3") - unsupported_flag_test("c11_flag", "clang@2.0") - supported_flag_test("c11_flag", "-std=c11", "clang@6.1.0") - unsupported_flag_test("c23_flag", "clang@8.0") - supported_flag_test("c23_flag", "-std=c2x", "clang@9.0") - supported_flag_test("c23_flag", "-std=c23", "clang@18.0") - supported_flag_test("cc_pic_flag", "-fPIC", "clang@3.3") - supported_flag_test("cxx_pic_flag", "-fPIC", "clang@3.3") - supported_flag_test("f77_pic_flag", "-fPIC", "clang@3.3") - supported_flag_test("fc_pic_flag", "-fPIC", "clang@3.3") - supported_flag_test( - "debug_flags", - [ - "-gcodeview", - "-gdwarf-2", - "-gdwarf-3", - "-gdwarf-4", - "-gdwarf-5", - "-gline-tables-only", - "-gmodules", - "-g", - ], - "clang@3.3", - ) - supported_flag_test( - "opt_flags", - ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os", "-Oz", "-Og", "-O", "-O4"], - "clang@3.3", - ) - - -def test_aocc_flags(): - supported_flag_test( - "debug_flags", - [ - "-gcodeview", - "-gdwarf-2", - "-gdwarf-3", - "-gdwarf-4", - "-gdwarf-5", - "-gline-tables-only", - "-gmodules", - "-g", - ], - "aocc@2.2.0", - ) - supported_flag_test( - "opt_flags", - ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os", "-Oz", "-Og", "-O", "-O4"], - "aocc@2.2.0", - ) - - supported_flag_test("stdcxx_libs", ("-lstdc++",), "aocc@2.2.0") - supported_flag_test("openmp_flag", "-fopenmp", "aocc@2.2.0") - supported_flag_test("cxx11_flag", "-std=c++11", "aocc@2.2.0") - supported_flag_test("cxx14_flag", "-std=c++14", "aocc@2.2.0") - supported_flag_test("cxx17_flag", "-std=c++17", "aocc@2.2.0") - supported_flag_test("c99_flag", "-std=c99", "aocc@2.2.0") - supported_flag_test("c11_flag", "-std=c11", "aocc@2.2.0") - supported_flag_test("cc_pic_flag", "-fPIC", "aocc@2.2.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "aocc@2.2.0") - supported_flag_test("f77_pic_flag", "-fPIC", "aocc@2.2.0") - supported_flag_test("fc_pic_flag", "-fPIC", "aocc@2.2.0") - supported_flag_test("version_argument", "--version", "aocc@2.2.0") - flg = "-Wno-unused-command-line-argument -mllvm -eliminate-similar-expr=false" - supported_flag_test("cflags", flg, "aocc@3.0.0") - supported_flag_test("cxxflags", flg, "aocc@3.0.0") - supported_flag_test("fflags", flg, "aocc@3.0.0") - - -def test_fj_flags(): - supported_flag_test("openmp_flag", "-Kopenmp", "fj@4.0.0") - supported_flag_test("cxx98_flag", "-std=c++98", "fj@4.0.0") - supported_flag_test("cxx11_flag", "-std=c++11", "fj@4.0.0") - supported_flag_test("cxx14_flag", "-std=c++14", "fj@4.0.0") - supported_flag_test("cxx17_flag", "-std=c++17", "fj@4.0.0") - supported_flag_test("c99_flag", "-std=c99", "fj@4.0.0") - supported_flag_test("c11_flag", "-std=c11", "fj@4.0.0") - supported_flag_test("cc_pic_flag", "-KPIC", "fj@4.0.0") - supported_flag_test("cxx_pic_flag", "-KPIC", "fj@4.0.0") - supported_flag_test("f77_pic_flag", "-KPIC", "fj@4.0.0") - supported_flag_test("fc_pic_flag", "-KPIC", "fj@4.0.0") - supported_flag_test("opt_flags", ["-O0", "-O1", "-O2", "-O3", "-Ofast"], "fj@4.0.0") - supported_flag_test("debug_flags", "-g", "fj@4.0.0") - - -def test_gcc_flags(): - supported_flag_test("openmp_flag", "-fopenmp", "gcc@4.1") - supported_flag_test("cxx98_flag", "", "gcc@5.2") - supported_flag_test("cxx98_flag", "-std=c++98", "gcc@6.0") - unsupported_flag_test("cxx11_flag", "gcc@4.2") - supported_flag_test("cxx11_flag", "-std=c++0x", "gcc@4.3") - supported_flag_test("cxx11_flag", "-std=c++11", "gcc@4.7") - unsupported_flag_test("cxx14_flag", "gcc@4.7") - supported_flag_test("cxx14_flag", "-std=c++1y", "gcc@4.8") - supported_flag_test("cxx14_flag", "-std=c++14", "gcc@4.9") - supported_flag_test("cxx14_flag", "-std=c++14", "gcc@6.0") - unsupported_flag_test("cxx17_flag", "gcc@4.9") - supported_flag_test("cxx17_flag", "-std=c++1z", "gcc@5.0") - supported_flag_test("cxx17_flag", "-std=c++17", "gcc@6.0") - unsupported_flag_test("c99_flag", "gcc@4.4") - supported_flag_test("c99_flag", "-std=c99", "gcc@4.5") - unsupported_flag_test("c11_flag", "gcc@4.6") - supported_flag_test("c11_flag", "-std=c11", "gcc@4.7") - supported_flag_test("cc_pic_flag", "-fPIC", "gcc@4.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "gcc@4.0") - supported_flag_test("f77_pic_flag", "-fPIC", "gcc@4.0") - supported_flag_test("fc_pic_flag", "-fPIC", "gcc@4.0") - supported_flag_test("stdcxx_libs", ("-lstdc++",), "gcc@4.1") - supported_flag_test( - "debug_flags", ["-g", "-gstabs+", "-gstabs", "-gxcoff+", "-gxcoff", "-gvms"], "gcc@4.0" - ) - supported_flag_test( - "opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-Os", "-Ofast", "-Og"], "gcc@4.0" - ) - - -def test_intel_flags(): - supported_flag_test("openmp_flag", "-openmp", "intel@=15.0") - supported_flag_test("openmp_flag", "-qopenmp", "intel@=16.0") - unsupported_flag_test("cxx11_flag", "intel@=11.0") - supported_flag_test("cxx11_flag", "-std=c++0x", "intel@=12.0") - supported_flag_test("cxx11_flag", "-std=c++11", "intel@=13") - unsupported_flag_test("cxx14_flag", "intel@=14.0") - supported_flag_test("cxx14_flag", "-std=c++1y", "intel@=15.0") - supported_flag_test("cxx14_flag", "-std=c++14", "intel@=15.0.2") - unsupported_flag_test("cxx17_flag", "intel@=18") - supported_flag_test("cxx17_flag", "-std=c++17", "intel@=19.0") - unsupported_flag_test("c99_flag", "intel@=11.0") - supported_flag_test("c99_flag", "-std=c99", "intel@=12.0") - unsupported_flag_test("c11_flag", "intel@=15.0") - supported_flag_test("c18_flag", "-std=c18", "intel@=21.5.0") - unsupported_flag_test("c18_flag", "intel@=21.4.0") - supported_flag_test("c11_flag", "-std=c1x", "intel@=16.0") - supported_flag_test("cc_pic_flag", "-fPIC", "intel@=1.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "intel@=1.0") - supported_flag_test("f77_pic_flag", "-fPIC", "intel@=1.0") - supported_flag_test("fc_pic_flag", "-fPIC", "intel@=1.0") - supported_flag_test("stdcxx_libs", ("-cxxlib",), "intel@=1.0") - supported_flag_test("debug_flags", ["-debug", "-g", "-g0", "-g1", "-g2", "-g3"], "intel@=1.0") - supported_flag_test( - "opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os"], "intel@=1.0" - ) - - -def test_oneapi_flags(): - supported_flag_test("openmp_flag", "-fiopenmp", "oneapi@=2020.8.0.0827") - supported_flag_test("cxx11_flag", "-std=c++11", "oneapi@=2020.8.0.0827") - supported_flag_test("cxx14_flag", "-std=c++14", "oneapi@=2020.8.0.0827") - supported_flag_test("c99_flag", "-std=c99", "oneapi@=2020.8.0.0827") - supported_flag_test("c11_flag", "-std=c1x", "oneapi@=2020.8.0.0827") - supported_flag_test("cc_pic_flag", "-fPIC", "oneapi@=2020.8.0.0827") - supported_flag_test("cxx_pic_flag", "-fPIC", "oneapi@=2020.8.0.0827") - supported_flag_test("f77_pic_flag", "-fPIC", "oneapi@=2020.8.0.0827") - supported_flag_test("fc_pic_flag", "-fPIC", "oneapi@=2020.8.0.0827") - supported_flag_test("stdcxx_libs", ("-cxxlib",), "oneapi@=2020.8.0.0827") - supported_flag_test( - "debug_flags", ["-debug", "-g", "-g0", "-g1", "-g2", "-g3"], "oneapi@=2020.8.0.0827" - ) - supported_flag_test( - "opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os"], "oneapi@=2020.8.0.0827" - ) - - -def test_nag_flags(): - supported_flag_test("openmp_flag", "-openmp", "nag@=1.0") - supported_flag_test("cxx11_flag", "-std=c++11", "nag@=1.0") - supported_flag_test("cc_pic_flag", "-fPIC", "nag@=1.0") - supported_flag_test("cxx_pic_flag", "-fPIC", "nag@=1.0") - supported_flag_test("f77_pic_flag", "-PIC", "nag@=1.0") - supported_flag_test("fc_pic_flag", "-PIC", "nag@=1.0") - supported_flag_test("cc_rpath_arg", "-Wl,-rpath,", "nag@=1.0") - supported_flag_test("cxx_rpath_arg", "-Wl,-rpath,", "nag@=1.0") - supported_flag_test("f77_rpath_arg", "-Wl,-Wl,,-rpath,,", "nag@=1.0") - supported_flag_test("fc_rpath_arg", "-Wl,-Wl,,-rpath,,", "nag@=1.0") - supported_flag_test("linker_arg", "-Wl,-Wl,,", "nag@=1.0") - supported_flag_test("debug_flags", ["-g", "-gline", "-g90"], "nag@=1.0") - supported_flag_test("opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-O4"], "nag@=1.0") - - -def test_nvhpc_flags(): - supported_flag_test("openmp_flag", "-mp", "nvhpc@=20.9") - supported_flag_test("cxx11_flag", "--c++11", "nvhpc@=20.9") - supported_flag_test("cxx14_flag", "--c++14", "nvhpc@=20.9") - supported_flag_test("cxx17_flag", "--c++17", "nvhpc@=20.9") - supported_flag_test("c99_flag", "-c99", "nvhpc@=20.9") - supported_flag_test("c11_flag", "-c11", "nvhpc@=20.9") - supported_flag_test("cc_pic_flag", "-fpic", "nvhpc@=20.9") - supported_flag_test("cxx_pic_flag", "-fpic", "nvhpc@=20.9") - supported_flag_test("f77_pic_flag", "-fpic", "nvhpc@=20.9") - supported_flag_test("fc_pic_flag", "-fpic", "nvhpc@=20.9") - supported_flag_test("debug_flags", ["-g", "-gopt"], "nvhpc@=20.9") - supported_flag_test("opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-O4"], "nvhpc@=20.9") - supported_flag_test("stdcxx_libs", ("-c++libs",), "nvhpc@=20.9") - - -def test_xl_flags(): - supported_flag_test("openmp_flag", "-qsmp=omp", "xl@=1.0") - unsupported_flag_test("cxx11_flag", "xl@=13.0") - supported_flag_test("cxx11_flag", "-qlanglvl=extended0x", "xl@=13.1") - unsupported_flag_test("c99_flag", "xl@=10.0") - supported_flag_test("c99_flag", "-qlanglvl=extc99", "xl@=10.1") - supported_flag_test("c99_flag", "-std=gnu99", "xl@=13.1.1") - unsupported_flag_test("c11_flag", "xl@=12.0") - supported_flag_test("c11_flag", "-qlanglvl=extc1x", "xl@=12.1") - supported_flag_test("c11_flag", "-std=gnu11", "xl@=13.1.2") - supported_flag_test("cc_pic_flag", "-qpic", "xl@=1.0") - supported_flag_test("cxx_pic_flag", "-qpic", "xl@=1.0") - supported_flag_test("f77_pic_flag", "-qpic", "xl@=1.0") - supported_flag_test("fc_pic_flag", "-qpic", "xl@=1.0") - supported_flag_test("fflags", "-qzerosize", "xl@=1.0") - supported_flag_test("debug_flags", ["-g", "-g0", "-g1", "-g2", "-g8", "-g9"], "xl@=1.0") - supported_flag_test( - "opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-O4", "-O5", "-Ofast"], "xl@=1.0" - ) - - -def test_xl_r_flags(): - supported_flag_test("openmp_flag", "-qsmp=omp", "xl_r@=1.0") - unsupported_flag_test("cxx11_flag", "xl_r@=13.0") - supported_flag_test("cxx11_flag", "-qlanglvl=extended0x", "xl_r@=13.1") - unsupported_flag_test("c99_flag", "xl_r@=10.0") - supported_flag_test("c99_flag", "-qlanglvl=extc99", "xl_r@=10.1") - supported_flag_test("c99_flag", "-std=gnu99", "xl_r@=13.1.1") - unsupported_flag_test("c11_flag", "xl_r@=12.0") - supported_flag_test("c11_flag", "-qlanglvl=extc1x", "xl_r@=12.1") - supported_flag_test("c11_flag", "-std=gnu11", "xl_r@=13.1.2") - supported_flag_test("cc_pic_flag", "-qpic", "xl_r@=1.0") - supported_flag_test("cxx_pic_flag", "-qpic", "xl_r@=1.0") - supported_flag_test("f77_pic_flag", "-qpic", "xl_r@=1.0") - supported_flag_test("fc_pic_flag", "-qpic", "xl_r@=1.0") - supported_flag_test("fflags", "-qzerosize", "xl_r@=1.0") - supported_flag_test("debug_flags", ["-g", "-g0", "-g1", "-g2", "-g8", "-g9"], "xl@=1.0") - supported_flag_test( - "opt_flags", ["-O", "-O0", "-O1", "-O2", "-O3", "-O4", "-O5", "-Ofast"], "xl@=1.0" - ) - - -# FIXME (compiler as nodes): revisit this test -# @pytest.mark.regression("14798,13733") -# def test_raising_if_compiler_target_is_over_specific(config): -# # Compiler entry with an overly specific target -# compilers = [ -# { -# "compiler": { -# "spec": "gcc@9.0.1", -# "paths": { -# "cc": "/usr/bin/gcc-9", -# "cxx": "/usr/bin/g++-9", -# "f77": "/usr/bin/gfortran-9", -# "fc": "/usr/bin/gfortran-9", -# }, -# "flags": {}, -# "operating_system": "ubuntu18.04", -# "target": "haswell", -# "modules": [], -# "environment": {}, -# "extra_rpaths": [], -# } -# } -# ] -# arch_spec = spack.spec.ArchSpec(("linux", "ubuntu18.04", "haswell")) -# with spack.config.override("compilers", compilers): -# cfg = spack.compilers.get_compiler_config(config) -# with pytest.raises(ValueError): -# spack.compilers.get_compilers(cfg, spack.spec.CompilerSpec("gcc@9.0.1"), arch_spec) - -# FIXME (compiler as nodes): revisit this test -# @pytest.mark.regression("42679") -# def test_get_compilers(config): -# """Tests that we can select compilers whose versions differ only for a suffix.""" -# common = { -# "flags": {}, -# "operating_system": "ubuntu23.10", -# "target": "x86_64", -# "modules": [], -# "environment": {}, -# "extra_rpaths": [], -# } -# with_suffix = { -# "spec": "gcc@13.2.0-suffix", -# "paths": { -# "cc": "/usr/bin/gcc-13.2.0-suffix", -# "cxx": "/usr/bin/g++-13.2.0-suffix", -# "f77": "/usr/bin/gfortran-13.2.0-suffix", -# "fc": "/usr/bin/gfortran-13.2.0-suffix", -# }, -# **common, -# } -# without_suffix = { -# "spec": "gcc@13.2.0", -# "paths": { -# "cc": "/usr/bin/gcc-13.2.0", -# "cxx": "/usr/bin/g++-13.2.0", -# "f77": "/usr/bin/gfortran-13.2.0", -# "fc": "/usr/bin/gfortran-13.2.0", -# }, -# **common, -# } -# -# compilers = [{"compiler": without_suffix}, {"compiler": with_suffix}] -# -# assert spack.compilers.get_compilers( -# compilers, cspec=spack.spec.CompilerSpec("gcc@=13.2.0-suffix") -# ) == [spack.compilers._compiler_from_config_entry(with_suffix)] -# -# assert spack.compilers.get_compilers( -# compilers, cspec=spack.spec.CompilerSpec("gcc@=13.2.0") -# ) == [spack.compilers._compiler_from_config_entry(without_suffix)] - - -@pytest.mark.enable_compiler_verification -def test_compiler_executable_verification_raises(tmpdir): - compiler = MockCompiler() - compiler.cc = "/this/path/does/not/exist" - - with pytest.raises(spack.compiler.CompilerAccessError): - compiler.verify_executables() - - -@pytest.mark.enable_compiler_verification -def test_compiler_executable_verification_success(tmpdir): - def prepare_executable(name): - real = str(tmpdir.join("cc").ensure()) - fs.set_executable(real) - setattr(compiler, name, real) - - # setup mock compiler with real paths - compiler = MockCompiler() - for name in ("cc", "cxx", "f77", "fc"): - prepare_executable(name) - - # testing that this doesn't raise an error because the paths exist and - # are executable - compiler.verify_executables() - - # Test that null entries don't fail - compiler.cc = None - compiler.verify_executables() - - -@pytest.mark.parametrize( - "compilers_extra_attributes,expected_length", - [ - # If we detect a C compiler we expect the result to be valid - ({"c": "/usr/bin/clang-12", "cxx": "/usr/bin/clang-12"}, 1), - # If we detect only a C++ compiler we expect the result to be discarded - ({"cxx": "/usr/bin/clang-12"}, 0), - ], -) -def test_detection_requires_c_compiler(compilers_extra_attributes, expected_length): - """Tests that compilers automatically added to the configuration have - at least a C compiler. - """ - packages_yaml = { - "llvm": { - "externals": [ - { - "spec": "clang@12.0.0", - "prefix": "/usr", - "extra_attributes": {"compilers": compilers_extra_attributes}, - } - ] - } - } - result = spack.compilers.CompilerFactory.from_packages_yaml(packages_yaml) - assert len(result) == expected_length - - -def test_compiler_environment(working_env): - """Test whether environment modifications from compilers are applied in compiler_environment""" - os.environ.pop("TEST", None) - compiler = Compiler( - "gcc@=13.2.0", - operating_system="ubuntu20.04", - target="x86_64", - paths=["/test/bin/gcc", "/test/bin/g++"], - environment={"set": {"TEST": "yes"}}, - ) - with compiler.compiler_environment(): - assert os.environ["TEST"] == "yes" - - -class MockCompilerWithoutExecutables(MockCompiler): - def __init__(self): - super().__init__() - self._compile_dummy_c_source_count = 0 - self._get_real_version_count = 0 - - def _compile_dummy_c_source(self) -> Optional[str]: - self._compile_dummy_c_source_count += 1 - return "gcc helloworld.c -o helloworld" - - def get_real_version(self) -> str: - self._get_real_version_count += 1 - return "1.0.0" - - -def test_compiler_output_caching(tmp_path): - """Test that compiler output is cached on the filesystem.""" - # The first call should trigger the cache to updated. - a = MockCompilerWithoutExecutables() - cache = spack.compiler.FileCompilerCache(FileCache(str(tmp_path))) - assert cache.get(a).c_compiler_output == "gcc helloworld.c -o helloworld" - assert cache.get(a).real_version == "1.0.0" - assert a._compile_dummy_c_source_count == 1 - assert a._get_real_version_count == 1 - - # The second call on an equivalent but distinct object should not trigger compiler calls. - b = MockCompilerWithoutExecutables() - cache = spack.compiler.FileCompilerCache(FileCache(str(tmp_path))) - assert cache.get(b).c_compiler_output == "gcc helloworld.c -o helloworld" - assert cache.get(b).real_version == "1.0.0" - assert b._compile_dummy_c_source_count == 0 - assert b._get_real_version_count == 0 - - # Cache schema change should be handled gracefully. - with open(cache.cache.cache_path(cache.name), "w", encoding="utf-8") as f: - for k in cache._data: - cache._data[k] = "corrupted entry" - f.write(json.dumps(cache._data)) - - c = MockCompilerWithoutExecutables() - cache = spack.compiler.FileCompilerCache(FileCache(str(tmp_path))) - assert cache.get(c).c_compiler_output == "gcc helloworld.c -o helloworld" - assert cache.get(c).real_version == "1.0.0" - - # Cache corruption should be handled gracefully. - with open(cache.cache.cache_path(cache.name), "w", encoding="utf-8") as f: - f.write("corrupted cache") - - d = MockCompilerWithoutExecutables() - cache = spack.compiler.FileCompilerCache(FileCache(str(tmp_path))) - assert cache.get(d).c_compiler_output == "gcc helloworld.c -o helloworld" - assert cache.get(d).real_version == "1.0.0"