Make Spec.compiler behavior stricter

Now the adaptor will raise if the Spec has no C, C++,
or Fortran compiler.
This commit is contained in:
Massimiliano Culpo 2024-11-17 14:23:20 +01:00
parent 875abbeb88
commit 013c4b8d3a
No known key found for this signature in database
GPG Key ID: 3E52BB992233066C
8 changed files with 27 additions and 34 deletions

View File

@ -73,7 +73,7 @@ def index_by(objects, *funcs):
if isinstance(f, str): if isinstance(f, str):
f = lambda x: getattr(x, funcs[0]) f = lambda x: getattr(x, funcs[0])
elif isinstance(f, tuple): elif isinstance(f, tuple):
f = lambda x: tuple(getattr(x, p) for p in funcs[0]) f = lambda x: tuple(getattr(x, p, None) for p in funcs[0])
result = {} result = {}
for o in objects: for o in objects:

View File

@ -2137,7 +2137,7 @@ def build_name(self):
Returns: (str) current spec's CDash build name.""" Returns: (str) current spec's CDash build name."""
spec = self.current_spec spec = self.current_spec
if spec: if spec:
build_name = f"{spec.name}@{spec.version}%{spec.compiler} \ build_name = f"{spec.name}@{spec.version} \
hash={spec.dag_hash()} arch={spec.architecture} ({self.build_group})" hash={spec.dag_hash()} arch={spec.architecture} ({self.build_group})"
tty.debug(f"Generated CDash build name ({build_name}) from the {spec.name}") tty.debug(f"Generated CDash build name ({build_name}) from the {spec.name}")
return build_name return build_name

View File

@ -369,8 +369,13 @@ def iter_groups(specs, indent, all_headers):
index = index_by(specs, ("architecture", "compiler")) index = index_by(specs, ("architecture", "compiler"))
ispace = indent * " " ispace = indent * " "
def _key(item):
if item is None:
return ""
return str(item)
# Traverse the index and print out each package # Traverse the index and print out each package
for i, (architecture, compiler) in enumerate(sorted(index)): for i, (architecture, compiler) in enumerate(sorted(index, key=_key)):
if i > 0: if i > 0:
print() print()
@ -443,7 +448,6 @@ def get_arg(name, default=None):
hashes = get_arg("long", False) hashes = get_arg("long", False)
namespaces = get_arg("namespaces", False) namespaces = get_arg("namespaces", False)
flags = get_arg("show_flags", False) flags = get_arg("show_flags", False)
full_compiler = get_arg("show_full_compiler", False)
variants = get_arg("variants", False) variants = get_arg("variants", False)
groups = get_arg("groups", True) groups = get_arg("groups", True)
all_headers = get_arg("all_headers", False) all_headers = get_arg("all_headers", False)
@ -465,10 +469,7 @@ def get_arg(name, default=None):
if format_string is None: if format_string is None:
nfmt = "{fullname}" if namespaces else "{name}" nfmt = "{fullname}" if namespaces else "{name}"
ffmt = "" ffmt = ""
if full_compiler or flags: if flags:
ffmt += "{%compiler.name}"
if full_compiler:
ffmt += "{@compiler.version}"
ffmt += " {compiler_flags}" ffmt += " {compiler_flags}"
vfmt = "{variants}" if variants else "" vfmt = "{variants}" if variants else ""
format_string = nfmt + "{@version}" + ffmt + vfmt format_string = nfmt + "{@version}" + ffmt + vfmt

View File

@ -518,8 +518,6 @@ def config_prefer_upstream(args):
for spec in pref_specs: for spec in pref_specs:
# Collect all the upstream compilers and versions for this package. # Collect all the upstream compilers and versions for this package.
pkg = pkgs.get(spec.name, {"version": []}) pkg = pkgs.get(spec.name, {"version": []})
all = pkgs.get("all", {"compiler": []})
pkgs["all"] = all
pkgs[spec.name] = pkg pkgs[spec.name] = pkg
# We have no existing variant if this is our first added version. # We have no existing variant if this is our first added version.
@ -529,10 +527,6 @@ def config_prefer_upstream(args):
if version not in pkg["version"]: if version not in pkg["version"]:
pkg["version"].append(version) pkg["version"].append(version)
compiler = str(spec.compiler)
if compiler not in all["compiler"]:
all["compiler"].append(compiler)
# Get and list all the variants that differ from the default. # Get and list all the variants that differ from the default.
variants = [] variants = []
for var_name, variant in spec.variants.items(): for var_name, variant in spec.variants.items():

View File

@ -99,7 +99,7 @@ def setup_parser(subparser):
"--show-full-compiler", "--show-full-compiler",
action="store_true", action="store_true",
dest="show_full_compiler", dest="show_full_compiler",
help="(DEPRECATED) show full compiler specs", help="(DEPRECATED) show full compiler specs. Currently it's a no-op",
) )
implicit_explicit = subparser.add_mutually_exclusive_group() implicit_explicit = subparser.add_mutually_exclusive_group()
implicit_explicit.add_argument( implicit_explicit.add_argument(
@ -279,7 +279,6 @@ def root_decorator(spec, string):
# these enforce details in the root specs to show what the user asked for # these enforce details in the root specs to show what the user asked for
namespaces=True, namespaces=True,
show_flags=True, show_flags=True,
show_full_compiler=True,
decorator=root_decorator, decorator=root_decorator,
variants=True, variants=True,
) )
@ -302,7 +301,6 @@ def root_decorator(spec, string):
decorator=lambda s, f: color.colorize("@*{%s}" % f), decorator=lambda s, f: color.colorize("@*{%s}" % f),
namespace=True, namespace=True,
show_flags=True, show_flags=True,
show_full_compiler=True,
variants=True, variants=True,
) )
print() print()

View File

@ -32,7 +32,6 @@
from llnl.util.lang import classproperty, memoized from llnl.util.lang import classproperty, memoized
from llnl.util.link_tree import LinkTree from llnl.util.link_tree import LinkTree
import spack.compilers.config
import spack.config import spack.config
import spack.dependency import spack.dependency
import spack.deptypes as dt import spack.deptypes as dt
@ -1937,17 +1936,14 @@ def _resource_stage(self, resource):
return resource_stage_folder return resource_stage_folder
def do_test(self, dirty=False, externals=False): def do_test(self, dirty=False, externals=False):
if self.test_requires_compiler: if self.test_requires_compiler and not any(
compilers = spack.compilers.config.compilers_for_spec( lang in self.spec for lang in ("c", "cxx", "fortran")
self.spec.compiler, arch_spec=self.spec.architecture ):
tty.error(
f"Skipping tests for package {self.spec}, since a compiler is required, "
f"but not available"
) )
if not compilers: return
tty.error(
"Skipping tests for package %s\n"
% self.spec.format("{name}-{version}-{hash:7}")
+ "Package test requires missing compiler %s" % self.spec.compiler
)
return
kwargs = { kwargs = {
"dirty": dirty, "dirty": dirty,

View File

@ -78,7 +78,6 @@ def __enter__(self):
"packages": [], "packages": [],
} }
spec_record["properties"].append(Property("architecture", input_spec.architecture)) spec_record["properties"].append(Property("architecture", input_spec.architecture))
spec_record["properties"].append(Property("compiler", input_spec.compiler))
self.init_spec_record(input_spec, spec_record) self.init_spec_record(input_spec, spec_record)
self.specs.append(spec_record) self.specs.append(spec_record)

View File

@ -82,6 +82,7 @@
import spack.provider_index import spack.provider_index
import spack.repo import spack.repo
import spack.solver import spack.solver
import spack.spec
import spack.store import spack.store
import spack.traverse as traverse import spack.traverse as traverse
import spack.util.executable import spack.util.executable
@ -594,7 +595,7 @@ def __contains__(self, string):
return string in str(self) or string in self.target return string in str(self) or string in self.target
def complete_with_defaults(self) -> None: def complete_with_defaults(self) -> None:
default_architecture = spack.spec.ArchSpec.default_arch() default_architecture = ArchSpec.default_arch()
if not self.platform: if not self.platform:
self.platform = default_architecture.platform self.platform = default_architecture.platform
@ -667,7 +668,8 @@ def factory(self, instance, owner):
deps = instance.dependencies(virtuals=language) deps = instance.dependencies(virtuals=language)
if deps: if deps:
return CompilerSpec(deps[0]) return CompilerSpec(deps[0])
return CompilerSpec(Spec())
raise AttributeError(f"{instance} has no C, C++, or Fortran compiler")
@lang.lazy_lexicographic_ordering @lang.lazy_lexicographic_ordering
@ -1386,13 +1388,13 @@ def tree(
class SpecAnnotations: class SpecAnnotations:
def __init__(self) -> None: def __init__(self) -> None:
self.original_spec_format = SPECFILE_FORMAT_VERSION self.original_spec_format = SPECFILE_FORMAT_VERSION
self.compiler_node_attribute: Optional["spack.spec.Spec"] = None self.compiler_node_attribute: Optional["Spec"] = None
def with_spec_format(self, spec_format: int) -> "SpecAnnotations": def with_spec_format(self, spec_format: int) -> "SpecAnnotations":
self.original_spec_format = spec_format self.original_spec_format = spec_format
return self return self
def with_compiler(self, compiler: "spack.spec.Spec") -> "SpecAnnotations": def with_compiler(self, compiler: "Spec") -> "SpecAnnotations":
self.compiler_node_attribute = compiler self.compiler_node_attribute = compiler
return self return self
@ -2945,7 +2947,7 @@ def _finalize_concretization(self):
for spec in self.traverse(): for spec in self.traverse():
spec._cached_hash(ht.dag_hash) spec._cached_hash(ht.dag_hash)
def concretized(self, tests: Union[bool, Iterable[str]] = False) -> "spack.spec.Spec": def concretized(self, tests: Union[bool, Iterable[str]] = False) -> "Spec":
"""This is a non-destructive version of concretize(). """This is a non-destructive version of concretize().
First clones, then returns a concrete version of this package First clones, then returns a concrete version of this package
@ -3952,6 +3954,9 @@ def format_attribute(match_object: Match) -> str:
try: try:
current = getattr(current, part) current = getattr(current, part)
except AttributeError: except AttributeError:
if part == "compiler":
return "none"
raise SpecFormatStringError( raise SpecFormatStringError(
f"Attempted to format attribute {attribute}. " f"Attempted to format attribute {attribute}. "
f"Spec {'.'.join(parts[:idx])} has no attribute {part}" f"Spec {'.'.join(parts[:idx])} has no attribute {part}"