Write adaptors for CompilerSpec and Compiler
Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
parent
cdc8236169
commit
9ca0bd5d97
@ -10,6 +10,7 @@
|
|||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
import spack.phase_callbacks
|
import spack.phase_callbacks
|
||||||
|
from spack.directives import depends_on
|
||||||
|
|
||||||
from .cmake import CMakeBuilder, CMakePackage
|
from .cmake import CMakeBuilder, CMakePackage
|
||||||
|
|
||||||
@ -357,6 +358,10 @@ class CachedCMakePackage(CMakePackage):
|
|||||||
|
|
||||||
CMakeBuilder = CachedCMakeBuilder
|
CMakeBuilder = CachedCMakeBuilder
|
||||||
|
|
||||||
|
# These dependencies are assumed in the builder
|
||||||
|
depends_on("c", type="build")
|
||||||
|
depends_on("cxx", type="build")
|
||||||
|
|
||||||
def flag_handler(self, name, flags):
|
def flag_handler(self, name, flags):
|
||||||
if name in ("cflags", "cxxflags", "cppflags", "fflags"):
|
if name in ("cflags", "cxxflags", "cppflags", "fflags"):
|
||||||
return None, None, None # handled in the cmake cache
|
return None, None, None # handled in the cmake cache
|
||||||
|
211
lib/spack/spack/compilers/adaptor.py
Normal file
211
lib/spack/spack/compilers/adaptor.py
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
# Copyright Spack Project Developers. See COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import enum
|
||||||
|
import typing
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from llnl.util import lang
|
||||||
|
|
||||||
|
from .libraries import CompilerPropertyDetector
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
import spack.spec
|
||||||
|
|
||||||
|
|
||||||
|
class Languages(enum.Enum):
|
||||||
|
C = "c"
|
||||||
|
CXX = "cxx"
|
||||||
|
FORTRAN = "fortran"
|
||||||
|
|
||||||
|
|
||||||
|
class CompilerAdaptor:
|
||||||
|
def __init__(
|
||||||
|
self, compiled_spec: "spack.spec.Spec", compilers: Dict[Languages, "spack.spec.Spec"]
|
||||||
|
) -> None:
|
||||||
|
if not compilers:
|
||||||
|
raise AttributeError(f"{compiled_spec} has no 'compiler' attribute")
|
||||||
|
|
||||||
|
self.compilers = compilers
|
||||||
|
self.compiled_spec = compiled_spec
|
||||||
|
|
||||||
|
def _lang_exists_or_raise(self, name: str, *, lang: Languages) -> None:
|
||||||
|
if lang not in self.compilers:
|
||||||
|
raise AttributeError(
|
||||||
|
f"'{self.compiled_spec}' has no {lang.value} compiler, so the "
|
||||||
|
f"'{name}' property cannot be retrieved"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _maybe_return_attribute(self, name: str, *, lang: Languages) -> str:
|
||||||
|
self._lang_exists_or_raise(name, lang=lang)
|
||||||
|
return getattr(self.compilers[lang].package, name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cc_rpath_arg(self) -> str:
|
||||||
|
self._lang_exists_or_raise("cc_rpath_arg", lang=Languages.C)
|
||||||
|
return self.compilers[Languages.C].package.rpath_arg
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx_rpath_arg(self) -> str:
|
||||||
|
self._lang_exists_or_raise("cxx_rpath_arg", lang=Languages.CXX)
|
||||||
|
return self.compilers[Languages.CXX].package.rpath_arg
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fc_rpath_arg(self) -> str:
|
||||||
|
self._lang_exists_or_raise("fc_rpath_arg", lang=Languages.FORTRAN)
|
||||||
|
return self.compilers[Languages.FORTRAN].package.rpath_arg
|
||||||
|
|
||||||
|
@property
|
||||||
|
def f77_rpath_arg(self) -> str:
|
||||||
|
self._lang_exists_or_raise("f77_rpath_arg", lang=Languages.FORTRAN)
|
||||||
|
return self.compilers[Languages.FORTRAN].package.rpath_arg
|
||||||
|
|
||||||
|
@property
|
||||||
|
def linker_arg(self) -> str:
|
||||||
|
return self._maybe_return_attribute("linker_arg", lang=Languages.C)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return next(iter(self.compilers.values())).name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self):
|
||||||
|
return next(iter(self.compilers.values())).version
|
||||||
|
|
||||||
|
def implicit_rpaths(self) -> List[str]:
|
||||||
|
result, seen = [], set()
|
||||||
|
for compiler in self.compilers.values():
|
||||||
|
if compiler in seen:
|
||||||
|
continue
|
||||||
|
seen.add(compiler)
|
||||||
|
result.extend(CompilerPropertyDetector(compiler).implicit_rpaths())
|
||||||
|
return result
|
||||||
|
|
||||||
|
@property
|
||||||
|
def openmp_flag(self) -> str:
|
||||||
|
return next(iter(self.compilers.values())).package.openmp_flag
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx98_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.CXX].package.standard_flag(
|
||||||
|
language=Languages.CXX.value, standard="98"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx11_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.CXX].package.standard_flag(
|
||||||
|
language=Languages.CXX.value, standard="11"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx14_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.CXX].package.standard_flag(
|
||||||
|
language=Languages.CXX.value, standard="14"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx17_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.CXX].package.standard_flag(
|
||||||
|
language=Languages.CXX.value, standard="17"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx20_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.CXX].package.standard_flag(
|
||||||
|
language=Languages.CXX.value, standard="20"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx23_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.CXX].package.standard_flag(
|
||||||
|
language=Languages.CXX.value, standard="23"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def c99_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.C].package.standard_flag(
|
||||||
|
language=Languages.C.value, standard="99"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def c11_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.C].package.standard_flag(
|
||||||
|
language=Languages.C.value, standard="11"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def c17_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.C].package.standard_flag(
|
||||||
|
language=Languages.C.value, standard="17"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def c23_flag(self) -> str:
|
||||||
|
return self.compilers[Languages.C].package.standard_flag(
|
||||||
|
language=Languages.C.value, standard="17"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cc_pic_flag(self) -> str:
|
||||||
|
self._lang_exists_or_raise("cc_pic_flag", lang=Languages.C)
|
||||||
|
return self.compilers[Languages.C].package.pic_flag
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx_pic_flag(self) -> str:
|
||||||
|
self._lang_exists_or_raise("cxx_pic_flag", lang=Languages.CXX)
|
||||||
|
return self.compilers[Languages.CXX].package.pic_flag
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fc_pic_flag(self) -> str:
|
||||||
|
self._lang_exists_or_raise("fc_pic_flag", lang=Languages.FORTRAN)
|
||||||
|
return self.compilers[Languages.FORTRAN].package.pic_flag
|
||||||
|
|
||||||
|
@property
|
||||||
|
def f77_pic_flag(self) -> str:
|
||||||
|
self._lang_exists_or_raise("f77_pic_flag", lang=Languages.FORTRAN)
|
||||||
|
return self.compilers[Languages.FORTRAN].package.pic_flag
|
||||||
|
|
||||||
|
@property
|
||||||
|
def prefix(self) -> str:
|
||||||
|
return next(iter(self.compilers.values())).prefix
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extra_rpaths(self) -> List[str]:
|
||||||
|
compiler = next(iter(self.compilers.values()))
|
||||||
|
return getattr(compiler, "extra_attributes", {}).get("extra_rpaths", [])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cc(self):
|
||||||
|
return self._maybe_return_attribute("cc", lang=Languages.C)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cxx(self):
|
||||||
|
return self._maybe_return_attribute("cxx", lang=Languages.CXX)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fc(self):
|
||||||
|
self._lang_exists_or_raise("fc", lang=Languages.FORTRAN)
|
||||||
|
return self.compilers[Languages.FORTRAN].package.fortran
|
||||||
|
|
||||||
|
@property
|
||||||
|
def f77(self):
|
||||||
|
self._lang_exists_or_raise("f77", lang=Languages.FORTRAN)
|
||||||
|
return self.compilers[Languages.FORTRAN].package.fortran
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecatedCompiler(lang.DeprecatedProperty):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__(name="compiler")
|
||||||
|
|
||||||
|
def factory(self, instance, owner) -> CompilerAdaptor:
|
||||||
|
spec = instance.spec
|
||||||
|
if not spec.concrete:
|
||||||
|
raise ValueError("Can only get a compiler for a concrete package.")
|
||||||
|
|
||||||
|
compilers = {}
|
||||||
|
for language in Languages:
|
||||||
|
deps = spec.dependencies(virtuals=[language.value])
|
||||||
|
if deps:
|
||||||
|
compilers[language] = deps[0]
|
||||||
|
|
||||||
|
return CompilerAdaptor(instance, compilers)
|
@ -165,9 +165,7 @@ def __init__(
|
|||||||
item.target.safe_name(),
|
item.target.safe_name(),
|
||||||
" ".join(self._install_target(s.safe_name()) for s in item.prereqs),
|
" ".join(self._install_target(s.safe_name()) for s in item.prereqs),
|
||||||
item.target.spec_hash(),
|
item.target.spec_hash(),
|
||||||
item.target.unsafe_format(
|
item.target.unsafe_format("{name}{@version}{variants}{ arch=architecture}"),
|
||||||
"{name}{@version}{%compiler}{variants}{arch=architecture}"
|
|
||||||
),
|
|
||||||
item.buildcache_flag,
|
item.buildcache_flag,
|
||||||
)
|
)
|
||||||
for item in adjacency_list
|
for item in adjacency_list
|
||||||
|
@ -70,12 +70,16 @@ def _filter_compiler_wrappers_impl(pkg_or_builder):
|
|||||||
|
|
||||||
x = llnl.util.filesystem.FileFilter(*abs_files)
|
x = llnl.util.filesystem.FileFilter(*abs_files)
|
||||||
|
|
||||||
compiler_vars = [
|
compiler_vars = []
|
||||||
("CC", pkg.compiler.cc),
|
if "c" in pkg.spec:
|
||||||
("CXX", pkg.compiler.cxx),
|
compiler_vars.append(("CC", pkg.spec["c"].package.cc))
|
||||||
("F77", pkg.compiler.f77),
|
|
||||||
("FC", pkg.compiler.fc),
|
if "cxx" in pkg.spec:
|
||||||
]
|
compiler_vars.append(("CXX", pkg.spec["cxx"].package.cxx))
|
||||||
|
|
||||||
|
if "fortran" in pkg.spec:
|
||||||
|
compiler_vars.append(("FC", pkg.spec["fortran"].package.fortran))
|
||||||
|
compiler_vars.append(("F77", pkg.spec["fortran"].package.fortran))
|
||||||
|
|
||||||
# Some paths to the compiler wrappers might be substrings of the others.
|
# Some paths to the compiler wrappers might be substrings of the others.
|
||||||
# For example:
|
# For example:
|
||||||
@ -103,7 +107,11 @@ def _filter_compiler_wrappers_impl(pkg_or_builder):
|
|||||||
x.filter(wrapper_path, compiler_path, **filter_kwargs)
|
x.filter(wrapper_path, compiler_path, **filter_kwargs)
|
||||||
|
|
||||||
# Remove this linking flag if present (it turns RPATH into RUNPATH)
|
# Remove this linking flag if present (it turns RPATH into RUNPATH)
|
||||||
x.filter("{0}--enable-new-dtags".format(pkg.compiler.linker_arg), "", **filter_kwargs)
|
for compiler_lang in ("c", "cxx", "fortran"):
|
||||||
|
if compiler_lang not in pkg.spec:
|
||||||
|
continue
|
||||||
|
compiler_pkg = pkg.spec[compiler_lang].package
|
||||||
|
x.filter(f"{compiler_pkg.linker_arg}--enable-new-dtags", "", **filter_kwargs)
|
||||||
|
|
||||||
# NAG compiler is usually mixed with GCC, which has a different
|
# NAG compiler is usually mixed with GCC, which has a different
|
||||||
# prefix for linker arguments.
|
# prefix for linker arguments.
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
import spack.util.path
|
import spack.util.path
|
||||||
import spack.util.web
|
import spack.util.web
|
||||||
import spack.variant
|
import spack.variant
|
||||||
|
from spack.compilers.adaptor import DeprecatedCompiler
|
||||||
from spack.error import InstallError, NoURLError, PackageError
|
from spack.error import InstallError, NoURLError, PackageError
|
||||||
from spack.filesystem_view import YamlFilesystemView
|
from spack.filesystem_view import YamlFilesystemView
|
||||||
from spack.resource import Resource
|
from spack.resource import Resource
|
||||||
@ -67,10 +68,9 @@
|
|||||||
]
|
]
|
||||||
FLAG_HANDLER_TYPE = Callable[[str, Iterable[str]], FLAG_HANDLER_RETURN_TYPE]
|
FLAG_HANDLER_TYPE = Callable[[str, Iterable[str]], FLAG_HANDLER_RETURN_TYPE]
|
||||||
|
|
||||||
"""Allowed URL schemes for spack packages."""
|
#: Allowed URL schemes for spack packages
|
||||||
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
||||||
|
|
||||||
|
|
||||||
#: Filename for the Spack build/install log.
|
#: Filename for the Spack build/install log.
|
||||||
_spack_build_logfile = "spack-build-out.txt"
|
_spack_build_logfile = "spack-build-out.txt"
|
||||||
|
|
||||||
@ -592,6 +592,8 @@ class PackageBase(WindowsRPath, PackageViewMixin, metaclass=PackageMeta):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
compiler = DeprecatedCompiler()
|
||||||
|
|
||||||
#
|
#
|
||||||
# These are default values for instance variables.
|
# These are default values for instance variables.
|
||||||
#
|
#
|
||||||
@ -1489,14 +1491,6 @@ def prefix(self):
|
|||||||
def home(self):
|
def home(self):
|
||||||
return self.prefix
|
return self.prefix
|
||||||
|
|
||||||
@property # type: ignore[misc]
|
|
||||||
@memoized
|
|
||||||
def compiler(self):
|
|
||||||
"""Get the spack.compiler.Compiler object used to build this package"""
|
|
||||||
if not self.spec.concrete:
|
|
||||||
raise ValueError("Can only get a compiler for a concrete package.")
|
|
||||||
raise NotImplementedError("Wrapper to old API still to be implemented")
|
|
||||||
|
|
||||||
def url_version(self, version):
|
def url_version(self, version):
|
||||||
"""
|
"""
|
||||||
Given a version, this returns a string that should be substituted
|
Given a version, this returns a string that should be substituted
|
||||||
|
@ -175,15 +175,13 @@
|
|||||||
#: Default format for Spec.format(). This format can be round-tripped, so that:
|
#: Default format for Spec.format(). This format can be round-tripped, so that:
|
||||||
#: Spec(Spec("string").format()) == Spec("string)"
|
#: Spec(Spec("string").format()) == Spec("string)"
|
||||||
DEFAULT_FORMAT = (
|
DEFAULT_FORMAT = (
|
||||||
"{name}{@versions}"
|
"{name}{@versions}{compiler_flags}"
|
||||||
"{%compiler.name}{@compiler.versions}{compiler_flags}"
|
|
||||||
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
|
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
|
||||||
)
|
)
|
||||||
|
|
||||||
#: Display format, which eliminates extra `@=` in the output, for readability.
|
#: Display format, which eliminates extra `@=` in the output, for readability.
|
||||||
DISPLAY_FORMAT = (
|
DISPLAY_FORMAT = (
|
||||||
"{name}{@version}"
|
"{name}{@version}{compiler_flags}"
|
||||||
"{%compiler.name}{@compiler.version}{compiler_flags}"
|
|
||||||
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
|
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -620,10 +618,69 @@ def complete_with_defaults(self) -> None:
|
|||||||
self.target = default_architecture.target
|
self.target = default_architecture.target
|
||||||
|
|
||||||
|
|
||||||
# FIXME (compiler as nodes): remove this class
|
|
||||||
class CompilerSpec:
|
class CompilerSpec:
|
||||||
def __init__(self, *args):
|
"""Adaptor to the old compiler spec interface. Exposes just a few attributes"""
|
||||||
raise SystemExit("CompilerSpec is being removed")
|
|
||||||
|
def __init__(self, spec):
|
||||||
|
self.spec = spec
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.spec.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self):
|
||||||
|
return self.spec.version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def versions(self):
|
||||||
|
return self.spec.versions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_str(self):
|
||||||
|
"""Equivalent to {compiler.name}{@compiler.version} for Specs, without extra
|
||||||
|
@= for readability."""
|
||||||
|
if self.spec.concrete:
|
||||||
|
return f"{self.name}@{self.version}"
|
||||||
|
elif self.versions != vn.any_version:
|
||||||
|
return f"{self.name}@{self.versions}"
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
if not isinstance(other, CompilerSpec):
|
||||||
|
return self.spec < other
|
||||||
|
return self.spec < other.spec
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, CompilerSpec):
|
||||||
|
return self.spec == other
|
||||||
|
return self.spec == other.spec
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.spec)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.spec)
|
||||||
|
|
||||||
|
def _cmp_iter(self):
|
||||||
|
return self.spec._cmp_iter()
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
if self.spec == Spec():
|
||||||
|
return False
|
||||||
|
return bool(self.spec)
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecatedCompilerSpec(lang.DeprecatedProperty):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(name="compiler")
|
||||||
|
|
||||||
|
def factory(self, instance, owner):
|
||||||
|
for language in ("c", "cxx", "fortran"):
|
||||||
|
deps = instance.dependencies(virtuals=language)
|
||||||
|
if deps:
|
||||||
|
return CompilerSpec(deps[0])
|
||||||
|
return CompilerSpec(Spec())
|
||||||
|
|
||||||
|
|
||||||
@lang.lazy_lexicographic_ordering
|
@lang.lazy_lexicographic_ordering
|
||||||
@ -1342,7 +1399,7 @@ def tree(
|
|||||||
|
|
||||||
@lang.lazy_lexicographic_ordering(set_hash=False)
|
@lang.lazy_lexicographic_ordering(set_hash=False)
|
||||||
class Spec:
|
class Spec:
|
||||||
compiler = lang.Const(None)
|
compiler = DeprecatedCompilerSpec()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_arch():
|
def default_arch():
|
||||||
@ -1414,7 +1471,7 @@ def __init__(self, spec_like=None, *, external_path=None, external_modules=None)
|
|||||||
spack.spec_parser.parse_one_or_raise(spec_like, self)
|
spack.spec_parser.parse_one_or_raise(spec_like, self)
|
||||||
|
|
||||||
elif spec_like is not None:
|
elif spec_like is not None:
|
||||||
raise TypeError("Can't make spec out of %s" % type(spec_like))
|
raise TypeError(f"Can't make spec out of {type(spec_like)}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _format_module_list(modules):
|
def _format_module_list(modules):
|
||||||
@ -2150,10 +2207,6 @@ def to_node_dict(self, hash=ht.dag_hash):
|
|||||||
'platform_os': 'mojave',
|
'platform_os': 'mojave',
|
||||||
'target': 'x86_64',
|
'target': 'x86_64',
|
||||||
},
|
},
|
||||||
'compiler': {
|
|
||||||
'name': 'apple-clang',
|
|
||||||
'version': '10.0.0',
|
|
||||||
},
|
|
||||||
'namespace': 'builtin',
|
'namespace': 'builtin',
|
||||||
'parameters': {
|
'parameters': {
|
||||||
'fts': 'true',
|
'fts': 'true',
|
||||||
|
Loading…
Reference in New Issue
Block a user