Skip to content

Commit a4662b3

Browse files
authored
Merge branch 'EESSI:main' into mpi_injection
2 parents 02db9c1 + 93ed6c6 commit a4662b3

File tree

2 files changed

+208
-54
lines changed

2 files changed

+208
-54
lines changed

eb_hooks.py

Lines changed: 177 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
HOST_INJECTIONS_LOCATION = "/cvmfs/software.eessi.io/host_injections/"
5151

5252
# Make sure a single environment variable name is used for this throughout the hooks
53+
EESSI_IGNORE_A64FX_RUST1650_ENVVAR="EESSI_IGNORE_LMOD_ERROR_A64FX_RUST1650"
5354
EESSI_IGNORE_ZEN4_GCC1220_ENVVAR="EESSI_IGNORE_LMOD_ERROR_ZEN4_GCC1220"
5455

5556
STACK_REPROD_SUBDIR = 'reprod'
@@ -67,6 +68,21 @@
6768
}
6869

6970

71+
# Ensure that we don't print any messages in --terse mode
72+
# Note that --terse was introduced in EB 4.9.1
73+
orig_print_msg = print_msg
74+
orig_print_warning = print_warning
75+
76+
def print_msg(*args, **kwargs):
77+
if EASYBUILD_VERSION < '4.9.1' or not build_option('terse'):
78+
orig_print_msg(*args, **kwargs)
79+
80+
81+
def print_warning(*args, **kwargs):
82+
if EASYBUILD_VERSION < '4.9.1' or not build_option('terse'):
83+
orig_print_warning(*args, **kwargs)
84+
85+
7086
def is_gcccore_1220_based(**kwargs):
7187
# ecname, ecversion, tcname, tcversion):
7288
"""
@@ -140,6 +156,9 @@ def parse_hook(ec, *args, **kwargs):
140156
if cpu_target == CPU_TARGET_ZEN4:
141157
parse_hook_zen4_module_only(ec, eprefix)
142158

159+
# All A64FX builds for the 2022b toolchain should use a newer Rust version, as the original one does not work
160+
parse_hook_bump_rust_version_in_2022b_for_a64fx(ec, eprefix)
161+
143162
# inject the GPU property (if required)
144163
ec = inject_gpu_property(ec)
145164

@@ -174,7 +193,10 @@ def verify_toolchains_supported_by_eessi_version(easyconfigs):
174193
site_top_level_toolchains_envvar = 'EESSI_SITE_TOP_LEVEL_TOOLCHAINS_' + eessi_version.replace('.', '_')
175194
site_top_level_toolchains = parse_list_of_dicts_env(site_top_level_toolchains_envvar)
176195
for top_level_toolchain in EESSI_SUPPORTED_TOP_LEVEL_TOOLCHAINS[eessi_version] + site_top_level_toolchains:
177-
supported_eessi_toolchains += get_toolchain_hierarchy(top_level_toolchain)
196+
try:
197+
supported_eessi_toolchains += get_toolchain_hierarchy(top_level_toolchain)
198+
except EasyBuildError as error:
199+
print_msg(f"No toolchain hierarchy found for {top_level_toolchain}, ignoring! ({error})")
178200
for ec in easyconfigs:
179201
toolchain = ec['ec']['toolchain']
180202
# if it is a system toolchain or appears in the list, we are all good
@@ -431,6 +453,33 @@ def parse_hook_openblas_relax_lapack_tests_num_errors(ec, eprefix):
431453
raise EasyBuildError("OpenBLAS-specific hook triggered for non-OpenBLAS easyconfig?!")
432454

433455

456+
def parse_hook_bump_rust_version_in_2022b_for_a64fx(ec, eprefix):
457+
"""
458+
Replace Rust 1.65.0 build dependency by version 1.75.0 for A64FX builds,
459+
because version 1.65.0 has build issues.
460+
"""
461+
cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR')
462+
463+
if cpu_target == CPU_TARGET_A64FX:
464+
# For Rust 1.65.0 itself we inject an error message in the module file
465+
if ec['name'] == 'Rust' and ec['version'] == '1.65.0':
466+
errmsg = "Rust 1.65.0 is not supported on A64FX. Please use version 1.75.0 instead."
467+
ec['modluafooter'] = 'if (not os.getenv("%s")) then LmodError("%s") end' % (EESSI_IGNORE_A64FX_RUST1650_ENVVAR, errmsg)
468+
469+
# For any builds that have a build dependency on Rust 1.65.0, we bump the version to 1.75.0
470+
if is_gcccore_1220_based(ecname=ec['name'], ecversion=ec['version'],
471+
tcname=ec['toolchain']['name'], tcversion=ec['toolchain']['version']):
472+
473+
build_deps = ec['builddependencies']
474+
rust_name = 'Rust'
475+
rust_original_version = '1.65.0'
476+
rust_new_version = '1.75.0'
477+
for idx, build_dep in enumerate(build_deps):
478+
if build_dep[0] == rust_name and build_dep[1] == rust_original_version:
479+
build_deps[idx] = (rust_name, rust_new_version)
480+
break
481+
482+
434483
def parse_hook_pybind11_replace_catch2(ec, eprefix):
435484
"""
436485
Replace Catch2 build dependency in pybind11 easyconfigs with one that doesn't use system toolchain.
@@ -513,9 +562,7 @@ def pre_fetch_hook(self, *args, **kwargs):
513562
PRE_FETCH_HOOKS[ec.name](self, *args, **kwargs)
514563

