|
80 | 80 | from easybuild.tools.config import CHECKSUM_PRIORITY_JSON, DEFAULT_ENVVAR_USERS_MODULES |
81 | 81 | from easybuild.tools.config import EASYBUILD_SOURCES_URL, EBPYTHONPREFIXES # noqa |
82 | 82 | 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 |
84 | 84 | from easybuild.tools.config import build_option, build_path, get_failed_install_build_dirs_path |
85 | 85 | from easybuild.tools.config import get_failed_install_logs_path, get_log_filename, get_repository, get_repositorypath |
86 | 86 | from easybuild.tools.config import install_path, log_path, package_path, source_paths |
|
104 | 104 | from easybuild.tools.module_generator import ModuleGeneratorLua, ModuleGeneratorTcl, module_generator, dependencies_for |
105 | 105 | from easybuild.tools.module_naming_scheme.utilities import det_full_ec_version |
106 | 106 | 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 |
108 | 108 | from easybuild.tools.modules import curr_module_paths, invalidate_module_caches_for, get_software_root |
109 | 109 | from easybuild.tools.modules import get_software_root_env_var_name, get_software_version_env_var_name |
110 | 110 | from easybuild.tools.output import PROGRESS_BAR_DOWNLOAD_ALL, PROGRESS_BAR_EASYCONFIG, PROGRESS_BAR_EXTENSIONS |
@@ -137,8 +137,9 @@ class LibSymlink(Enum): |
137 | 137 | - LIB_TO_LIB64: 'lib' is a symlink to 'lib64' |
138 | 138 | - LIB64_TO_LIB: 'lib64' is a symlink to 'lib' |
139 | 139 | - 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 |
140 | 141 | - """ |
141 | | - LIB_TO_LIB64, LIB64_TO_LIB, NEITHER = range(3) |
| 142 | + LIB_TO_LIB64, LIB64_TO_LIB, NEITHER, BOTH_TO_DIR = range(4) |
142 | 143 |
|
143 | 144 |
|
144 | 145 | class EasyBlock(object): |
@@ -224,7 +225,19 @@ def __init__(self, ec, logfile=None): |
224 | 225 | self.modules_header = read_file(modules_header_path) |
225 | 226 |
|
226 | 227 | # 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) |
228 | 241 |
|
229 | 242 | # determine install subdirectory, based on module name |
230 | 243 | self.install_subdir = None |
@@ -331,6 +344,7 @@ def post_init(self): |
331 | 344 | # but needs to be correct if the build is performed in the installation directory |
332 | 345 | self.log.info("Changing build dir to %s", self.installdir) |
333 | 346 | self.builddir = self.installdir |
| 347 | + self.set_parallel() |
334 | 348 |
|
335 | 349 | # INIT/CLOSE LOG |
336 | 350 | def _init_log(self): |
@@ -1672,12 +1686,12 @@ def make_module_req(self): |
1672 | 1686 |
|
1673 | 1687 | if self.make_module_req_guess.__qualname__ != "EasyBlock.make_module_req_guess": |
1674 | 1688 | # 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 |
1676 | 1690 | self.log.deprecated( |
1677 | 1691 | "make_module_req_guess() is deprecated, use EasyBlock.module_load_environment instead.", |
1678 | 1692 | "6.0", |
1679 | 1693 | ) |
1680 | | - self.module_load_environment.update(self.make_module_req_guess()) |
| 1694 | + self.module_load_environment.replace(self.make_module_req_guess()) |
1681 | 1695 |
|
1682 | 1696 | # Expand and inject path-like environment variables into module file |
1683 | 1697 | env_var_requirements = { |
@@ -1764,7 +1778,9 @@ def check_install_lib_symlink(self): |
1764 | 1778 |
|
1765 | 1779 | self._install_lib_symlink = LibSymlink.NEITHER |
1766 | 1780 | 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): |
1768 | 1784 | self._install_lib_symlink = LibSymlink.LIB_TO_LIB64 |
1769 | 1785 | elif os.path.islink(lib64_dir) and os.path.samefile(lib_dir, lib64_dir): |
1770 | 1786 | self._install_lib_symlink = LibSymlink.LIB64_TO_LIB |
@@ -1967,7 +1983,7 @@ def skip_extensions_parallel(self, exts_filter): |
1967 | 1983 | exts_cnt = len(self.ext_instances) |
1968 | 1984 | cmds = [resolve_exts_filter_template(exts_filter, ext) for ext in self.ext_instances] |
1969 | 1985 |
|
1970 | | - with ThreadPoolExecutor(max_workers=self.cfg['parallel']) as thread_pool: |
| 1986 | + with ThreadPoolExecutor(max_workers=self.cfg.parallel) as thread_pool: |
1971 | 1987 |
|
1972 | 1988 | # list of command to run asynchronously |
1973 | 1989 | 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): |
2097 | 2113 | """ |
2098 | 2114 | self.log.info("Installing extensions in parallel...") |
2099 | 2115 |
|
2100 | | - thread_pool = ThreadPoolExecutor(max_workers=self.cfg['parallel']) |
| 2116 | + thread_pool = ThreadPoolExecutor(max_workers=self.cfg.parallel) |
2101 | 2117 |
|
2102 | 2118 | running_exts = [] |
2103 | 2119 | installed_ext_names = [] |
@@ -2159,7 +2175,7 @@ def update_exts_progress_bar_helper(running_exts, progress_size): |
2159 | 2175 |
|
2160 | 2176 | for _ in range(max_iter): |
2161 | 2177 |
|
2162 | | - if not (exts_queue and len(running_exts) < self.cfg['parallel']): |
| 2178 | + if not (exts_queue and len(running_exts) < self.cfg.parallel): |
2163 | 2179 | break |
2164 | 2180 |
|
2165 | 2181 | # check whether extension at top of the queue is ready to install |
@@ -2398,19 +2414,21 @@ def set_parallel(self): |
2398 | 2414 | """Set 'parallel' easyconfig parameter to determine how many cores can/should be used for parallel builds.""" |
2399 | 2415 | # set level of parallelism for build |
2400 | 2416 | par = build_option('parallel') |
2401 | | - cfg_par = self.cfg['parallel'] |
2402 | | - if cfg_par is None: |
| 2417 | + if par is not None: |
2403 | 2418 | 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) |
2410 | 2419 |
|
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 |
2414 | 2432 |
|
2415 | 2433 | def remove_module_file(self): |
2416 | 2434 | """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): |
2456 | 2474 | """ |
2457 | 2475 | Verify if all is ok to start build. |
2458 | 2476 | """ |
2459 | | - self.set_parallel() |
2460 | | - |
2461 | 2477 | # check whether modules are loaded |
2462 | 2478 | loadedmods = self.modules_tool.loaded_modules() |
2463 | 2479 | if len(loadedmods) > 0: |
@@ -3329,8 +3345,8 @@ def sanity_check_rpath(self, rpath_dirs=None, check_readelf_rpath=True): |
3329 | 3345 | # For example, libcuda.so.1 should never be RPATH-ed by design, |
3330 | 3346 | # see https://github.com/easybuilders/easybuild-framework/issues/4095 |
3331 | 3347 | 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) |
3334 | 3350 |
|
3335 | 3351 | if rpath_dirs is None: |
3336 | 3352 | rpath_dirs = self.cfg['bin_lib_subdirs'] or self.bin_lib_subdirs() |
@@ -4520,7 +4536,7 @@ def build_and_install_one(ecdict, init_env): |
4520 | 4536 | try: |
4521 | 4537 | app_class = get_easyblock_class(easyblock, name=name) |
4522 | 4538 | 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)) |
4524 | 4540 | except EasyBuildError as err: |
4525 | 4541 | print_error("Failed to get application instance for %s (easyblock: %s): %s" % (name, easyblock, err.msg), |
4526 | 4542 | silent=silent) |
@@ -4602,7 +4618,7 @@ def ensure_writable_log_dir(log_dir): |
4602 | 4618 | adjust_permissions(log_dir, stat.S_IWUSR, add=True, recursive=True) |
4603 | 4619 | else: |
4604 | 4620 | 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): |
4606 | 4622 | adjust_permissions(parent_dir, stat.S_IWUSR, add=True, recursive=False) |
4607 | 4623 | mkdir(log_dir, parents=True) |
4608 | 4624 | adjust_permissions(parent_dir, stat.S_IWUSR, add=False, recursive=False) |
@@ -4683,7 +4699,7 @@ def ensure_writable_log_dir(log_dir): |
4683 | 4699 | copy_file(patch['path'], target) |
4684 | 4700 | _log.debug("Copied patch %s to %s", patch['path'], target) |
4685 | 4701 |
|
4686 | | - if build_option('read_only_installdir'): |
| 4702 | + if build_option('read_only_installdir') and not app.cfg['stop']: |
4687 | 4703 | # take away user write permissions (again) |
4688 | 4704 | perms = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH |
4689 | 4705 | adjust_permissions(new_log_dir, perms, add=False, recursive=True) |
|
0 commit comments