Skip to content

Commit d8804c2

Browse files
authored
Merge pull request #4108 from easybuilders/5.3.x
release EasyBuild v5.3.0
2 parents 0bb747c + 7fe1cf4 commit d8804c2

32 files changed

+1021
-329
lines changed

RELEASE_NOTES

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,42 @@ For more detailed information, please see the git log.
33

44
These release notes can also be consulted at https://docs.easybuild.io/release-notes .
55

6-
The latest version of easybuild-easyblocks provides 208 software-specific easyblocks and 46 generic easyblocks.
6+
The latest version of easybuild-easyblocks provides 209 software-specific easyblocks and 47 generic easyblocks.
7+
8+
9+
v5.3.0 (10 Apr 2026)
10+
--------------------
11+
12+
feature release
13+
14+
- new easyblocks:
15+
- add generic `ROCmComponent` easyblock to build & install ROCm components (#3861)
16+
- custom easyblock for Sentaurus (#4001)
17+
- bug fixes:
18+
- add guard to sanity check in custom easyblock for Stata to avoid running `ldd` on non ELF executable (#4077)
19+
- take into account that no Python dependency may be provided when setting `$Python3_ROOT_DIR` in configure step of `PythonPackage` easyblock (#4079)
20+
- also handle references to git tags in Cargo crates and download git repos recursively (#4081)
21+
- make sure that netcdf easyblock picks up the provided libxml2 and bzip2 dependencies (#4086)
22+
- set `$CIRCLECI` environment variable for torchvsion to work around flaky test (that requires downloading a file from `wikimedia.org`) (#4094)
23+
- include `/usr/local` Python package directory for system-level Python package installations (#4095)
24+
- avoid crash in test step of custom easyblock for SuperLU if OpenMPI is not a dependency (#4099)
25+
- enhancements:
26+
- use `clean_dir` instead of `remove_dir` on installation directory various easyblocks: `Binary` (#3927), `Tarball` (#3926),
27+
Amber (+ AmberTools) (#3935), Anaconda (#3934), FDTD_Solutions (#3933), GATE (#3932), Go (#3931), Java (#3928), Molpro (#3930), Tkinter (#3929)
28+
- enhance `PythonPackage` and `PythonBundle` to verify Python package names and versions with `pip list` with `sanity_check_pip_list` parameter (#4049)
29+
- add ignore patterns for some RISC-V tests in LLVM easyblock (#4059)
30+
- enhance `PythonPackage` and `PythonBundle` easyblocks to add support to install dummy Python packages (#4063)
31+
- enhance custom easyblocks for SCOTCH & MUMPS to add `lfoss` toolchain support (#4069)
32+
- add search paths to CUPTI in installations of nvidia-compilers with CUDA (#4085)
33+
- enhance custom easyblock for Amber easyblock to support installing `pmemd` only (#4093)
34+
- limit number of parallel compile jobs in PyTorch tests by setting `$MAX_JOBS` + add support for using Arm Compute Library (ACL) as dependency (#4096)
35+
- be more patient when running CPLEX interactive installer (#4103)
36+
- add mapping to LAMMPS easyblock for `9.0a`, `10.0f` and `12.0f` CUDA compute capabilities (#4105)
37+
- updates:
38+
- update Conda easyblock to take into account that in Conda 24.3 `--force` was renamed to `--yes` (#3573)
39+
- update CPLEX easyblock for CPLEX v22.1.2 (which doesn't include Python bindings anymore) (#3909)
40+
- update jaxlib easyblock to support LLVM as alternative to Clang for CUDA builds (#4101)
41+
742

843
v5.2.1 (20 Feb 2026)
944
--------------------

easybuild/easyblocks/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
# recent setuptools versions will *TRANSFORM* something like 'X.Y.Zdev' into 'X.Y.Z.dev0', with a warning like
4343
# UserWarning: Normalizing '2.4.0dev' to '2.4.0.dev0'
4444
# This causes problems further up the dependency chain...
45-
VERSION = '5.2.1'
45+
VERSION = '5.3.0'
4646
UNKNOWN = 'UNKNOWN'
4747

4848

easybuild/easyblocks/a/amber.py

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@
4040
from easybuild.easyblocks.generic.pythonpackage import det_pylibdir
4141
from easybuild.framework.easyconfig import CUSTOM
4242
from easybuild.tools.build_log import EasyBuildError
43+
from easybuild.tools.config import build_option
4344
from easybuild.tools.modules import get_software_root, get_software_version
4445
from easybuild.tools.run import run_shell_cmd
45-
from easybuild.tools.filetools import remove_dir, which
46+
from easybuild.tools.filetools import clean_dir, which
4647
from easybuild.tools.systemtools import get_shared_lib_ext
4748

4849

@@ -81,17 +82,26 @@ def __init__(self, *args, **kwargs):
8182
self.with_cuda = False
8283
self.with_mpi = False
8384

85+
if '-pmemd' in self.cfg['versionsuffix']:
86+
self.pmemd = True
87+
else:
88+
self.pmemd = False
89+
8490
def extract_step(self):
8591
"""Extract sources; strip off parent directory during unpack"""
8692
self.cfg.update('unpack_options', "--strip-components=1")
8793
super().extract_step()
8894

8995
def patch_step(self, *args, **kwargs):
90-
"""Patch Amber using 'update_amber' tool, prior to applying listed patch files (if any)."""
96+
"""Patch Amber using update script, prior to applying listed patch files (if any)."""
97+
if self.pmemd:
98+
update_script = 'update_pmemd'
99+
else:
100+
update_script = 'update_amber'
91101

92-
# Use the update_amber script if patchlevels is defined - if not then the easyconfig should apply the patches
102+
# Use update_script if patchlevels is defined - if not then the easyconfig should apply the patches
93103
if self.cfg['patchlevels']:
94-
# figure out which Python command to use to run the update_amber script;
104+
# figure out which Python command to use to run the update script;
95105
# by default it uses 'python', but this may not be available (on CentOS 8 for example);
96106
# note that the dependencies are not loaded yet at this point, so we're at the mercy of the OS here...
97107
python_cmd = None
@@ -101,21 +111,25 @@ def patch_step(self, *args, **kwargs):
101111
break
102112

103113
if python_cmd is None:
104-
raise EasyBuildError("No suitable Python command found to run update_amber script!")
114+
raise EasyBuildError(f"No suitable Python command found to run {update_script}!")
105115

106116
if self.cfg['patchlevels'] == "latest":
107-
cmd = "%s ./update_amber --update" % python_cmd
117+
cmd = f"{python_cmd} ./{update_script} --update"
108118
# Run as many times as specified. It is the responsibility
109119
# of the easyconfig author to get this right, especially if
110120
# he or she selects "latest". (Note: "latest" is not
111121
# recommended for this reason and others.)
112122
for _ in range(self.cfg['patchruns']):
113123
run_shell_cmd(cmd)
114124
else:
115-
for (tree, patch_level) in zip(['AmberTools', 'Amber'], self.cfg['patchlevels']):
125+
if isinstance(self.cfg['patchlevels'], int):
126+
patch_levels = [(self.name, self.cfg['patchlevels'])]
127+
else:
128+
patch_levels = zip(['AmberTools', 'Amber'], self.cfg['patchlevels'])
129+
for (tree, patch_level) in patch_levels:
116130
if patch_level == 0:
117131
continue
118-
cmd = "%s ./update_amber --update-to %s/%s" % (python_cmd, tree, patch_level)
132+
cmd = f"{python_cmd} ./{update_script} --update-to {tree}/{patch_level}"
119133
# Run as many times as specified. It is the responsibility
120134
# of the easyconfig author to get this right.
121135
for _ in range(self.cfg['patchruns']):
@@ -131,8 +145,8 @@ def configure_step(self):
131145
return
132146

133147
# CMake will search a previous install directory for Amber-compiled libs. We will therefore
134-
# manually remove the install directory prior to configuration.
135-
remove_dir(self.installdir)
148+
# manually clean the install directory prior to configuration.
149+
clean_dir(self.installdir)
136150

137151
external_libs_list = []
138152

@@ -161,7 +175,10 @@ def configure_step(self):
161175
self.cfg.update('configopts', '-DCUDA=TRUE')
162176
if get_software_root('NCCL'):
163177
self.cfg.update('configopts', '-DNCCL=TRUE')
164-
external_libs_list.append('nccl')
178+
if self.pmemd:
179+
self.cfg.update('configopts', '-Dnccl_ENABLED=TRUE')
180+
else:
181+
external_libs_list.append('nccl')
165182

166183
pythonroot = get_software_root('Python')
167184
if pythonroot:
@@ -184,18 +201,20 @@ def configure_step(self):
184201
self.cfg.update('configopts', f'-DPYTHON_LIBRARY={python_library}')
185202
self.cfg.update('configopts', f'-DPYTHON_INCLUDE_DIR={python_incdir}')
186203

187-
if get_software_root('FFTW'):
188-
external_libs_list.append('fftw')
189204
if get_software_root('netCDF'):
190205
external_libs_list.append('netcdf')
191206
if get_software_root('netCDF-Fortran'):
192207
external_libs_list.append('netcdf-fortran')
193208
if get_software_root('zlib'):
194209
external_libs_list.append('zlib')
195-
if get_software_root('Boost'):
196-
external_libs_list.append('boost')
197-
if get_software_root('PnetCDF'):
198-
external_libs_list.append('pnetcdf')
210+
211+
if not self.pmemd:
212+
if get_software_root('FFTW'):
213+
external_libs_list.append('fftw')
214+
if get_software_root('Boost'):
215+
external_libs_list.append('boost')
216+
if get_software_root('PnetCDF'):
217+
external_libs_list.append('pnetcdf')
199218

200219
# Force libs for available deps (see cmake/3rdPartyTools.cmake in Amber source for list of 3rd party libs)
201220
# This provides an extra layer of checking but should already be handled by TRUST_SYSTEM_LIBS=TRUE
@@ -217,6 +236,9 @@ def configure_step(self):
217236

218237
self.cfg.update('configopts', '-DCOMPILER=AUTO')
219238

239+
if self.pmemd:
240+
self.cfg.update('configopts', '-DPMEMD_ONLY=TRUE')
241+
220242
# configure using cmake
221243
super().configure_step()
222244

@@ -361,34 +383,47 @@ def install_step(self):
361383
'source %s/amber.sh && cd %s' % (self.installdir, testdir)
362384
])
363385

386+
if build_option('ignore_test_failure'):
387+
fail_on_error = False
388+
else:
389+
fail_on_error = True
390+
364391
# serial tests
392+
if self.pmemd:
393+
pre = 'ln -sr config.h ../ && '
394+
else:
395+
pre = ''
365396
if LooseVersion(self.version) >= LooseVersion('24'):
366-
run_shell_cmd("%s && make test" % pretestcommands)
397+
run_shell_cmd(f"{pre}{pretestcommands} && make test", fail_on_error=fail_on_error)
367398
else:
368-
run_shell_cmd("%s && make test.serial" % pretestcommands)
399+
run_shell_cmd(f"{pre}{pretestcommands} && make test.serial", fail_on_error=fail_on_error)
369400
if self.with_cuda:
370-
res = run_shell_cmd(f"{pretestcommands} && make {testname_cs}")
401+
res = run_shell_cmd(f"{pretestcommands} && make {testname_cs}", fail_on_error=fail_on_error)
371402
if res.exit_code > 0:
372403
self.log.warning("Check the output of the Amber cuda tests for possible failures")
373404

374405
# parallel tests
375406
if self.with_mpi:
376407
# Hard-code parallel tests to use 4 threads
377408
env.setvar("DO_PARALLEL", self.toolchain.mpi_cmd_for('', 4))
378-
res = run_shell_cmd(f"{pretestcommands} && make test.parallel")
409+
res = run_shell_cmd(f"{pretestcommands} && make test.parallel", fail_on_error=fail_on_error)
379410
if res.exit_code > 0:
380411
self.log.warning("Check the output of the Amber parallel tests for possible failures")
381412

382413
if self.with_mpi and self.with_cuda:
383414
# Hard-code CUDA parallel tests to use 2 threads
384415
env.setvar("DO_PARALLEL", self.toolchain.mpi_cmd_for('', 2))
385-
res = run_shell_cmd(f"{pretestcommands} && make {testname_cp}")
416+
res = run_shell_cmd(f"{pretestcommands} && make {testname_cp}", fail_on_error=fail_on_error)
386417
if res.exit_code > 0:
387418
self.log.warning("Check the output of the Amber cuda_parallel tests for possible failures")
388419

389420
def sanity_check_step(self):
390421
"""Custom sanity check for Amber."""
391-
binaries = ['sander', 'tleap']
422+
binaries = []
423+
424+
if not self.pmemd:
425+
binaries.extend(['sander', 'tleap'])
426+
392427
if self.name == 'Amber':
393428
binaries.append('pmemd')
394429
if self.with_cuda:
@@ -398,15 +433,17 @@ def sanity_check_step(self):
398433
binaries.append('pmemd.cuda.MPI')
399434
else:
400435
binaries.append('pmemd.cuda_DPFP.MPI')
436+
401437
if self.name == 'AmberTools':
402438
binaries.append('gem.pmemd')
403439

404440
if self.with_mpi:
405-
binaries.extend(['sander.MPI'])
406441
if self.name == 'Amber':
407442
binaries.append('pmemd.MPI')
408443
if self.name == 'AmberTools':
409444
binaries.append('gem.pmemd.MPI')
445+
if not self.pmemd:
446+
binaries.append('sander.MPI')
410447

411448
custom_paths = {
412449
'files': [os.path.join(self.installdir, 'bin', binary) for binary in binaries],

easybuild/easyblocks/a/anaconda.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import stat
3434

3535
from easybuild.easyblocks.generic.binary import Binary
36-
from easybuild.tools.filetools import adjust_permissions, remove_dir
36+
from easybuild.tools.filetools import adjust_permissions, clean_dir
3737
from easybuild.tools.modules import MODULE_LOAD_ENV_HEADERS
3838
from easybuild.tools.run import run_shell_cmd
3939

@@ -59,7 +59,7 @@ def __init__(self, *args, **kwargs):
5959
def install_step(self):
6060
"""Copy all files in build directory to the install directory"""
6161

62-
remove_dir(self.installdir)
62+
clean_dir(self.installdir)
6363
install_script = self.src[0]['name']
6464

6565
adjust_permissions(os.path.join(self.builddir, install_script), stat.S_IRUSR | stat.S_IXUSR)

easybuild/easyblocks/c/cplex.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ def prepare_step(self, *args, **kwargs):
6565
"""Prepare build environment."""
6666
super().prepare_step(*args, **kwargs)
6767

68-
if get_software_root('Python'):
68+
# for CPLEX >= 22.1.2 Python bindings are not included anymore,
69+
# must be installed from PyPI;
70+
# see https://www.ibm.com/docs/en/icos/22.1.2?topic=rnco2-cplex-python-api-now-installed-using-pip-conda
71+
if get_software_root('Python') and LooseVersion(self.version) < LooseVersion('22.1.2'):
6972
self.with_python = True
7073

7174
def install_step(self):
@@ -98,13 +101,15 @@ def install_step(self):
98101
]
99102
no_qa = [r'Installing\.\.\..*\n.*------.*\n\n.*============.*\n.*$']
100103

101-
run_shell_cmd(cmd, qa_patterns=qa, qa_wait_patterns=no_qa)
104+
run_shell_cmd(cmd, qa_patterns=qa, qa_wait_patterns=no_qa, qa_timeout=1000)
102105

103106
# fix permissions on install dir
104107
perms = stat.S_IRWXU | stat.S_IXOTH | stat.S_IXGRP | stat.S_IROTH | stat.S_IRGRP
105108
adjust_permissions(self.installdir, perms, recursive=False, relative=False)
106109

107-
# also install Python bindings if Python is included as a dependency
110+
# also install Python bindings if Python is included as a dependency;
111+
# only for CPLEX < 22.1.2, for recent version Python bindings must be
112+
# installed from PyPI
108113
if self.with_python:
109114
cwd = change_dir(os.path.join(self.installdir, 'python'))
110115
run_shell_cmd("python setup.py install --prefix=%s" % self.installdir)

easybuild/easyblocks/f/fdtd_solutions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def install_step(self):
7373
else:
7474
raise EasyBuildError("Failed to isolate top-level directory using %s", top_dir_glob)
7575

76-
copy_dir(top_dir, self.installdir, symlinks=self.cfg['keepsymlinks'])
76+
copy_dir(top_dir, self.installdir, symlinks=self.cfg['keepsymlinks'], dirs_exist_ok=True)
7777

7878
def sanity_check_step(self):
7979
"""Custom sanity check for FDTD Solutions."""

easybuild/easyblocks/g/gate.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from easybuild.easyblocks.generic.cmakemake import CMakeMake
4141
from easybuild.framework.easyconfig import CUSTOM
4242
from easybuild.tools.build_log import EasyBuildError
43+
from easybuild.tools.filetools import clean_dir, copy_dir
4344
from easybuild.tools.run import run_shell_cmd
4445
from easybuild.tools.systemtools import get_shared_lib_ext
4546

@@ -138,8 +139,8 @@ def install_step(self):
138139

139140
# copy all the things
140141
try:
141-
shutil.rmtree(self.installdir)
142-
shutil.copytree(self.cfg['start_dir'], self.installdir)
142+
clean_dir(self.installdir)
143+
copy_dir(self.cfg['start_dir'], self.installdir, dirs_exist_ok=True)
143144
except OSError as err:
144145
raise EasyBuildError("Failed to copy %s to %s: %s", self.cfg['start_dir'], self.installdir, err)
145146

easybuild/easyblocks/g/go.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@
2929
@author: Kenneth Hoste (HPC-UGent)
3030
"""
3131
import os
32-
import shutil
3332

3433
from easybuild.tools import LooseVersion
3534

3635
from easybuild.easyblocks.generic.configuremake import ConfigureMake
3736
from easybuild.tools.build_log import EasyBuildError
38-
from easybuild.tools.filetools import remove_dir
37+
from easybuild.tools.filetools import clean_dir, copy_dir
3938
from easybuild.tools.run import run_shell_cmd
4039
from easybuild.tools.modules import get_software_root
4140

@@ -76,7 +75,7 @@ def install_step(self):
7675
run_shell_cmd(cmd, work_dir=srcdir)
7776

7877
try:
79-
remove_dir(self.installdir)
80-
shutil.copytree(self.cfg['start_dir'], self.installdir, symlinks=self.cfg['keepsymlinks'])
78+
clean_dir(self.installdir)
79+
copy_dir(self.cfg['start_dir'], self.installdir, symlinks=self.cfg['keepsymlinks'], dirs_exist_ok=True)
8180
except OSError as err:
8281
raise EasyBuildError("Failed to copy installation to %s: %s", self.installdir, err)

0 commit comments

Comments
 (0)