515564
# Always trigger this one, regardless of self.name
516-
cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR')
517-
if cpu_target == CPU_TARGET_ZEN4:
518-
pre_fetch_hook_zen4_gcccore1220(self, *args, **kwargs)
565+
pre_fetch_hook_unsupported_modules(self, *args, **kwargs)
519566

520567
# Always check the software installation path
521568
pre_fetch_hook_check_installation_path(self, *args, **kwargs)
@@ -549,13 +596,28 @@ def pre_fetch_hook_check_installation_path(self, *args, **kwargs):
549596
)
550597

551598

552-
def pre_fetch_hook_zen4_gcccore1220(self, *args, **kwargs):
553-
"""Use --force --module-only if building a foss-2022b-based EasyConfig for Zen4.
554-
This toolchain will not be supported on Zen4, so we will generate a modulefile
555-
and have it print an LmodError.
599+
def is_unsupported_module(ec):
556600
"""
557-
if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name,
558-
tcversion=self.toolchain.version):
601+
Determine if the given module is unsupported in EESSI, and hence if a dummy module needs to be built that just prints an LmodError.
602+
If true, this function returns the name of the environment variable that can be used to ignore that particular LmodError,
603+
as this is still required to actually build the module itself (EasyBuild will load/test the module).
604+
Otherwise, it returns False.
605+
"""
606+
cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR')
607+
608+
if cpu_target == CPU_TARGET_A64FX and ec.name == 'Rust' and ec.version == '1.65.0':
609+
return EESSI_IGNORE_A64FX_RUST1650_ENVVAR
610+
if cpu_target == CPU_TARGET_ZEN4 and is_gcccore_1220_based(ecname=ec.name, ecversion=ec.version, tcname=ec.toolchain.name, tcversion=ec.toolchain.version):
611+
return EESSI_IGNORE_ZEN4_GCC1220_ENVVAR
612+
return False
613+
614+
615+
def pre_fetch_hook_unsupported_modules(self, *args, **kwargs):
616+
"""Use --force --module-only if building a module for unsupported software,
617+
e.g. foss-2022b-based EasyConfigs for Zen4.
618+
We will generate a modulefile and have it print an LmodError.
619+
"""
620+
if is_unsupported_module(self):
559621
if hasattr(self, EESSI_MODULE_ONLY_ATTR):
560622
raise EasyBuildError("'self' already has attribute %s! Can't use pre_fetch hook.",
561623
EESSI_MODULE_ONLY_ATTR)
@@ -571,20 +633,20 @@ def pre_fetch_hook_zen4_gcccore1220(self, *args, **kwargs):
571633
print_msg("Updated build option 'force' to 'True'")
572634

573635

574-
def pre_module_hook_zen4_gcccore1220(self, *args, **kwargs):
636+
def pre_module_hook_unsupported_module(self, *args, **kwargs):
575637
"""Make module load-able during module step"""
576-
if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name,
577-
tcversion=self.toolchain.version):
638+
ignore_lmoderror_envvar = is_unsupported_module(self)
639+
if ignore_lmoderror_envvar:
578640
if hasattr(self, 'initial_environ'):
579641
# Allow the module to be loaded in the module step (which uses initial environment)
580-
print_msg(f"Setting {EESSI_IGNORE_ZEN4_GCC1220_ENVVAR} in initial environment")
581-
self.initial_environ[EESSI_IGNORE_ZEN4_GCC1220_ENVVAR] = "1"
642+
print_msg(f"Setting {ignore_lmoderror_envvar} in initial environment")
643+
self.initial_environ[ignore_lmoderror_envvar] = "1"
582644

583645

584-
def post_module_hook_zen4_gcccore1220(self, *args, **kwargs):
585-
"""Revert changes from pre_fetch_hook_zen4_gcccore1220"""
586-
if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name,
587-
tcversion=self.toolchain.version):
646+
def post_module_hook_unsupported_module(self, *args, **kwargs):
647+
"""Revert changes from pre_fetch_hook_unsupported_modules"""
648+
ignore_lmoderror_envvar = is_unsupported_module(self)
649+
if ignore_lmoderror_envvar:
588650
if hasattr(self, EESSI_MODULE_ONLY_ATTR):
589651
update_build_option('module_only', getattr(self, EESSI_MODULE_ONLY_ATTR))
590652
print_msg("Restored original build option 'module_only' to %s" % getattr(self, EESSI_MODULE_ONLY_ATTR))
@@ -601,9 +663,9 @@ def post_module_hook_zen4_gcccore1220(self, *args, **kwargs):
601663

602664
# If the variable to allow loading is set, remove it
603665
if hasattr(self, 'initial_environ'):
604-
if self.initial_environ.get(EESSI_IGNORE_ZEN4_GCC1220_ENVVAR, False):
605-
print_msg(f"Removing {EESSI_IGNORE_ZEN4_GCC1220_ENVVAR} in initial environment")
606-
del self.initial_environ[EESSI_IGNORE_ZEN4_GCC1220_ENVVAR]
666+
if self.initial_environ.get(ignore_lmoderror_envvar, False):
667+
print_msg(f"Removing {ignore_lmoderror_envvar} in initial environment")
668+
del self.initial_environ[ignore_lmoderror_envvar]
607669

608670

609671
def post_easyblock_hook_copy_easybuild_subdir(self, *args, **kwargs):
@@ -679,6 +741,11 @@ def pre_configure_hook(self, *args, **kwargs):
679741
if self.name in PRE_CONFIGURE_HOOKS:
680742
PRE_CONFIGURE_HOOKS[self.name](self, *args, **kwargs)
681743

744+
# workaround for a Zlib macro being renamed in Gentoo, see https://bugs.gentoo.org/383179
745+
# (solves "expected initializer before 'OF'" errors)
746+
if self.name in ['FreeXL', 'libspatialite', 'VSEARCH']:
747+
self.cfg.update('configopts', 'CPPFLAGS="-DOF=_Z_OF ${CPPFLAGS}"')
748+
682749

683750
def pre_configure_hook_BLIS_a64fx(self, *args, **kwargs):
684751
"""
@@ -740,18 +807,6 @@ def pre_configure_hook_score_p(self, *args, **kwargs):
740807
raise EasyBuildError("Score-P-specific hook triggered for non-Score-P easyconfig?!")
741808

