Skip to content

Commit d3d5570

Browse files
Merge branch 'nompi' of github.com:SebastianAchilles/easybuild-framework into nompi
2 parents 853f990 + 3518f13 commit d3d5570

File tree

22 files changed

+346
-178
lines changed

22 files changed

+346
-178
lines changed

RELEASE_NOTES

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

66

7+
v4.4.0 (June 2nd 2021)
8+
----------------------
9+
10+
feature release
11+
12+
- various enhancements, including:
13+
- enhance apply_regex_substitutions to allow specifying action to take in case there are no matches (#3440)
14+
- performance improvements for easyconfig parsing and eb startup (#3555)
15+
- add support for downloading easyconfigs from multiple PRs with --from-pr (#3605, #3707, #3708)
16+
- add support for prepending custom library paths in RPATH section via --rpath-override-dirs (#3650)
17+
- allow amending easyconfig parameters which are not the default (#3651)
18+
- update HierarchicalMNS for Intel OneAPI compilers (#3653)
19+
- add support for --sanity-check-only (#3655)
20+
- add support for running commands asynchronously via run_cmd + complete_cmd functions (#3656)
21+
- add support for using oneAPI versions of 'intel' toolchain components (#3665)
22+
- add toolchain definition for gofbf (foss with FlexiBLAS rather than OpenBLAS) (#3666)
23+
- add support for using ARCH constant in easyconfig files (#3670)
24+
- honor keyboard interrupt in 'eb' command (#3674)
25+
- add toolchain definition for Fujitsu toolchain (#3677, #3704, #3712, #3713, #3714, #3717)
26+
- extend sanity check step to check whether specific libraries are not linked into installed binaries/libraries (#3678)
27+
- via banned-linked-shared-libs and required-linked-shared-libs EasyBuild configuration options
28+
- via banned_linked_shared_libs and required_linked_shared_libs methods in toolchain support
29+
- via banned_linked_shared_libs and required_linked_shared_libs methods in easyblock
30+
- via banned_linked_shared_libs and required_linked_shared_libs easyconfig parameters
31+
- add locate_solib function to locate Linux shared libraries (#3682)
32+
- add system agnostic function to locate shared libraries (#3683)
33+
- add update_build_option function to update specific build options after initializing the EasyBuild configuration (#3684)
34+
- allow opting out of recursively unloaded of modules via recursive_module_unload easyconfig parameter (#3689)
35+
- check for correct version values when parsing easystack file (#3693)
36+
- run post-install commands specified for a specific extension (#3696)
37+
- add support for --skip-extensions (#3702)
38+
- include PR title in output produced by --merge-pr (#3706)
39+
- various bug fixes, including:
40+
- avoid metadata greedy behaviour when probing for external module metadata (mostly relevant for integration with Cray Programming Environment) (#3559)
41+
- catch problems early on if --github-user is not specified for --new-pr & co (#3644)
42+
- re-enable write permissions when installing with read-only-installdir (#3649)
43+
- also run sanity check for extensions when using --module-only (#3655)
44+
- improve logging when failing to load class from exts_classmap (#3657)
45+
- fix use of --module-only on existing installations without write permissions (#3659)
46+
- correct help text for subdir-user-modules (#3660)
47+
- avoid picking up easyblocks outside of sandbox in framework tests (#3680)
48+
- use unload/load in ModuleGeneratorLua.swap_module, since 'swap' is not supported by Lmod (#3685)
49+
- update HierarchicalMNS to also return 'Toolchain/<name>/<version>' as $MODULEPATH extension for cpe* Cray toolchains (#3686)
50+
- make EasyConfigParser.get_config_dict return a copy rather than a reference (#3692)
51+
- make sure that $TAPE is unset when using piped tar (#3698)
52+
- fix extending message for changed files in new_pr_from_branch (#3699)
53+
- enhance sched_getaffinity function to avoid early crash when counting available cores on systems with more than 1024 cores (#3701)
54+
- correctly strip extension from filename in extract_cmd and back_up_file functions (#3705)
55+
- other changes:
56+
- deprecate adding a non-existing path to $MODULEPATH (#3637)
57+
- bump cryptography requirement from 3.2.1 to 3.3.2 (#3643, #3648)
58+
- test bootstrap script in separate workflow, and limit test configurations a bit (#3646)
59+
- update setup.py to indicate compatibility with Python 3.8 and 3.9 (#3647)
60+
- replace log_error parameter of which() by on_error (#3661, #3664)
61+
- don't skip sanity check for --module-only --rebuild (#3645)
62+
- move disable_templating function into the EasyConfig class (#3668)
63+
- pin GitPython version for Python<3.6, don't test bootstrap script against Python 3.8/3.9 (#3675)
64+
- tweak foss toolchain definition to switch from OpenBLAS to FlexiBLAS in foss/2021a (#3679)
65+
- suggest missing SSH key when not able to read from remote repository in --check-github (#3681)
66+
- drop support for Python 2.6 (#3715)
67+
68+
769
v4.3.4 (April 9th 2021)
870
-----------------------
971

easybuild/framework/easyblock.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
from easybuild.tools.hooks import BUILD_STEP, CLEANUP_STEP, CONFIGURE_STEP, EXTENSIONS_STEP, FETCH_STEP, INSTALL_STEP
8282
from easybuild.tools.hooks import MODULE_STEP, PACKAGE_STEP, PATCH_STEP, PERMISSIONS_STEP, POSTITER_STEP, POSTPROC_STEP
8383
from easybuild.tools.hooks import PREPARE_STEP, READY_STEP, SANITYCHECK_STEP, SOURCE_STEP, TEST_STEP, TESTCASES_STEP
84-
from easybuild.tools.hooks import load_hooks, run_hook
84+
from easybuild.tools.hooks import MODULE_WRITE, load_hooks, run_hook
8585
from easybuild.tools.run import run_cmd
8686
from easybuild.tools.jenkins import write_to_xml
8787
from easybuild.tools.module_generator import ModuleGeneratorLua, ModuleGeneratorTcl, module_generator, dependencies_for
@@ -144,7 +144,7 @@ def __init__(self, ec):
144144
# keep track of original working directory, so we can go back there
145145
self.orig_workdir = os.getcwd()
146146

147-
# list of pre- and post-step hooks
147+
# dict of all hooks (mapping of name to function)
148148
self.hooks = load_hooks(build_option('hooks'))
149149

150150
# list of patch/source files, along with checksums
@@ -3165,6 +3165,10 @@ def make_module_step(self, fake=False):
31653165
txt += self.make_module_extra()
31663166
txt += self.make_module_footer()
31673167

3168+
hook_txt = run_hook(MODULE_WRITE, self.hooks, args=[self, mod_filepath, txt])
3169+
if hook_txt is not None:
3170+
txt = hook_txt
3171+
31683172
if self.dry_run:
31693173
# only report generating actual module file during dry run, don't mention temporary module files
31703174
if not fake:
@@ -3528,7 +3532,16 @@ def run_all_steps(self, run_test_cases):
35283532
else:
35293533
print_msg("%s..." % descr, log=self.log, silent=self.silent)
35303534
self.current_step = step_name
3531-
self.run_step(step_name, step_methods)
3535+
start_time = datetime.now()
3536+
try:
3537+
self.run_step(step_name, step_methods)
3538+
finally:
3539+
if not self.dry_run:
3540+
step_duration = datetime.now() - start_time
3541+
if step_duration.total_seconds() >= 1:
3542+
print_msg("... (took %s)", time2str(step_duration), log=self.log, silent=self.silent)
3543+
elif self.logdebug or build_option('trace'):
3544+
print_msg("... (took < 1 sec)", log=self.log, silent=self.silent)
35323545

35333546
except StopException:
35343547
pass

easybuild/framework/easyconfig/format/one.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,14 @@ def get_config_dict(self):
135135
# we can't use copy.deepcopy() directly because in Python 2 copying the (irrelevant) __builtins__ key fails...
136136
cfg_copy = {}
137137
for key in cfg:
138-
if key != '__builtins__':
139-
cfg_copy[key] = copy.deepcopy(cfg[key])
138+
# skip special variables like __builtins__, and imported modules (like 'os')
139+
if key != '__builtins__' and "'module'" not in str(type(cfg[key])):
140+
try:
141+
cfg_copy[key] = copy.deepcopy(cfg[key])
142+
except Exception as err:
143+
raise EasyBuildError("Failed to copy '%s' easyconfig parameter: %s" % (key, err))
144+
else:
145+
self.log.debug("Not copying '%s' variable from parsed easyconfig", key)
140146

141147
return cfg_copy
142148

easybuild/framework/easyconfig/tools.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ def det_easyconfig_paths(orig_paths):
334334
:return: list of paths to easyconfig files
335335
"""
336336
try:
337-
from_prs = [int(pr_nr) for pr_nr in build_option('from_pr')]
337+
from_prs = [int(x) for x in build_option('from_pr')]
338338
except ValueError:
339339
raise EasyBuildError("Argument to --from-pr must be a comma separated list of PR #s.")
340340

@@ -623,6 +623,14 @@ def categorize_files_by_type(paths):
623623
# file must exist in order to check whether it's a patch file
624624
elif os.path.isfile(path) and is_patch_file(path):
625625
res['patch_files'].append(path)
626+
elif path.endswith('.patch'):
627+
if not os.path.exists(path):
628+
raise EasyBuildError('File %s does not exist, did you mistype the path?', path)
629+
elif not os.path.isfile(path):
630+
raise EasyBuildError('File %s is expected to be a regular file, but is a folder instead', path)
631+
else:
632+
raise EasyBuildError('%s is not detected as a valid patch file. Please verify its contents!',
633+
path)
626634
else:
627635
# anything else is considered to be an easyconfig file
628636
res['easyconfigs'].append(path)

easybuild/toolchains/compiler/fujitsu.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
:author: Miguel Dias Costa (National University of Singapore)
3131
"""
3232
import os
33+
import re
3334

35+
import easybuild.tools.environment as env
3436
import easybuild.tools.systemtools as systemtools
3537
from easybuild.tools.toolchain.compiler import Compiler, DEFAULT_OPT_LEVEL
3638

@@ -46,9 +48,8 @@ class FujitsuCompiler(Compiler):
4648
COMPILER_MODULE_NAME = [TC_CONSTANT_MODULE_NAME]
4749
COMPILER_FAMILY = TC_CONSTANT_FUJITSU
4850

49-
# make sure fcc is always called in clang compatibility mode
50-
COMPILER_CC = 'fcc -Nclang'
51-
COMPILER_CXX = 'FCC -Nclang'
51+
COMPILER_CC = 'fcc'
52+
COMPILER_CXX = 'FCC'
5253

5354
COMPILER_F77 = 'frt'
5455
COMPILER_F90 = 'frt'
@@ -85,15 +86,31 @@ class FujitsuCompiler(Compiler):
8586
(systemtools.AARCH64, systemtools.ARM): '-mcpu=generic -mtune=generic',
8687
}
8788

89+
def prepare(self, *args, **kwargs):
90+
super(FujitsuCompiler, self).prepare(*args, **kwargs)
91+
92+
# fcc doesn't accept e.g. -std=c++11 or -std=gnu++11, only -std=c11 or -std=gnu11
93+
pattern = r'-std=(gnu|c)\+\+(\d+)'
94+
if re.search(pattern, self.vars['CFLAGS']):
95+
self.log.debug("Found '-std=(gnu|c)++' in CFLAGS, fcc doesn't accept '++' here, removing it")
96+
self.vars['CFLAGS'] = re.sub(pattern, r'-std=\1\2', self.vars['CFLAGS'])
97+
self._setenv_variables()
98+
99+
# make sure the fujitsu module libraries are found (and added to rpath by wrapper)
100+
library_path = os.getenv('LIBRARY_PATH', '')
101+
libdir = os.path.join(os.getenv(TC_CONSTANT_MODULE_VAR), 'lib64')
102+
if libdir not in library_path:
103+
self.log.debug("Adding %s to $LIBRARY_PATH" % libdir)
104+
env.setvar('LIBRARY_PATH', os.pathsep.join([library_path, libdir]))
105+
88106
def _set_compiler_vars(self):
89107
super(FujitsuCompiler, self)._set_compiler_vars()
90108

91109
# enable clang compatibility mode
92-
# moved to compiler constants to make sure it is always used
93-
# self.variables.nappend('CFLAGS', ['Nclang'])
94-
# self.variables.nappend('CXXFLAGS', ['Nclang'])
110+
self.variables.nappend('CFLAGS', ['Nclang'])
111+
self.variables.nappend('CXXFLAGS', ['Nclang'])
95112

96-
# make sure the fujitsu module libraries are found (and added to rpath by wrapper)
113+
# also add fujitsu module library path to LDFLAGS
97114
libdir = os.path.join(os.getenv(TC_CONSTANT_MODULE_VAR), 'lib64')
98115
self.log.debug("Adding %s to $LDFLAGS" % libdir)
99116
self.variables.nappend('LDFLAGS', [libdir])

easybuild/toolchains/fft/fujitsufftw.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,4 @@
3333
class FujitsuFFTW(Fftw):
3434
"""Fujitsu FFTW FFT library"""
3535

36-
FFT_MODULE_NAME = ['FFTW3-sve']
3736
FFTW_API_VERSION = '3'

easybuild/toolchains/fujitsu.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,3 @@ class Fujitsu(Ffmpi, FujitsuFFTW, FujitsuSSL):
3636
"""Compiler toolchain for Fujitsu."""
3737
NAME = 'Fujitsu'
3838
SUBTOOLCHAIN = Ffmpi.NAME
39-
COMPILER_MODULE_NAME = []

easybuild/tools/github.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ def reasons_for_closing(pr_data):
12321232

12331233
robot_paths = build_option('robot_path')
12341234

1235-
pr_files = [path for path in fetch_easyconfigs_from_pr(pr_data['number']) if path.endswith('.eb')]
1235+
pr_files = [p for p in fetch_easyconfigs_from_pr(pr_data['number']) if p.endswith('.eb')]
12361236

12371237
obsoleted = []
12381238
uses_archived_tc = []
@@ -1491,17 +1491,17 @@ def add_pr_labels(pr, branch=GITHUB_DEVELOP_BRANCH):
14911491

14921492
download_repo_path = download_repo(branch=branch, path=tmpdir)
14931493

1494-
pr_files = [path for path in fetch_easyconfigs_from_pr(pr) if path.endswith('.eb')]
1494+
pr_files = [p for p in fetch_easyconfigs_from_pr(pr) if p.endswith('.eb')]
14951495

14961496
file_info = det_file_info(pr_files, download_repo_path)
14971497

14981498
pr_target_account = build_option('pr_target_account')
14991499
github_user = build_option('github_user')
15001500
pr_data, _ = fetch_pr_data(pr, pr_target_account, pr_target_repo, github_user)
1501-
pr_labels = [label['name'] for label in pr_data['labels']]
1501+
pr_labels = [x['name'] for x in pr_data['labels']]
15021502

15031503
expected_labels = det_pr_labels(file_info, pr_target_repo)
1504-
missing_labels = [label for label in expected_labels if label not in pr_labels]
1504+
missing_labels = [x for x in expected_labels if x not in pr_labels]
15051505

15061506
dry_run = build_option('dry_run') or build_option('extended_dry_run')
15071507

easybuild/tools/hooks.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858

5959
START = 'start'
6060
PARSE = 'parse'
61+
MODULE_WRITE = 'module_write'
6162
END = 'end'
6263

6364
PRE_PREF = 'pre_'
@@ -69,7 +70,7 @@
6970
INSTALL_STEP, EXTENSIONS_STEP, POSTPROC_STEP, SANITYCHECK_STEP, CLEANUP_STEP, MODULE_STEP,
7071
PERMISSIONS_STEP, PACKAGE_STEP, TESTCASES_STEP]
7172

72-
HOOK_NAMES = [START, PARSE] + [p + s for s in STEP_NAMES for p in [PRE_PREF, POST_PREF]] + [END]
73+
HOOK_NAMES = [START, PARSE, MODULE_WRITE] + [p + s for s in STEP_NAMES for p in [PRE_PREF, POST_PREF]] + [END]
7374
KNOWN_HOOKS = [h + HOOK_SUFF for h in HOOK_NAMES]
7475

7576

@@ -99,7 +100,7 @@ def load_hooks(hooks_path):
99100
if attr.endswith(HOOK_SUFF):
100101
hook = getattr(imported_hooks, attr)
101102
if callable(hook):
102-
hooks.update({attr: hook})
103+
hooks[attr] = hook
103104
else:
104105
_log.debug("Skipping non-callable attribute '%s' when loading hooks", attr)
105106
_log.info("Found hooks: %s", sorted(hooks.keys()))
@@ -119,11 +120,8 @@ def load_hooks(hooks_path):
119120

120121

121122
def verify_hooks(hooks):
122-
"""Check whether list of obtained hooks only includes known hooks."""
123-
unknown_hooks = []
124-
for key in sorted(hooks):
125-
if key not in KNOWN_HOOKS:
126-
unknown_hooks.append(key)
123+
"""Check whether obtained hooks only includes known hooks."""
124+
unknown_hooks = [key for key in sorted(hooks) if key not in KNOWN_HOOKS]
127125

128126
if unknown_hooks:
129127
error_lines = ["Found one or more unknown hooks:"]
@@ -147,7 +145,7 @@ def find_hook(label, hooks, pre_step_hook=False, post_step_hook=False):
147145
Find hook with specified label.
148146
149147
:param label: name of hook
150-
:param hooks: list of defined hooks
148+
:param hooks: dict of defined hooks
151149
:param pre_step_hook: indicates whether hook to run is a pre-step hook
152150
:param post_step_hook: indicates whether hook to run is a post-step hook
153151
"""
@@ -162,27 +160,26 @@ def find_hook(label, hooks, pre_step_hook=False, post_step_hook=False):
162160

163161
hook_name = hook_prefix + label + HOOK_SUFF
164162

165-
for key in hooks:
166-
if key == hook_name:
167-
_log.info("Found %s hook", hook_name)
168-
res = hooks[key]
169-
break
163+
res = hooks.get(hook_name)
164+
if res:
165+
_log.info("Found %s hook", hook_name)
170166

171167
return res
172168

173169

174170
def run_hook(label, hooks, pre_step_hook=False, post_step_hook=False, args=None, msg=None):
175171
"""
176-
Run hook with specified label.
172+
Run hook with specified label and return result of calling the hook or None.
177173
178174
:param label: name of hook
179-
:param hooks: list of defined hooks
175+
:param hooks: dict of defined hooks
180176
:param pre_step_hook: indicates whether hook to run is a pre-step hook
181177
:param post_step_hook: indicates whether hook to run is a post-step hook
182178
:param args: arguments to pass to hook function
183179
:param msg: custom message that is printed when hook is called
184180
"""
185181
hook = find_hook(label, hooks, pre_step_hook=pre_step_hook, post_step_hook=post_step_hook)
182+
res = None
186183
if hook:
187184
if args is None:
188185
args = []
@@ -197,4 +194,5 @@ def run_hook(label, hooks, pre_step_hook=False, post_step_hook=False, args=None,
197194
print_msg(msg)
198195

199196
_log.info("Running '%s' hook function (arguments: %s)...", hook.__name__, args)
200-
hook(*args)
197+
res = hook(*args)
198+
return res

easybuild/tools/options.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,7 @@ def set_up_configuration(args=None, logfile=None, testing=False, silent=False):
14641464

14651465
# map list of strings --from-pr value to list of integers
14661466
try:
1467-
from_prs = [int(pr_nr) for pr_nr in eb_go.options.from_pr]
1467+
from_prs = [int(x) for x in eb_go.options.from_pr]
14681468
except ValueError:
14691469
raise EasyBuildError("Argument to --from-pr must be a comma separated list of PR #s.")
14701470

@@ -1500,7 +1500,7 @@ def set_up_configuration(args=None, logfile=None, testing=False, silent=False):
15001500
# done here instead of in _postprocess_include because github integration requires build_options to be initialized
15011501
if eb_go.options.include_easyblocks_from_pr:
15021502
try:
1503-
easyblock_prs = [int(pr_nr) for pr_nr in eb_go.options.include_easyblocks_from_pr]
1503+
easyblock_prs = [int(x) for x in eb_go.options.include_easyblocks_from_pr]
15041504
except ValueError:
15051505
raise EasyBuildError("Argument to --include-easyblocks-from-pr must be a comma separated list of PR #s.")
15061506

0 commit comments

Comments
 (0)