Skip to content

Commit 8c13cca

Browse files
authored
Merge pull request #5006 from easybuilders/5.1.x
release EasyBuild v5.1.2
2 parents e5ba343 + ae073ba commit 8c13cca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1916
-981
lines changed

.github/workflows/unit_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
setup:
1414
runs-on: ubuntu-latest
1515
outputs:
16-
lmod8: Lmod-8.7.58
16+
lmod8: Lmod-8.7.65
1717
modules4: modules-4.5.3
1818
modules5: modules-5.3.1
1919
steps:

RELEASE_NOTES

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,45 @@ For more detailed information, please see the git log.
44
These release notes can also be consulted at https://docs.easybuild.io/release-notes .
55

66

7+
v5.1.2 (26 Sept 2025)
8+
---------------------
9+
10+
update/bugfix release
11+
12+
- enhancements:
13+
- show readable error message when applying patch without (extracted) source (#4738)
14+
- add support for `amdgcn-capabilities` configuration option and `amdgcn_capabilities` easyconfig parameter + related templates, similar to `cuda-compute-capabilities` (#4860)
15+
- try to empty install dir if removing it fails (#4932)
16+
- add support for "extensions" on Tcl modulefiles , but disable it for now (#4972, #4978, #4985)
17+
- exit with appropriate error code for `--search` when no match is found (#4976)
18+
- handle `post_install_patches` and `post_install_msgs` for extensions (#4980)
19+
- skip RPATH sanity check for symlinks explicitely (#4988)
20+
- take `--terse` into account for `--dry-run-short`/`-D` and `--dry-run` (#4989)
21+
- bug fixes:
22+
- test if all extensions support parallel install before attempting parallel extension install (#4949)
23+
- do not fail for read-only installation directory on `--module-only` (re)builds (#4958, #5004)
24+
- store all patches (incl. the ones for extensions) that need to be copied to a repo/reprod dir in an `all_patches` set (#4960)
25+
- fix error when adding files to existing PR with `--update-pr` and refactor + fixes in `options` tests (#4962)
26+
- add back `OrderedDict` import in (deprecated) `easybuild.tools.py2vs3.py3` module (#4965)
27+
- fixes for RPATH wrapper script:
28+
- detect & replace `-Xlinker --enable-new-dtags` (#4970)
29+
- do not add RPATH (linking) flags when `-c` flag specified (#4981)
30+
- honor `--disable-module-extensions` configuration option (#4971)
31+
- fix f-string in rpath check and skip check for linked libs on symlinks (#4975)
32+
- fix passing command as list of strings to `run_shell_cmd` (#4977)
33+
- add `f` for the f-string in a `git_config` error (#4982)
34+
- keep `ModuleTool.mod_paths` in sync with `MODULEPATH` in `ModuleTool.load()` (#4991)
35+
- fix failure to resolve template in tests (#4994)
36+
- update regex used in `Lmod.get_setenv_value_from_modulefile` (#4998)
37+
- enhancements and fixes for test suite:
38+
- only run tests for `--from-commit` for subset of test configurations (those for which a GitHub token is available) (#4967)
39+
- adapt `module_extensions` disable test for Tcl modulefiles (#4973)
40+
- other changes:
41+
- don't log variables (un)set + raw output of `module` command when cleaning up fake module (#4942)
42+
- introduce `PYTHON_EXE` variable in template for RPATH wrapper script (to easily replace name of `python` command to use in `buildenv` easyblock) (#4984)
43+
- remove deprecated license classifier in `setup.py` (#5002)
44+
45+
746
v5.1.1 (6 July 2025)
847
--------------------
948

easybuild/base/frozendict.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __repr__(self):
5252

5353
def __hash__(self):
5454
if self.__hash is None:
55-
self.__hash = reduce(operator.xor, map(hash, self.iteritems()), 0)
55+
self.__hash = reduce(operator.xor, map(hash, self.items()), 0)
5656

5757
return self.__hash
5858

easybuild/base/testing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ def assertEqual(self, a, b, msg=None):
114114
raise AssertionError("%s:\nDIFF%s:\n%s" % (msg, limit, ''.join(diff[:self.ASSERT_MAX_DIFF]))) from None
115115

116116
def assertExists(self, path, msg=None):
117-
"""Assert the given path exists"""
117+
"""Assert that the given path exists"""
118118
if msg is None:
119119
msg = "'%s' should exist" % path
120120
self.assertTrue(os.path.exists(path), msg)
121121

122122
def assertNotExists(self, path, msg=None):
123-
"""Assert the given path exists"""
123+
"""Assert that the given path does not exist"""
124124
if msg is None:
125125
msg = "'%s' should not exist" % path
126126
self.assertFalse(os.path.exists(path), msg)

easybuild/framework/easyblock.py

Lines changed: 145 additions & 89 deletions
Large diffs are not rendered by default.

easybuild/framework/easyconfig/default.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
'toolchainopts': [None, 'Extra options for compilers', TOOLCHAIN],
8585

8686
# BUILD easyconfig parameters
87+
'amdgcn_capabilities': [[], "List of AMDGCN capabilities to build with (if supported)", BUILD],
8788
'banned_linked_shared_libs': [[], "List of shared libraries (names, file names, or paths) which are not allowed "
8889
"to be linked in any installed binary/library", BUILD],
8990
'bitbucket_account': ['%(namelower)s', "Bitbucket account name to be used to resolve template values in source"

easybuild/framework/easyconfig/easyconfig.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,28 @@ def get_cuda_cc_template_value(self, key, required=True):
19921992
error_msg = "%s is not a template value based on --cuda-compute-capabilities/cuda_compute_capabilities"
19931993
raise EasyBuildError(error_msg, key)
19941994

1995+
def get_amdgcn_cc_template_value(self, key, required=True):
1996+
"""
1997+
Get template value based on --amdgcn-capabilities EasyBuild configuration option
1998+
and amdgcn_capabilities easyconfig parameter.
1999+
Returns user-friendly error message in case neither are defined,
2000+
or if an unknown key is used.
2001+
"""
2002+
if key.startswith('amdgcn_') and any(x == key for x in TEMPLATE_NAMES_DYNAMIC):
2003+
try:
2004+
return self.template_values[key]
2005+
except KeyError:
2006+
if not required:
2007+
self.log.debug(f'Key {key} not found in template values, returning empty value')
2008+
return ''
2009+
error_msg = "Template value '%s' is not defined!\n"
2010+
error_msg += "Make sure that either the --amdgcn-capabilities EasyBuild configuration "
2011+
error_msg += "option is set, or that the amdgcn_capabilities easyconfig parameter is defined."
2012+
raise EasyBuildError(error_msg, key)
2013+
else:
2014+
error_msg = "%s is not a template value based on --amdgcn-capabilities/amdgcn_capabilities"
2015+
raise EasyBuildError(error_msg, key)
2016+
19952017

19962018
def det_installversion(version, toolchain_name, toolchain_version, prefix, suffix):
19972019
"""Deprecated 'det_installversion' function, to determine exact install version, based on supplied parameters."""

easybuild/framework/easyconfig/templates.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@
8888
# template values which are only generated dynamically
8989
TEMPLATE_NAMES_DYNAMIC = {
9090
'arch': 'System architecture (e.g. x86_64, aarch64, ppc64le, ...)',
91+
'amdgcn_capabilities': "Comma-separated list of AMDGCN capabilities, as specified via "
92+
"--amdgcn-capabilities configuration option or "
93+
"via amdgcn_capabilities easyconfig parameter",
94+
'amdgcn_cc_space_sep': "Space-separated list of AMDGCN capabilities",
95+
'amdgcn_cc_semicolon_sep': "Semicolon-separated list of AMDGCN capabilities",
9196
'cuda_compute_capabilities': "Comma-separated list of CUDA compute capabilities, as specified via "
9297
"--cuda-compute-capabilities configuration option or "
9398
"via cuda_compute_capabilities easyconfig parameter",
@@ -478,6 +483,14 @@ def template_constant_dict(config, ignore=None, toolchain=None):
478483
template_values['cuda_sm_comma_sep'] = ','.join(sm_values)
479484
template_values['cuda_sm_space_sep'] = ' '.join(sm_values)
480485

486+
# step 7. AMDGCN capabilities
487+
# Use the commandline / easybuild config option if given, else use the value from the EC (as a default)
488+
amdgcn_cc = build_option('amdgcn_capabilities') or config.get('amdgcn_capabilities')
489+
if amdgcn_cc:
490+
template_values['amdgcn_capabilities'] = ','.join(amdgcn_cc)
491+
template_values['amdgcn_cc_space_sep'] = ' '.join(amdgcn_cc)
492+
template_values['amdgcn_cc_semicolon_sep'] = ';'.join(amdgcn_cc)
493+
481494
unknown_names = []
482495
for key in template_values:
483496
if not (key in common_template_names or key in TEMPLATE_NAMES_DYNAMIC):

easybuild/framework/extension.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ def post_install_extension(self):
232232
Stuff to do after installing a extension.
233233
"""
234234
self.master.run_post_install_commands(commands=self.cfg.get('postinstallcmds', []))
235+
self.master.apply_post_install_patches(patches=[p for p in self.patches if p['postinstall']])
236+
self.master.print_post_install_messages(msgs=self.cfg.get('postinstallmsgs', []))
235237

236238
def install_extension_substep(self, substep, *args, **kwargs):
237239
"""

easybuild/main.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
# IMPORTANT this has to be the first easybuild import as it customises the logging
5050
# expect missing log output when this not the case!
5151
from easybuild.tools.build_log import EasyBuildError, print_error, print_msg, print_warning, stop_logging
52+
from easybuild.tools.build_log import EasyBuildExit
5253

5354
from easybuild.framework.easyblock import build_and_install_one, inject_checksums, inject_checksums_to_json
5455
from easybuild.framework.easyconfig import EASYCONFIGS_PKG_SUBDIR
@@ -243,10 +244,10 @@ def run_contrib_style_checks(ecs, check_contrib, check_style):
243244
return check_contrib or check_style
244245

245246

246-
def clean_exit(logfile, tmpdir, testing, silent=False):
247+
def clean_exit(logfile, tmpdir, testing, silent=False, exit_code=0):
247248
"""Small utility function to perform a clean exit."""
248249
cleanup(logfile, tmpdir, testing, silent=silent)
249-
sys.exit(0)
250+
sys.exit(exit_code)
250251

251252

252253
def process_easystack(easystack_path, args, logfile, testing, init_session_state, do_build):
@@ -675,15 +676,13 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None, pr
675676
else:
676677
_log.debug("Packaging not enabled, so not checking for packaging support.")
677678

678-
# search for easyconfigs, if a query is specified
679-
if search_query:
680-
search_easyconfigs(search_query, short=options.search_short, filename_only=options.search_filename,
681-
terse=options.terse)
682-
683679
if options.check_eb_deps:
684680
print_checks(check_easybuild_deps(modtool))
685681

686-
# GitHub options that warrant a silent cleanup & exit
682+
# Exitcode to use when exiting directly after any of the following options
683+
silent_exit_code = EasyBuildExit.SUCCESS
684+
685+
# Options that warrant a silent cleanup & exit
687686
if options.check_github:
688687
check_github()
689688

@@ -713,6 +712,11 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None, pr
713712
elif options.list_software:
714713
print(list_software(output_format=options.output_format, detailed=options.list_software == 'detailed'))
715714

715+
elif search_query:
716+
if not search_easyconfigs(search_query, short=options.search_short, filename_only=options.search_filename,
717+
terse=options.terse):
718+
silent_exit_code = EasyBuildExit.MISSING_EASYCONFIG
719+
716720
elif options.create_index:
717721
print_msg("Creating index for %s..." % options.create_index, prefix=False)
718722
index_fp = dump_index(options.create_index, max_age_sec=options.index_max_age)
@@ -732,13 +736,13 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None, pr
732736
options.list_prs,
733737
options.merge_pr,
734738
options.review_pr,
735-
# --missing-modules is processed by process_eb_args,
739+
# --missing-modules and dry_run(_short) are processed by process_eb_args,
736740
# so we can't exit just yet here if it's used in combination with --terse
737-
options.terse and not options.missing_modules,
741+
options.terse and not (options.missing_modules or options.dry_run or options.dry_run_short),
738742
search_query,
739743
]
740744
if any(early_stop_options):
741-
clean_exit(logfile, eb_tmpdir, testing, silent=True)
745+
clean_exit(logfile, eb_tmpdir, testing, silent=True, exit_code=silent_exit_code)
742746

743747
# update session state
744748
eb_config = eb_go.generate_cmd_line(add_default=True)

0 commit comments

Comments
 (0)