diff --git a/src/mpsd_software_manager/spack.py b/src/mpsd_software_manager/spack.py index d011a0b22df8d387bc0b9ca96302aa9f6dc22379..bf3f81367fe8dc89e9d17c5bf58b3f885a02fc3a 100644 --- a/src/mpsd_software_manager/spack.py +++ b/src/mpsd_software_manager/spack.py @@ -323,17 +323,37 @@ def refresh_modules(compilers: dict[str, Any] | None = None) -> None: ) gcc_module = compilers["fallback"]["package"].split("%")[0].replace("@", "/") module_file = Config().lmod_root / "Core" / intel_module - logger.debug( - "Updating family(...) in '%s' (make '%s' depend on '%s')", - module_file, - intel_module, - gcc_module, - ) - with module_file.open() as f: - content = f.read() - content = content.replace('family("compiler")', 'family("intel_compiler")') - # insert gcc as dependency before other dependencies and before modifying - # MODULE_PATH + CLASSIC_FAMILY = "intel_classic_compiler" + ONEAPI_FAMILY = "intel_oneapi_compiler" + family = CLASSIC_FAMILY if "classic" in intel_module else ONEAPI_FAMILY + patch_intel_module(module_file, gcc_module, family) + if family == "intel_classic_compiler": + # We need to also patch the intel module, which is loaded as a dependency of + # the intel classic module. We read the module name from the intel classic + # module file. + classic_content = module_file.read_text() + match = re.search( + r'depends_on\("(intel-oneapi-compilers/[0-9.]+)"\)', classic_content + ) + # match.group(1) will fail should we not find the line (should never happen) + oneapi_module = match.group(1) + ".lua" + oneapi_module_file = Config().lmod_root / "Core" / oneapi_module + patch_intel_module(oneapi_module_file, gcc_module, ONEAPI_FAMILY) + + +def patch_intel_module(module_file: Path, gcc_module: str, family: str) -> None: + """Make intel modules depend on gcc and change family.""" + logger.debug( + "Updating family(...) in '%s' and make it depend on '%s'", + module_file, + gcc_module, + ) + content = module_file.read_text() + content = content.replace('family("compiler")', f'family("{family}")') + # Insert gcc as dependency before other dependencies and before modifying + # MODULE_PATH. + # This function can be called multiple times, so only insert if not yet present. + if f'depends_on("{gcc_module}")\n' not in content: insertion_point = min( content.find("depends_on("), content.find('prepend_path("MODULEPATH"') ) @@ -342,8 +362,7 @@ def refresh_modules(compilers: dict[str, Any] | None = None) -> None: + f'depends_on("{gcc_module}")\n' + content[insertion_point:] ) - with module_file.open("w") as f: - f.write(content) + module_file.write_text(content) def install_package_set_from_environment(spack_environment: str) -> None: