(WIP) Fix LMod module generation

Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
Massimiliano Culpo 2024-10-12 00:16:25 +02:00
parent 6674ce6dc4
commit a1866d7a4b
No known key found for this signature in database
GPG Key ID: 3E52BB992233066C

View File

@ -5,6 +5,7 @@
import collections import collections
import itertools import itertools
import os import os
import pathlib
from typing import Dict, List, Optional, Tuple from typing import Dict, List, Optional, Tuple
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
@ -58,7 +59,7 @@ def make_context(
return LmodContext(make_configuration(spec, module_set_name, explicit)) return LmodContext(make_configuration(spec, module_set_name, explicit))
def guess_core_compilers(name, store=False) -> List[spack.spec.CompilerSpec]: def guess_core_compilers(name, store=False) -> List[spack.spec.Spec]:
"""Guesses the list of core compilers installed in the system. """Guesses the list of core compilers installed in the system.
Args: Args:
@ -71,14 +72,10 @@ def guess_core_compilers(name, store=False) -> List[spack.spec.CompilerSpec]:
core_compilers = [] core_compilers = []
for compiler in spack.compilers.config.all_compilers(): for compiler in spack.compilers.config.all_compilers():
try: try:
# A compiler is considered to be a core compiler if any of the cc_dir = pathlib.Path(compiler.package.cc).parent
# C, C++ or Fortran compilers reside in a system directory is_system_compiler = str(cc_dir) in spack.util.environment.SYSTEM_DIRS
is_system_compiler = any(
os.path.dirname(getattr(compiler, x, "")) in spack.util.environment.SYSTEM_DIRS
for x in ("cc", "cxx", "f77", "fc")
)
if is_system_compiler: if is_system_compiler:
core_compilers.append(compiler.spec) core_compilers.append(compiler)
except (KeyError, TypeError, AttributeError): except (KeyError, TypeError, AttributeError):
continue continue
@ -100,18 +97,32 @@ class LmodConfiguration(BaseConfiguration):
default_projections = {"all": "{name}/{version}"} default_projections = {"all": "{name}/{version}"}
def __init__(self, spec: spack.spec.Spec, module_set_name: str, explicit: bool) -> None:
super().__init__(spec, module_set_name, explicit)
# FIXME (compiler as nodes): make this a bit more robust
candidates = collections.defaultdict(list)
for node in spec.traverse(deptype=("link", "run")):
candidates["c"].extend(node.dependencies(virtuals="c"))
candidates["cxx"].extend(node.dependencies(virtuals="c"))
# FIXME (compiler as nodes): decide what to do when we have more than one C compiler
if candidates["c"] and len(set(candidates["c"])) == 1:
self.compiler = candidates["c"][0]
elif not candidates["c"]:
self.compiler = None
@property @property
def core_compilers(self) -> List[spack.spec.CompilerSpec]: def core_compilers(self) -> List[spack.spec.Spec]:
"""Returns the list of "Core" compilers """Returns the list of "Core" compilers
Raises: Raises:
CoreCompilersNotFoundError: if the key was not CoreCompilersNotFoundError: if the key was not specified in the configuration file or
specified in the configuration file or the sequence the sequence is empty
is empty
""" """
compilers = [ compilers = []
spack.spec.CompilerSpec(c) for c in configuration(self.name).get("core_compilers", []) for c in configuration(self.name).get("core_compilers", []):
] compilers.extend(spack.spec.Spec(f"%{c}").dependencies())
if not compilers: if not compilers:
compilers = guess_core_compilers(self.name, store=True) compilers = guess_core_compilers(self.name, store=True)
@ -160,12 +171,15 @@ def hierarchy_tokens(self):
@property @property
@lang.memoized @lang.memoized
def requires(self): def requires(self):
"""Returns a dictionary mapping all the requirements of this spec """Returns a dictionary mapping all the requirements of this spec to the actual provider.
to the actual provider. 'compiler' is always present among the
requirements. The 'compiler' key is always present among the requirements.
""" """
# If it's a core_spec, lie and say it requires a core compiler # If it's a core_spec, lie and say it requires a core compiler
if any(self.spec.satisfies(core_spec) for core_spec in self.core_specs): if (
any(self.spec.satisfies(core_spec) for core_spec in self.core_specs)
or self.compiler is None
):
return {"compiler": self.core_compilers[0]} return {"compiler": self.core_compilers[0]}
hierarchy_filter_list = [] hierarchy_filter_list = []
@ -176,7 +190,8 @@ def requires(self):
# Keep track of the requirements that this package has in terms # Keep track of the requirements that this package has in terms
# of virtual packages that participate in the hierarchical structure # of virtual packages that participate in the hierarchical structure
requirements = {"compiler": self.spec.compiler}
requirements = {"compiler": self.compiler}
# For each virtual dependency in the hierarchy # For each virtual dependency in the hierarchy
for x in self.hierarchy_tokens: for x in self.hierarchy_tokens:
# Skip anything filtered for this spec # Skip anything filtered for this spec
@ -200,11 +215,11 @@ def provides(self):
# If it is in the list of supported compilers family -> compiler # If it is in the list of supported compilers family -> compiler
if self.spec.name in spack.compilers.config.supported_compilers(): if self.spec.name in spack.compilers.config.supported_compilers():
provides["compiler"] = spack.spec.CompilerSpec(self.spec.format("{name}{@versions}")) provides["compiler"] = spack.spec.Spec(self.spec.format("{name}{@versions}"))
elif self.spec.name in spack.compilers.config.package_name_to_compiler_name: elif self.spec.name in spack.compilers.config.package_name_to_compiler_name:
# If it is the package for a supported compiler, but of a different name # If it is the package for a supported compiler, but of a different name
cname = spack.compilers.config.package_name_to_compiler_name[self.spec.name] cname = spack.compilers.config.package_name_to_compiler_name[self.spec.name]
provides["compiler"] = spack.spec.CompilerSpec(cname, self.spec.versions) provides["compiler"] = spack.spec.Spec(cname, self.spec.versions)
# All the other tokens in the hierarchy must be virtual dependencies # All the other tokens in the hierarchy must be virtual dependencies
for x in self.hierarchy_tokens: for x in self.hierarchy_tokens:
@ -300,12 +315,10 @@ def path_part_fmt(token):
# If we are dealing with a core compiler, return 'Core' # If we are dealing with a core compiler, return 'Core'
core_compilers = self.conf.core_compilers core_compilers = self.conf.core_compilers
if name == "compiler" and any( if name == "compiler" and any(spack.spec.Spec(value).satisfies(c) for c in core_compilers):
spack.spec.CompilerSpec(value).satisfies(c) for c in core_compilers
):
return "Core" return "Core"
# CompilerSpec does not have a hash, as we are not allowed to # Spec does not have a hash, as we are not allowed to
# use different flavors of the same compiler # use different flavors of the same compiler
if name == "compiler": if name == "compiler":
return path_part_fmt(token=value) return path_part_fmt(token=value)