Skip to content

Commit 1d757db

Browse files
committed
Merge branch '5.0.x' into feature/error-logging
2 parents e184b67 + 19964d3 commit 1d757db

33 files changed

+837
-243
lines changed

easybuild/framework/easyblock.py

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
from easybuild.tools.config import CHECKSUM_PRIORITY_JSON, DEFAULT_ENVVAR_USERS_MODULES
8181
from easybuild.tools.config import EASYBUILD_SOURCES_URL, EBPYTHONPREFIXES # noqa
8282
from easybuild.tools.config import FORCE_DOWNLOAD_ALL, FORCE_DOWNLOAD_PATCHES, FORCE_DOWNLOAD_SOURCES
83-
from easybuild.tools.config import PYTHONPATH, SEARCH_PATH_BIN_DIRS, SEARCH_PATH_LIB_DIRS
83+
from easybuild.tools.config import MOD_SEARCH_PATH_HEADERS, PYTHONPATH, SEARCH_PATH_BIN_DIRS, SEARCH_PATH_LIB_DIRS
8484
from easybuild.tools.config import build_option, build_path, get_failed_install_build_dirs_path
8585
from easybuild.tools.config import get_failed_install_logs_path, get_log_filename, get_repository, get_repositorypath
8686
from easybuild.tools.config import install_path, log_path, package_path, source_paths
@@ -104,7 +104,7 @@
104104
from easybuild.tools.module_generator import ModuleGeneratorLua, ModuleGeneratorTcl, module_generator, dependencies_for
105105
from easybuild.tools.module_naming_scheme.utilities import det_full_ec_version
106106
from easybuild.tools.modules import ROOT_ENV_VAR_NAME_PREFIX, VERSION_ENV_VAR_NAME_PREFIX, DEVEL_ENV_VAR_NAME_PREFIX
107-
from easybuild.tools.modules import Lmod, ModEnvVarType, ModuleLoadEnvironment
107+
from easybuild.tools.modules import Lmod, ModEnvVarType, ModuleLoadEnvironment, MODULE_LOAD_ENV_HEADERS
108108
from easybuild.tools.modules import curr_module_paths, invalidate_module_caches_for, get_software_root
109109
from easybuild.tools.modules import get_software_root_env_var_name, get_software_version_env_var_name
110110
from easybuild.tools.output import PROGRESS_BAR_DOWNLOAD_ALL, PROGRESS_BAR_EASYCONFIG, PROGRESS_BAR_EXTENSIONS
@@ -137,8 +137,9 @@ class LibSymlink(Enum):
137137
- LIB_TO_LIB64: 'lib' is a symlink to 'lib64'
138138
- LIB64_TO_LIB: 'lib64' is a symlink to 'lib'
139139
- NEITHER: neither 'lib' is a symlink to 'lib64', nor 'lib64' is a symlink to 'lib'
140+
- BOTH_TO_DIR: 'lib' and 'lib64' are symlinks to some other directory
140141
- """
141-
LIB_TO_LIB64, LIB64_TO_LIB, NEITHER = range(3)
142+
LIB_TO_LIB64, LIB64_TO_LIB, NEITHER, BOTH_TO_DIR = range(4)
142143

143144

144145
class EasyBlock(object):
@@ -224,7 +225,19 @@ def __init__(self, ec, logfile=None):
224225
self.modules_header = read_file(modules_header_path)
225226

226227
# environment variables on module load
227-
self.module_load_environment = ModuleLoadEnvironment()
228+
mod_load_aliases = {}
229+
# apply --module-search-path-headers: easyconfig parameter has precedence
230+
mod_load_cpp_headers = self.cfg['module_search_path_headers'] or build_option('module_search_path_headers')
231+
232+
try:
233+
mod_load_aliases[MODULE_LOAD_ENV_HEADERS] = MOD_SEARCH_PATH_HEADERS[mod_load_cpp_headers]
234+
except KeyError as err:
235+
raise EasyBuildError(
236+
f"Unknown value selected for option module-search-path-headers: {mod_load_cpp_headers}. "
237+
f"Choose one of: {', '.join(MOD_SEARCH_PATH_HEADERS)}"
238+
) from err
239+
240+
self.module_load_environment = ModuleLoadEnvironment(aliases=mod_load_aliases)
228241

229242
# determine install subdirectory, based on module name
230243
self.install_subdir = None
@@ -331,6 +344,7 @@ def post_init(self):
331344
# but needs to be correct if the build is performed in the installation directory
332345
self.log.info("Changing build dir to %s", self.installdir)
333346
self.builddir = self.installdir
347+
self.set_parallel()
334348

335349
# INIT/CLOSE LOG
336350
def _init_log(self):
@@ -1672,12 +1686,12 @@ def make_module_req(self):
16721686

16731687
if self.make_module_req_guess.__qualname__ != "EasyBlock.make_module_req_guess":
16741688
# Deprecated make_module_req_guess method used in child Easyblock
1675-
# Update environment with custom make_module_req_guess
1689+
# adjust environment with custom make_module_req_guess
16761690
self.log.deprecated(
16771691
"make_module_req_guess() is deprecated, use EasyBlock.module_load_environment instead.",
16781692
"6.0",
16791693
)
1680-
self.module_load_environment.update(self.make_module_req_guess())
1694+
self.module_load_environment.replace(self.make_module_req_guess())
16811695

16821696
# Expand and inject path-like environment variables into module file
16831697
env_var_requirements = {
@@ -1764,7 +1778,9 @@ def check_install_lib_symlink(self):
17641778

17651779
self._install_lib_symlink = LibSymlink.NEITHER
17661780
if os.path.exists(lib_dir) and os.path.exists(lib64_dir):
1767-
if os.path.islink(lib_dir) and os.path.samefile(lib_dir, lib64_dir):
1781+
if os.path.islink(lib_dir) and os.path.islink(lib64_dir):
1782+
self._install_lib_symlink = LibSymlink.BOTH_TO_DIR
1783+
elif os.path.islink(lib_dir) and os.path.samefile(lib_dir, lib64_dir):
17681784
self._install_lib_symlink = LibSymlink.LIB_TO_LIB64
17691785
elif os.path.islink(lib64_dir) and os.path.samefile(lib_dir, lib64_dir):
17701786
self._install_lib_symlink = LibSymlink.LIB64_TO_LIB
@@ -1967,7 +1983,7 @@ def skip_extensions_parallel(self, exts_filter):
19671983
exts_cnt = len(self.ext_instances)
19681984
cmds = [resolve_exts_filter_template(exts_filter, ext) for ext in self.ext_instances]
19691985

1970-
with ThreadPoolExecutor(max_workers=self.cfg['parallel']) as thread_pool:
1986+
with ThreadPoolExecutor(max_workers=self.cfg.parallel) as thread_pool:
19711987

19721988
# list of command to run asynchronously
19731989
async_cmds = [thread_pool.submit(run_shell_cmd, cmd, stdin=stdin, hidden=True, fail_on_error=False,
@@ -2097,7 +2113,7 @@ def install_extensions_parallel(self, install=True):
20972113
"""
20982114
self.log.info("Installing extensions in parallel...")
20992115