742809

743-
def pre_configure_hook_vsearch(self, *args, **kwargs):
744-
"""
745-
Pre-configure hook for VSEARCH
746-
- Workaround for a Zlib macro being renamed in Gentoo, see https://bugs.gentoo.org/383179
747-
(solves "expected initializer before 'OF'" errors)
748-
"""
749-
if self.name == 'VSEARCH':
750-
self.cfg.update('configopts', 'CPPFLAGS="-DOF=_Z_OF ${CPPFLAGS}"')
751-
else:
752-
raise EasyBuildError("VSEARCH-specific hook triggered for non-VSEARCH easyconfig?!")
753-
754-
755810
def pre_configure_hook_extrae(self, *args, **kwargs):
756811
"""
757812
Pre-configure hook for Extrae
@@ -879,6 +934,42 @@ def pre_configure_hook_openblas_optarch_generic(self, *args, **kwargs):
879934
raise EasyBuildError("OpenBLAS-specific hook triggered for non-OpenBLAS easyconfig?!")
880935

881936

937+
def pre_configure_hook_openmpi_ipv6(self, *args, **kwargs):
938+
"""
939+
Pre-configure hook to enable IPv6 support in OpenMPI from EESSI 2025.06 onwards
940+
"""
941+
if self.name == 'OpenMPI':
942+
eessi_version = get_eessi_envvar('EESSI_VERSION')
943+
if eessi_version and LooseVersion(eessi_version) >= '2025.06':
944+
self.cfg.update('configopts', '--enable-ipv6')
945+
else:
946+
raise EasyBuildError("OpenMPI-specific hook triggered for non-OpenMPI easyconfig?!")
947+
948+
949+
def pre_configure_hook_pmix_ipv6(self, *args, **kwargs):
950+
"""
951+
Pre-configure hook to enable IPv6 support in PMIx from EESSI 2025.06 onwards
952+
"""
953+
if self.name == 'PMIx':
954+
eessi_version = get_eessi_envvar('EESSI_VERSION')
955+
if eessi_version and LooseVersion(eessi_version) >= '2025.06':
956+
self.cfg.update('configopts', '--enable-ipv6')
957+
else:
958+
raise EasyBuildError("PMIx-specific hook triggered for non-PMIx easyconfig?!")
959+
960+
961+
def pre_configure_hook_prrte_ipv6(self, *args, **kwargs):
962+
"""
963+
Pre-configure hook to enable IPv6 support in PRRTE from EESSI 2025.06 onwards
964+
"""
965+
if self.name == 'PRRTE':
966+
eessi_version = get_eessi_envvar('EESSI_VERSION')
967+
if eessi_version and LooseVersion(eessi_version) >= '2025.06':
968+
self.cfg.update('configopts', '--enable-ipv6')
969+
else:
970+
raise EasyBuildError("PRRTE-specific hook triggered for non-PRRTE easyconfig?!")
971+
972+
882973
def pre_configure_hook_libfabric_disable_psm3_x86_64_generic(self, *args, **kwargs):
883974
"""Add --disable-psm3 to libfabric configure options when building with --optarch=GENERIC on x86_64."""
884975
if self.name == 'libfabric':
@@ -926,23 +1017,66 @@ def pre_configure_hook_wrf_aarch64(self, *args, **kwargs):
9261017
raise EasyBuildError("WRF-specific hook triggered for non-WRF easyconfig?!")
9271018

9281019

929-
def pre_configure_hook_LAMMPS_zen4(self, *args, **kwargs):
1020+
def pre_configure_hook_LAMMPS_zen4_and_aarch64_cuda(self, *args, **kwargs):
9301021
"""
9311022
pre-configure hook for LAMMPS:
932-
- set kokkos_arch on x86_64/amd/zen4
1023+
- set kokkos_arch on x86_64/amd/zen4 and aarch64/nvidia/grace
1024+
- Disable SIMD for Aarch64 + cuda builds
9331025
"""
9341026

1027+
# Get cpu_target for zen4 hook
9351028
cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR')
1029+
9361030
if self.name == 'LAMMPS':
1031+
# Set kokkos_arch for LAMMPS version which do not have support for the target architecture
1032+
# This is no longer required with easybuild 5.1.2
9371033
if self.version in ('2Aug2023_update2', '2Aug2023_update4', '29Aug2024'):
9381034
if get_cpu_architecture() == X86_64:
9391035
if cpu_target == CPU_TARGET_ZEN4:
9401036
# There is no support for ZEN4 in LAMMPS yet so falling back to ZEN3
9411037
self.cfg['kokkos_arch'] = 'ZEN3'
1038+
elif get_cpu_architecture() == AARCH64:
1039+
if cpu_target == CPU_TARGET_NVIDIA_GRACE:
1040+
# There is no support for NVIDA grace in LAMMPS yet so falling back to ARMV81
1041+
self.cfg['kokkos_arch'] = 'ARMV81'
1042+
1043+
# Disable SIMD for specific CUDA versions
1044+
if self.version == '2Aug2023_update2':
1045+
if get_cpu_architecture() == AARCH64:
1046+
if self.cuda:
1047+
for dep in self.cfg.dependencies():
1048+
if 'CUDA' == dep['name']:
1049+
# This was broken until CUDA 13.1
1050+
if dep['version'] < LooseVersion('13.1'):
1051+
self.cfg['kokkos_arch'] = 'ARMV70'
1052+
cxxflags = os.getenv('CXXFLAGS', '')
1053+
cxxflags = cxxflags.replace('-mcpu=native', '')
1054+
cxxflags += ' -march=armv8-a+nosimd'
1055+
self.log.info("Setting CXXFLAGS to disable NEON: %s", cxxflags)
1056+
env.setvar('CXXFLAGS', cxxflags)
1057+
9421058
else:
9431059
raise EasyBuildError("LAMMPS-specific hook triggered for non-LAMMPS easyconfig?!")
9441060

9451061

1062+
def pre_configure_hook_cmake_system(self, *args, **kwargs):
1063+
"""
1064+
pre-configure hook for CMake built with SYSTEM toolchain:
1065+
- remove configure options that link to ncurses static libraries for CMake with system toolchain;
1066+
see also https://github.com/EESSI/software-layer/issues/1175
1067+
"""
1068+
1069+
if self.name == 'CMake':
1070+
if is_system_toolchain(self.toolchain.name):
1071+
self.log.info("Removing configure options that require ncurses static libraries...")
1072+
self.log.info(f"Original configopts value: {self.cfg['configopts']}")
1073+
regex = re.compile(r"-DCURSES_[A-Z]+_LIBRARY=\$EBROOTNCURSES/lib/lib[a-z]+\.a")
1074+
self.cfg['configopts'] = regex.sub(self.cfg['configopts'], '')
1075+
self.log.info(f"Updated configopts value: {self.cfg['configopts']}")
1076+
else:
1077+
raise EasyBuildError("CMake-specific hook triggered for non-CMake easyconfig?!")
1078+
1079+
9461080
def pre_test_hook(self, *args, **kwargs):
9471081
"""Main pre-test hook: trigger custom functions based on software name."""
9481082
if self.name in PRE_TEST_HOOKS:
@@ -1412,9 +1546,7 @@ def pre_module_hook(self, *args, **kwargs):
14121546
PRE_MODULE_HOOKS[self.name](self, *args, **kwargs)
14131547

14141548
# Always trigger this one, regardless of self.name
1415-
cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR')
1416-
if cpu_target == CPU_TARGET_ZEN4:
1417-
pre_module_hook_zen4_gcccore1220(self, *args, **kwargs)
1549+
pre_module_hook_unsupported_module(self, *args, **kwargs)
14181550

14191551

14201552
def post_module_hook(self, *args, **kwargs):
@@ -1423,9 +1555,7 @@ def post_module_hook(self, *args, **kwargs):
14231555
POST_MODULE_HOOKS[self.name](self, *args, **kwargs)
14241556

14251557
# Always trigger this one, regardless of self.name
1426-
cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR')
1427-
if cpu_target == CPU_TARGET_ZEN4:
1428-
post_module_hook_zen4_gcccore1220(self, *args, **kwargs)
1558+
post_module_hook_unsupported_module(self, *args, **kwargs)
14291559

14301560

14311561
# The post_easyblock_hook was introduced in EasyBuild 5.1.1.
@@ -1480,10 +1610,13 @@ def post_easyblock_hook(self, *args, **kwargs):
14801610
'ROCm-LLVM': pre_configure_hook_llvm,
14811611
'MetaBAT': pre_configure_hook_metabat_filtered_zlib_dep,
14821612
'OpenBLAS': pre_configure_hook_openblas_optarch_generic,
1613+
'OpenMPI': pre_configure_hook_openmpi_ipv6,
1614+
'PMIx': pre_configure_hook_pmix_ipv6,
1615+
'PRRTE': pre_configure_hook_prrte_ipv6,
14831616
'WRF': pre_configure_hook_wrf_aarch64,
1484-
'LAMMPS': pre_configure_hook_LAMMPS_zen4,
1617+
'LAMMPS': pre_configure_hook_LAMMPS_zen4_and_aarch64_cuda,
14851618
'Score-P': pre_configure_hook_score_p,
1486-
'VSEARCH': pre_configure_hook_vsearch,
1619+
'CMake': pre_configure_hook_cmake_system,
14871620
}
14881621

14891622
PRE_TEST_HOOKS = {

0 commit comments

Comments
 (0)