gcc/oneapi: inject runtime iff language virtual (#49956)

Currently we inject runtimes when a package has a direct build dep on a
compiler, but what matters is whether the package depends on a language.

That way we can avoid recursion of injecting runtimes to runtimes
without a rule in the solver: runtimes don't depend on languages, they
just have a build dep on the same compiler.
This commit is contained in:
Harmen Stoppels 2025-04-08 19:51:16 +02:00 committed by GitHub
parent 4372907fc1
commit 8ffd6c29bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 73 deletions

View File

@ -3201,12 +3201,13 @@ def define_runtime_constraints(self) -> List[spack.spec.Spec]:
# FIXME (compiler as nodes): think of using isinstance(compiler_cls, WrappedCompiler)
# Add a dependency on the compiler wrapper
recorder("*").depends_on(
"compiler-wrapper",
when=f"%{compiler.name}@{compiler.versions}",
type="build",
description=f"Add the compiler wrapper when using {compiler}",
)
for language in ("c", "cxx", "fortran"):
recorder("*").depends_on(
"compiler-wrapper",
when=f"%[virtuals={language}] {compiler.name}@{compiler.versions}",
type="build",
description=f"Add the compiler wrapper when using {compiler} for {language}",
)
if not using_libc_compatibility():
continue
@ -3601,11 +3602,9 @@ def rule_body_from(self, when_spec: "spack.spec.Spec") -> Tuple[str, str]:
# (avoid adding virtuals everywhere, if a single edge needs it)
_, provider, virtual = clause.args
clause.args = "virtual_on_edge", node_placeholder, provider, virtual
body_str = (
f" {f',{os.linesep} '.join(str(x) for x in body_clauses)},\n"
f" not external({node_variable}),\n"
f" not runtime(Package)"
).replace(f'"{node_placeholder}"', f"{node_variable}")
body_str = ",\n".join(f" {x}" for x in body_clauses)
body_str += f",\n not external({node_variable})"
body_str = body_str.replace(f'"{node_placeholder}"', f"{node_variable}")
for old, replacement in when_substitutions.items():
body_str = body_str.replace(old, replacement)
return body_str, node_variable

View File

@ -81,19 +81,13 @@ def runtime_constraints(cls, *, spec, pkg):
spec: spec that will inject runtime dependencies
pkg: object used to forward information to the solver
"""
pkg("*").depends_on(
"gcc-runtime",
when="%gcc",
type="link",
description="If any package uses %gcc, it depends on gcc-runtime",
)
pkg("*").depends_on(
f"gcc-runtime@{str(spec.version)}:",
when=f"^[deptypes=build] {spec.name}@{spec.versions}",
type="link",
description=f"If any package uses %{str(spec)}, "
f"it depends on gcc-runtime@{str(spec.version)}:",
)
for language in ("c", "cxx", "fortran"):
pkg("*").depends_on(
f"gcc-runtime@{spec.version}:",
when=f"%[virtuals={language}] {spec.name}@{spec.versions}",
type="link",
description=f"Inject gcc-runtime when gcc is used as a {language} compiler",
)
gfortran_str = "libgfortran@5"
if spec.satisfies("gcc@:6"):
@ -104,18 +98,14 @@ def runtime_constraints(cls, *, spec, pkg):
for fortran_virtual in ("fortran-rt", gfortran_str):
pkg("*").depends_on(
fortran_virtual,
when=f"^[virtuals=fortran deptypes=build] {spec.name}@{spec.versions}",
when=f"%[virtuals=fortran] {spec.name}@{spec.versions}",
type="link",
description=f"Add a dependency on '{gfortran_str}' for nodes compiled with "
f"{str(spec)} and using the 'fortran' language",
f"{spec} and using the 'fortran' language",
)
# The version of gcc-runtime is the same as the %gcc used to "compile" it
pkg("gcc-runtime").requires(
f"@{str(spec.versions)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}"
)
pkg("gcc-runtime").requires(f"@{spec.versions}", when=f"%{spec.name}@{spec.versions}")
# If a node used %gcc@X.Y its dependencies must use gcc-runtime@:X.Y
# (technically @:X is broader than ... <= @=X but this should work in practice)
pkg("*").propagate(
f"gcc@:{str(spec.version)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}"
)
pkg("*").propagate(f"gcc@:{spec.version}", when=f"%{spec.name}@{spec.versions}")

View File

@ -1158,19 +1158,13 @@ def runtime_constraints(cls, *, spec, pkg):
spec: spec that will inject runtime dependencies
pkg: object used to forward information to the solver
"""
pkg("*").depends_on(
"gcc-runtime",
when="%gcc",
type="link",
description="If any package uses %gcc, it depends on gcc-runtime",
)
pkg("*").depends_on(
f"gcc-runtime@{str(spec.version)}:",
when=f"^[deptypes=build] {spec.name}@{spec.versions}",
type="link",
description=f"If any package uses %{str(spec)}, "
f"it depends on gcc-runtime@{str(spec.version)}:",
)
for language in ("c", "cxx", "fortran"):
pkg("*").depends_on(
f"gcc-runtime@{spec.version}:",
when=f"%[virtuals={language}] {spec.name}@{spec.versions}",
type="link",
description=f"Inject gcc-runtime when gcc is used as a {language} compiler",
)
gfortran_str = "libgfortran@5"
if spec.satisfies("gcc@:6"):
@ -1181,21 +1175,17 @@ def runtime_constraints(cls, *, spec, pkg):
for fortran_virtual in ("fortran-rt", gfortran_str):
pkg("*").depends_on(
fortran_virtual,
when=f"^[virtuals=fortran deptypes=build] {spec.name}@{spec.versions}",
when=f"%[virtuals=fortran] {spec.name}@{spec.versions}",
type="link",
description=f"Add a dependency on '{gfortran_str}' for nodes compiled with "
f"{str(spec)} and using the 'fortran' language",
f"{spec} and using the 'fortran' language",
)
# The version of gcc-runtime is the same as the %gcc used to "compile" it
pkg("gcc-runtime").requires(
f"@{str(spec.versions)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}"
)
pkg("gcc-runtime").requires(f"@{spec.versions}", when=f"%{spec.name}@{spec.versions}")
# If a node used %gcc@X.Y its dependencies must use gcc-runtime@:X.Y
# (technically @:X is broader than ... <= @=X but this should work in practice)
pkg("*").propagate(
f"gcc@:{str(spec.version)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}"
)
pkg("*").propagate(f"gcc@:{spec.version}", when=f"%{spec.name}@{spec.versions}")
def _post_buildcache_install_hook(self):
if not self.spec.satisfies("platform=linux"):

View File

@ -655,38 +655,32 @@ def determine_variants(cls, exes, version_str):
@classmethod
def runtime_constraints(cls, *, spec, pkg):
pkg("*").depends_on(
"intel-oneapi-runtime",
when="%oneapi",
type="link",
description="If any package uses %oneapi, it depends on intel-oneapi-runtime",
)
pkg("*").depends_on(
f"intel-oneapi-runtime@{str(spec.version)}:",
when=f"^[deptypes=build] {spec.name}@{spec.versions}",
type="link",
description=f"If any package uses %{str(spec)}, "
f"it depends on intel-oneapi-runtime@{str(spec.version)}:",
)
for language in ("c", "cxx", "fortran"):
pkg("*").depends_on(
f"intel-oneapi-runtime@{spec.version}:",
when=f"%[virtuals={language}] {spec.name}@{spec.versions}",
type="link",
description="Inject intel-oneapi-runtime when oneapi is used as "
f"a {language} compiler",
)
for fortran_virtual in ("fortran-rt", "libifcore@5"):
pkg("*").depends_on(
fortran_virtual,
when=f"^[virtuals=fortran deptypes=build] {spec.name}@{spec.versions}",
when=f"%[virtuals=fortran] {spec.name}@{spec.versions}",
type="link",
description=f"Add a dependency on 'libifcore' for nodes compiled with "
f"{str(spec)} and using the 'fortran' language",
description="Add a dependency on 'libifcore' for nodes compiled with "
f"{spec.name}@{spec.versions} and using the 'fortran' language",
)
# The version of intel-oneapi-runtime is the same as the %oneapi used to "compile" it
pkg("intel-oneapi-runtime").requires(
f"@{str(spec.versions)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}"
f"@{spec.versions}", when=f"%{spec.name}@{spec.versions}"
)
# If a node used %intel-oneapi=runtime@X.Y its dependencies must use @:X.Y
# If a node used %intel-oneapi-runtime@X.Y its dependencies must use @:X.Y
# (technically @:X is broader than ... <= @=X but this should work in practice)
pkg("*").propagate(
f"intel-oneapi-compilers@:{str(spec.version)}",
when=f"^[deptypes=build] {spec.name}@{spec.versions}",
f"intel-oneapi-compilers@:{spec.version}", when=f"%{spec.name}@{spec.versions}"
)
def _cc_path(self):