Write adaptors for CompilerSpec and Compiler

Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
Massimiliano Culpo 2024-10-16 19:08:25 +02:00
parent cdc8236169
commit 9ca0bd5d97
No known key found for this signature in database
GPG Key ID: 3E52BB992233066C
6 changed files with 302 additions and 33 deletions

View File

@ -10,6 +10,7 @@
import llnl.util.tty as tty
import spack.phase_callbacks
from spack.directives import depends_on
from .cmake import CMakeBuilder, CMakePackage
@ -357,6 +358,10 @@ class CachedCMakePackage(CMakePackage):
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):
if name in ("cflags", "cxxflags", "cppflags", "fflags"):
return None, None, None # handled in the cmake cache

View 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)

View File

@ -165,9 +165,7 @@ def __init__(
item.target.safe_name(),
" ".join(self._install_target(s.safe_name()) for s in item.prereqs),
item.target.spec_hash(),
item.target.unsafe_format(
"{name}{@version}{%compiler}{variants}{arch=architecture}"
),
item.target.unsafe_format("{name}{@version}{variants}{ arch=architecture}"),
item.buildcache_flag,
)
for item in adjacency_list

View File

@ -70,12 +70,16 @@ def _filter_compiler_wrappers_impl(pkg_or_builder):
x = llnl.util.filesystem.FileFilter(*abs_files)
compiler_vars = [
("CC", pkg.compiler.cc),
("CXX", pkg.compiler.cxx),
("F77", pkg.compiler.f77),
("FC", pkg.compiler.fc),
]
compiler_vars = []
if "c" in pkg.spec:
compiler_vars.append(("CC", pkg.spec["c"].package.cc))
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.
# For example:
@ -103,7 +107,11 @@ def _filter_compiler_wrappers_impl(pkg_or_builder):
x.filter(wrapper_path, compiler_path, **filter_kwargs)
# 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
# prefix for linker arguments.

View File

@ -53,6 +53,7 @@
import spack.util.path
import spack.util.web
import spack.variant
from spack.compilers.adaptor import DeprecatedCompiler
from spack.error import InstallError, NoURLError, PackageError
from spack.filesystem_view import YamlFilesystemView
from spack.resource import Resource
@ -67,10 +68,9 @@
]
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"]
#: Filename for the Spack build/install log.
_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.
#
@ -1489,14 +1491,6 @@ def prefix(self):
def home(self):
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):
"""
Given a version, this returns a string that should be substituted

View File

@ -175,15 +175,13 @@
#: Default format for Spec.format(). This format can be round-tripped, so that:
#: Spec(Spec("string").format()) == Spec("string)"
DEFAULT_FORMAT = (
"{name}{@versions}"
"{%compiler.name}{@compiler.versions}{compiler_flags}"
"{name}{@versions}{compiler_flags}"
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
)
#: Display format, which eliminates extra `@=` in the output, for readability.
DISPLAY_FORMAT = (
"{name}{@version}"
"{%compiler.name}{@compiler.version}{compiler_flags}"
"{name}{@version}{compiler_flags}"
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
)
@ -620,10 +618,69 @@ def complete_with_defaults(self) -> None:
self.target = default_architecture.target
# FIXME (compiler as nodes): remove this class
class CompilerSpec:
def __init__(self, *args):
raise SystemExit("CompilerSpec is being removed")
"""Adaptor to the old compiler spec interface. Exposes just a few attributes"""
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
@ -1342,7 +1399,7 @@ def tree(
@lang.lazy_lexicographic_ordering(set_hash=False)
class Spec:
compiler = lang.Const(None)
compiler = DeprecatedCompilerSpec()
@staticmethod
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)
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
def _format_module_list(modules):
@ -2150,10 +2207,6 @@ def to_node_dict(self, hash=ht.dag_hash):
'platform_os': 'mojave',
'target': 'x86_64',
},
'compiler': {
'name': 'apple-clang',
'version': '10.0.0',
},
'namespace': 'builtin',
'parameters': {
'fts': 'true',