Remove spack.compilers Python modules
Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
parent
67b04f1b8d
commit
bec58a1554
@ -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<dir>[/\\].*)")
|
||||
|
||||
#: regex to match linker library path arguments
|
||||
_LIBPATH_ARG = re.compile(r"^[-/](LIBPATH|libpath):(?P<dir>.*)")
|
||||
|
||||
|
||||
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 <prefix><name><suffix>
|
||||
# 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
|
@ -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"
|
@ -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"
|
@ -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:
|
||||
#
|
||||
# $ arm<c/f>lang --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"]
|
@ -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 ()
|
@ -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
|
@ -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"
|
@ -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: <prefix>``.
|
||||
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 <prefix>/lib/gcc/<triplet>/<version>/ to <prefix>
|
||||
return ancestor(gcc_prefix, 4)
|
||||
|
||||
raise RuntimeError(
|
||||
"could not find install prefix of GCC from output:\n\t{}".format(gcc_output)
|
||||
)
|
@ -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")
|
@ -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<short-ver>
|
||||
"""
|
||||
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
|
@ -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 ""
|
@ -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"]
|
@ -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=<value>
|
||||
# -fopenmp-version=<value>
|
||||
# -fopenmp Parse OpenMP pragmas and generate parallel code.
|
||||
# -qno-openmp Disable OpenMP support
|
||||
# -qopenmp-link=<value> 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=<value>
|
||||
# -qopenmp Parse OpenMP pragmas and generate parallel code.
|
||||
# -static-openmp Use the static host OpenMP runtime while
|
||||
# linking.
|
||||
# -Xopenmp-target=<triple> <arg>
|
||||
# -Xopenmp-target <arg> Pass <arg> 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: <prefix>/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 <prefix>/bin/compiler to <prefix>
|
||||
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:")
|
@ -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++",)
|
@ -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"
|
@ -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"),
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
# Copyright Spack Project Developers. See COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
@ -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"
|
Loading…
Reference in New Issue
Block a user