2100-
thread_pool = ThreadPoolExecutor(max_workers=self.cfg['parallel'])
2116+
thread_pool = ThreadPoolExecutor(max_workers=self.cfg.parallel)
21012117

21022118
running_exts = []
21032119
installed_ext_names = []
@@ -2159,7 +2175,7 @@ def update_exts_progress_bar_helper(running_exts, progress_size):
21592175

21602176
for _ in range(max_iter):
21612177

2162-
if not (exts_queue and len(running_exts) < self.cfg['parallel']):
2178+
if not (exts_queue and len(running_exts) < self.cfg.parallel):
21632179
break
21642180

21652181
# check whether extension at top of the queue is ready to install
@@ -2398,19 +2414,21 @@ def set_parallel(self):
23982414
"""Set 'parallel' easyconfig parameter to determine how many cores can/should be used for parallel builds."""
23992415
# set level of parallelism for build
24002416
par = build_option('parallel')
2401-
cfg_par = self.cfg['parallel']
2402-
if cfg_par is None:
2417+
if par is not None:
24032418
self.log.debug("Desired parallelism specified via 'parallel' build option: %s", par)
2404-
elif par is None:
2405-
par = cfg_par
2406-
self.log.debug("Desired parallelism specified via 'parallel' easyconfig parameter: %s", par)
2407-
else:
2408-
par = min(int(par), int(cfg_par))
2409-
self.log.debug("Desired parallelism: minimum of 'parallel' build option/easyconfig parameter: %s", par)
24102419

2411-
par = det_parallelism(par, maxpar=self.cfg['maxparallel'])
2412-
self.log.info("Setting parallelism: %s" % par)
2413-
self.cfg['parallel'] = par
2420+
# Transitional only in case some easyblocks still set/change cfg['parallel']
2421+
# Use _parallelLegacy to avoid deprecation warnings
2422+
cfg_par = self.cfg['_parallelLegacy']
2423+
if cfg_par is not None:
2424+
if par is None:
2425+
par = cfg_par
2426+
else:
2427+
par = min(int(par), int(cfg_par))
2428+
2429+
par = det_parallelism(par=par, maxpar=self.cfg['max_parallel'])
2430+
self.log.info(f"Setting parallelism: {par}")
2431+
self.cfg.parallel = par
24142432

24152433
def remove_module_file(self):
24162434
"""Remove module file (if it exists), and check for ghost installation directory (and deal with it)."""
@@ -2456,8 +2474,6 @@ def check_readiness_step(self):
24562474
"""
24572475
Verify if all is ok to start build.
24582476
"""
2459-
self.set_parallel()
2460-
24612477
# check whether modules are loaded
24622478
loadedmods = self.modules_tool.loaded_modules()
24632479
if len(loadedmods) > 0:
@@ -3329,8 +3345,8 @@ def sanity_check_rpath(self, rpath_dirs=None, check_readelf_rpath=True):
33293345
# For example, libcuda.so.1 should never be RPATH-ed by design,
33303346
# see https://github.com/easybuilders/easybuild-framework/issues/4095
33313347
filter_rpath_sanity_libs = build_option('filter_rpath_sanity_libs')
3332-
msg = "Ignoring the following libraries if they are not found by RPATH sanity check: {filter_rpath_sanity_libs}"
3333-
self.log.info(msg)
3348+
self.log.info("Ignoring the following libraries if they are not found by RPATH sanity check: %s",
3349+
filter_rpath_sanity_libs)
33343350

33353351
if rpath_dirs is None:
33363352
rpath_dirs = self.cfg['bin_lib_subdirs'] or self.bin_lib_subdirs()
@@ -4520,7 +4536,7 @@ def build_and_install_one(ecdict, init_env):
45204536
try:
45214537
app_class = get_easyblock_class(easyblock, name=name)
45224538
app = app_class(ecdict['ec'])
4523-
_log.info("Obtained application instance of for %s (easyblock: %s)" % (name, easyblock))
4539+
_log.info("Obtained application instance for %s (easyblock: %s)" % (name, easyblock))
45244540
except EasyBuildError as err:
45254541
print_error("Failed to get application instance for %s (easyblock: %s): %s" % (name, easyblock, err.msg),
45264542
silent=silent)
@@ -4602,7 +4618,7 @@ def ensure_writable_log_dir(log_dir):
46024618
adjust_permissions(log_dir, stat.S_IWUSR, add=True, recursive=True)
46034619
else:
46044620
parent_dir = os.path.dirname(log_dir)
4605-
if os.path.exists(parent_dir):
4621+
if os.path.exists(parent_dir) and not (os.stat(parent_dir).st_mode & stat.S_IWUSR):
46064622
adjust_permissions(parent_dir, stat.S_IWUSR, add=True, recursive=False)
46074623
mkdir(log_dir, parents=True)
46084624
adjust_permissions(parent_dir, stat.S_IWUSR, add=False, recursive=False)
@@ -4683,7 +4699,7 @@ def ensure_writable_log_dir(log_dir):
46834699
copy_file(patch['path'], target)
46844700
_log.debug("Copied patch %s to %s", patch['path'], target)
46854701

4686-
if build_option('read_only_installdir'):
4702+
if build_option('read_only_installdir') and not app.cfg['stop']:
46874703
# take away user write permissions (again)
46884704
perms = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH
46894705
adjust_permissions(new_log_dir, perms, add=False, recursive=True)

easybuild/framework/easyconfig/default.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,8 @@
108108
BUILD],
109109
'hidden': [False, "Install module file as 'hidden' by prefixing its version with '.'", BUILD],
110110
'installopts': ['', 'Extra options for installation', BUILD],
111-
'maxparallel': [16, 'Max degree of parallelism', BUILD],
111+
'maxparallel': [None, 'Max degree of parallelism', BUILD],
112112
'module_only': [False, 'Only generate module file', BUILD],
113-
'parallel': [None, ('Degree of parallelism for e.g. make (default: based on the number of '
114-
'cores, active cpuset and restrictions in ulimit)'), BUILD],
115113
'patches': [[], "List of patches to apply", BUILD],
116114
'prebuildopts': ['', 'Extra options pre-passed to build command.', BUILD],
117115
'preconfigopts': ['', 'Extra options pre-passed to configure.', BUILD],
@@ -156,8 +154,8 @@
156154
FILEMANAGEMENT],
157155
'keeppreviousinstall': [False, ('Boolean to keep the previous installation with identical '
158156
'name. Experts only!'), FILEMANAGEMENT],
159-
'keepsymlinks': [False, ('Boolean to determine whether symlinks are to be kept during copying '
160-
'or if the content of the files pointed to should be copied'),
157+
'keepsymlinks': [True, ('Boolean to determine whether symlinks are to be kept during copying '
158+
'or if the content of the files pointed to should be copied'),
161159
FILEMANAGEMENT],
162160
'start_dir': [None, ('Path to start the make in. If the path is absolute, use that path. '
163161
'If not, this is added to the guessed path.'), FILEMANAGEMENT],
@@ -208,10 +206,11 @@
208206
'moduleloadnoconflict': [False, "Don't check for conflicts, unload other versions instead ", MODULES],
209207
'module_depends_on': [None, 'Use depends_on (Lmod 7.6.1+) for dependencies in generated module '
210208
'(implies recursive unloading of modules) [DEPRECATED]', MODULES],
209+
'module_search_path_headers': [None, "Environment variable set by modules on load "
210+
"with search paths to header files (if None, use $CPATH)", MODULES],
211211
'recursive_module_unload': [None, "Recursive unload of all dependencies when unloading module "
212-
"(True/False to hard enable/disable; None implies honoring "
213-
"the --recursive-module-unload EasyBuild configuration setting",
214-
MODULES],
212+
"(True/False to hard enable/disable; None implies honoring the "
213+
"--recursive-module-unload EasyBuild configuration setting", MODULES],
215214

216215
# MODULES documentation easyconfig parameters
217216
# (docurls is part of MANDATORY)

0 commit comments

Comments
 (0)