Skip to content

Commit d278319

Browse files
author
SebastianAchilles
authored
Merge pull request #4042 from easybuilders/4.6.x
release EasyBuild v4.6.0
2 parents f3b642b + 738640c commit d278319

File tree

27 files changed

+547
-112
lines changed

27 files changed

+547
-112
lines changed

.github/workflows/bootstrap_script.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jobs:
66
runs-on: ubuntu-latest
77
outputs:
88
lmod7: Lmod-7.8.22
9-
lmod8: Lmod-8.4.27
9+
lmod8: Lmod-8.7.6
1010
modulesTcl: modules-tcl-1.147
1111
modules3: modules-3.2.10
1212
modules4: modules-4.1.4

.github/workflows/container_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
cd $HOME
4040
export INSTALL_DEP=$GITHUB_WORKSPACE/easybuild/scripts/install_eb_dep.sh
4141
# install Lmod
42-
source $INSTALL_DEP Lmod-8.4.27 $HOME
42+
source $INSTALL_DEP Lmod-8.7.6 $HOME
4343
# changes in environment are not passed to other steps, so need to create files...
4444
echo $MOD_INIT > mod_init
4545
echo $PATH > path

.github/workflows/eb_command.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
cd $HOME
3939
export INSTALL_DEP=$GITHUB_WORKSPACE/easybuild/scripts/install_eb_dep.sh
4040
# install Lmod
41-
source $INSTALL_DEP Lmod-8.4.26 $HOME
41+
source $INSTALL_DEP Lmod-8.7.6 $HOME
4242
# changes in environment are not passed to other steps, so need to create files...
4343
echo $MOD_INIT > mod_init
4444
echo $PATH > path

.github/workflows/unit_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jobs:
66
runs-on: ubuntu-latest
77
outputs:
88
lmod7: Lmod-7.8.22
9-
lmod8: Lmod-8.4.27
9+
lmod8: Lmod-8.7.6
1010
modulesTcl: modules-tcl-1.147
1111
modules3: modules-3.2.10
1212
modules4: modules-4.1.4

RELEASE_NOTES

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@ 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.6.0 (July 8th 2022)
8+
----------------------
9+
10+
feature release
11+
12+
- various enhancements, including:
13+
- allow searching for sources/patches in alternative location by specifying 'alt_location' in source/patch spec (#3994)
14+
- show URLs used for download attempts in trace output (#4026)
15+
- add support for setting environment variables via 'pushenv' with modextravars (#4030)
16+
- add support for OneAPI compilers using toolchain option 'oneapi' (#4031, #4032, #4039)
17+
- make check_linked_shared_libs more robust by taking into account that 'ldd' may fail (#4033)
18+
- fall back to sequential extension install if parallel install is not implemented (#4034)
19+
- add support for using template values in name/version of extensions (#4036)
20+
- various bug fixes, including:
21+
- make sure that ARCH constant has 'aarch64' (rather than 'arm64') as value on macOS ARM (#4018)
22+
- tweak 'eb' wrapper script to correctly handle errors when python command being considered fails to run (#4019)
23+
- tweak is_patch_for function to make it more robust (#4028)
24+
- other changes:
25+
- update Lmod used to run tests to version 8.7.6 (#4027, #4030)
26+
- tweak apply_patch to not create .orig files (by default) when applying patch files (#4038)
27+
28+
729
v4.5.5 (June 8th 2022)
830
----------------------
931

easybuild/framework/easyblock.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ def fetch_source(self, source, checksum=None, extension=False, download_instruct
373373
:param checksum: checksum corresponding to source
374374
:param extension: flag if being called from collect_exts_file_info()
375375
"""
376-
filename, download_filename, extract_cmd, source_urls, git_config = None, None, None, None, None
376+
filename, download_filename, extract_cmd = None, None, None
377+
source_urls, git_config, alt_location = None, None, None
377378

378379
if source is None:
379380
raise EasyBuildError("fetch_source called with empty 'source' argument")
@@ -387,6 +388,7 @@ def fetch_source(self, source, checksum=None, extension=False, download_instruct
387388
download_filename = source.pop('download_filename', None)
388389
source_urls = source.pop('source_urls', None)
389390
git_config = source.pop('git_config', None)
391+
alt_location = source.pop('alt_location', None)
390392
if source:
391393
raise EasyBuildError("Found one or more unexpected keys in 'sources' specification: %s", source)
392394

@@ -401,7 +403,7 @@ def fetch_source(self, source, checksum=None, extension=False, download_instruct
401403
force_download = build_option('force_download') in [FORCE_DOWNLOAD_ALL, FORCE_DOWNLOAD_SOURCES]
402404
path = self.obtain_file(filename, extension=extension, download_filename=download_filename,
403405
force_download=force_download, urls=source_urls, git_config=git_config,
404-
download_instructions=download_instructions)
406+
download_instructions=download_instructions, alt_location=alt_location)
405407
if path is None:
406408
raise EasyBuildError('No file found for source %s', filename)
407409

@@ -468,7 +470,9 @@ def fetch_patches(self, patch_specs=None, extension=False, checksums=None):
468470
patch_info['postinstall'] = patch_spec in post_install_patches
469471

470472
force_download = build_option('force_download') in [FORCE_DOWNLOAD_ALL, FORCE_DOWNLOAD_PATCHES]
471-
path = self.obtain_file(patch_info['name'], extension=extension, force_download=force_download)
473+
alt_location = patch_info.pop('alt_location', None)
474+
path = self.obtain_file(patch_info['name'], extension=extension, force_download=force_download,
475+
alt_location=alt_location)
472476
if path:
473477
self.log.debug('File %s found for patch %s', path, patch_spec)
474478
patch_info['path'] = path
@@ -517,11 +521,13 @@ def collect_exts_file_info(self, fetch_files=True, verify_checksums=True):
517521
for ext in exts_list:
518522
if isinstance(ext, (list, tuple)) and ext:
519523
# expected format: (name, version, options (dict))
520-
ext_name = ext[0]
524+
# name and version can use templates, resolved via parent EC
525+
526+
ext_name = resolve_template(ext[0], self.cfg.template_values)
521527
if len(ext) == 1:
522528
exts_sources.append({'name': ext_name})
523529
else:
524-
ext_version = ext[1]
530+
ext_version = resolve_template(ext[1], self.cfg.template_values)
525531

526532
# make sure we grab *raw* dict of default options for extension,
527533
# since it may use template values like %(name)s & %(version)s
@@ -687,7 +693,7 @@ def collect_exts_file_info(self, fetch_files=True, verify_checksums=True):
687693
return exts_sources
688694

689695
def obtain_file(self, filename, extension=False, urls=None, download_filename=None, force_download=False,
690-
git_config=None, download_instructions=None):
696+
git_config=None, download_instructions=None, alt_location=None):
691697
"""
692698
Locate the file with the given name
693699
- searches in different subdirectories of source path
@@ -698,11 +704,18 @@ def obtain_file(self, filename, extension=False, urls=None, download_filename=No
698704
:param download_filename: filename with which the file should be downloaded, and then renamed to <filename>
699705
:param force_download: always try to download file, even if it's already available in source path
700706
:param git_config: dictionary to define how to download a git repository
707+
:param download_instructions: instructions to manually add source (used for complex cases)
708+
:param alt_location: alternative location to use instead of self.name
701709
"""
702710
srcpaths = source_paths()
703711

704712
update_progress_bar(PROGRESS_BAR_DOWNLOAD_ALL, label=filename)
705713

714+
if alt_location is None:
715+
location = self.name
716+
else:
717+
location = alt_location
718+
706719
# should we download or just try and find it?
707720
if re.match(r"^(https?|ftp)://", filename):
708721
# URL detected, so let's try and download it
@@ -711,7 +724,7 @@ def obtain_file(self, filename, extension=False, urls=None, download_filename=No
711724
filename = url.split('/')[-1]
712725

713726
# figure out where to download the file to
714-
filepath = os.path.join(srcpaths[0], letter_dir_for(self.name), self.name)
727+
filepath = os.path.join(srcpaths[0], letter_dir_for(location), location)
715728
if extension:
716729
filepath = os.path.join(filepath, "extensions")
717730
self.log.info("Creating path %s to download file to" % filepath)
@@ -750,8 +763,8 @@ def obtain_file(self, filename, extension=False, urls=None, download_filename=No
750763

751764
for path in ebpath + common_filepaths + srcpaths:
752765
# create list of candidate filepaths
753-
namepath = os.path.join(path, self.name)
754-
letterpath = os.path.join(path, letter_dir_for(self.name), self.name)
766+
namepath = os.path.join(path, location)
767+
letterpath = os.path.join(path, letter_dir_for(location), location)
755768

756769
# most likely paths
757770
candidate_filepaths = [
@@ -790,8 +803,8 @@ def obtain_file(self, filename, extension=False, urls=None, download_filename=No
790803

791804
break # no need to try other source paths
792805

793-
name_letter = self.name.lower()[0]
794-
targetdir = os.path.join(srcpaths[0], name_letter, self.name)
806+
name_letter = location.lower()[0]
807+
targetdir = os.path.join(srcpaths[0], name_letter, location)
795808

796809
if foundfile:
797810
if self.dry_run:
@@ -808,7 +821,7 @@ def obtain_file(self, filename, extension=False, urls=None, download_filename=No
808821
source_urls.extend(self.cfg['source_urls'])
809822

810823
# add https://sources.easybuild.io as fallback source URL
811-
source_urls.append(EASYBUILD_SOURCES_URL + '/' + os.path.join(name_letter, self.name))
824+
source_urls.append(EASYBUILD_SOURCES_URL + '/' + os.path.join(name_letter, location))
812825

813826
mkdir(targetdir, parents=True)
814827

@@ -1754,7 +1767,13 @@ def install_extensions(self, install=True):
17541767

17551768
if build_option('parallel_extensions_install'):
17561769
self.log.experimental("installing extensions in parallel")
1757-
self.install_extensions_parallel(install=install)
1770+
try:
1771+
self.install_extensions_parallel(install=install)
1772+
except NotImplementedError:
1773+
# If parallel extension install is not supported for this type of extension then install sequentially
1774+
msg = "Parallel extensions install not supported for %s - using sequential install" % self.name
1775+
self.log.experimental(msg)
1776+
self.install_extensions_sequential(install=install)
17581777
else:
17591778
self.install_extensions_sequential(install=install)
17601779

easybuild/framework/easyconfig/constants.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,35 @@
3434
import platform
3535

3636
from easybuild.base import fancylogger
37-
from easybuild.tools.systemtools import get_os_name, get_os_type, get_os_version
37+
from easybuild.tools.build_log import print_warning
38+
from easybuild.tools.systemtools import KNOWN_ARCH_CONSTANTS, get_os_name, get_os_type, get_os_version
3839

3940

4041
_log = fancylogger.getLogger('easyconfig.constants', fname=False)
4142

4243

4344
EXTERNAL_MODULE_MARKER = 'EXTERNAL_MODULE'
4445

46+
47+
def _get_arch_constant():
48+
"""
49+
Get value for ARCH constant.
50+
"""
51+
arch = platform.uname()[4]
52+
53+
# macOS on Arm produces 'arm64' rather than 'aarch64'
54+
if arch == 'arm64':
55+
arch = 'aarch64'
56+
57+
if arch not in KNOWN_ARCH_CONSTANTS:
58+
print_warning("Using unknown value for ARCH constant: %s", arch)
59+
60+
return arch
61+
62+
4563
# constants that can be used in easyconfig
4664
EASYCONFIG_CONSTANTS = {
47-
'ARCH': (platform.uname()[4], "CPU architecture of current system (aarch64, x86_64, ppc64le, ...)"),
65+
'ARCH': (_get_arch_constant(), "CPU architecture of current system (aarch64, x86_64, ppc64le, ...)"),
4866
'EXTERNAL_MODULE': (EXTERNAL_MODULE_MARKER, "External module marker"),
4967
'HOME': (os.path.expanduser('~'), "Home directory ($HOME)"),
5068
'OS_TYPE': (get_os_type(), "System type (e.g. 'Linux' or 'Darwin')"),

easybuild/toolchains/compiler/intel_compilers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"""
3030
import os
3131

32+
from distutils.version import LooseVersion
33+
3234
from easybuild.toolchains.compiler.inteliccifort import IntelIccIfort
3335
from easybuild.tools.toolchain.compiler import Compiler
3436

@@ -39,6 +41,8 @@ class IntelCompilers(IntelIccIfort):
3941
"""
4042

4143
COMPILER_MODULE_NAME = ['intel-compilers']
44+
COMPILER_UNIQUE_OPTS = dict(IntelIccIfort.COMPILER_UNIQUE_OPTS,
45+
oneapi=(False, "Use oneAPI compilers icx/icpx/ifx instead of classic compilers"))
4246

4347
def _set_compiler_vars(self):
4448
"""Intel compilers-specific adjustments after setting compiler variables."""
@@ -59,5 +63,22 @@ def _set_compiler_vars(self):
5963
def set_variables(self):
6064
"""Set the variables."""
6165

66+
if self.options.get('oneapi', False):
67+
self.COMPILER_CXX = 'icpx'
68+
self.COMPILER_CC = 'icx'
69+
self.COMPILER_F77 = 'ifx'
70+
self.COMPILER_F90 = 'ifx'
71+
self.COMPILER_FC = 'ifx'
72+
# fp-model source is not supported by icx but is equivalent to precise
73+
self.options.options_map['defaultprec'] = ['fp-speculation=safe', 'fp-model precise']
74+
if LooseVersion(self.get_software_version(self.COMPILER_MODULE_NAME)[0]) >= LooseVersion('2022'):
75+
self.options.options_map['defaultprec'].insert(0, 'ftz')
76+
# icx doesn't like -fp-model fast=1; fp-model fast is equivalent
77+
self.options.options_map['loose'] = ['fp-model fast']
78+
# fp-model fast=2 gives "warning: overriding '-ffp-model=fast=2' option with '-ffp-model=fast'"
79+
self.options.options_map['veryloose'] = ['fp-model fast']
80+
# recommended in porting guide
81+
self.options.options_map['openmp'] = ['fiopenmp']
82+
6283
# skip IntelIccIfort.set_variables (no longer relevant for recent versions)
6384
Compiler.set_variables(self)

easybuild/tools/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
250250
'add_dummy_to_minimal_toolchains',
251251
'add_system_to_minimal_toolchains',
252252
'allow_modules_tool_mismatch',
253+
'backup_patched_files',
253254
'consider_archived_easyconfigs',
254255
'container_build_image',
255256
'debug',

easybuild/tools/filetools.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
from easybuild.tools.config import build_option, install_path
6666
from easybuild.tools.output import PROGRESS_BAR_DOWNLOAD_ONE, start_progress_bar, stop_progress_bar, update_progress_bar
6767
from easybuild.tools.py2vs3 import HTMLParser, std_urllib, string_type
68-
from easybuild.tools.utilities import natural_keys, nub, remove_unwanted_chars
68+
from easybuild.tools.utilities import natural_keys, nub, remove_unwanted_chars, trace_msg
6969

7070
try:
7171
import requests
@@ -856,9 +856,11 @@ def download_file(filename, url, path, forced=False):
856856

857857
if downloaded:
858858
_log.info("Successful download of file %s from url %s to path %s" % (filename, url, path))
859+
trace_msg("download succeeded: %s" % url)
859860
return path
860861
else:
861862
_log.warning("Download of %s to %s failed, done trying" % (url, path))
863+
trace_msg("download failed: %s" % url)
862864
return None
863865

864866

@@ -1469,6 +1471,9 @@ def create_patch_info(patch_spec):
14691471
"""
14701472
Create info dictionary from specified patch spec.
14711473
"""
1474+
# Valid keys that can be used in a patch spec dict
1475+
valid_keys = ['name', 'copy', 'level', 'sourcepath', 'alt_location']
1476+
14721477
if isinstance(patch_spec, (list, tuple)):
14731478
if not len(patch_spec) == 2:
14741479
error_msg = "Unknown patch specification '%s', only 2-element lists/tuples are supported!"
@@ -1495,19 +1500,44 @@ def create_patch_info(patch_spec):
14951500
str(patch_spec))
14961501

14971502
elif isinstance(patch_spec, string_type):
1498-
allowed_patch_exts = ['.patch' + x for x in ('',) + ZIPPED_PATCH_EXTS]
1499-
if not any(patch_spec.endswith(x) for x in allowed_patch_exts):
1500-
msg = "Use of patch file with filename that doesn't end with correct extension: %s " % patch_spec
1501-
msg += "(should be any of: %s)" % (', '.join(allowed_patch_exts))
1502-
_log.deprecated(msg, '5.0')
1503+
validate_patch_spec(patch_spec)
15031504
patch_info = {'name': patch_spec}
1505+
elif isinstance(patch_spec, dict):
1506+
patch_info = {}
1507+
for key in patch_spec.keys():
1508+
if key in valid_keys:
1509+
patch_info[key] = patch_spec[key]
1510+
else:
1511+
raise EasyBuildError("Wrong patch spec '%s', use of unknown key %s in dict (valid keys are %s)",
1512+
str(patch_spec), key, valid_keys)
1513+
1514+
# Dict must contain at least the patchfile name
1515+
if 'name' not in patch_info.keys():
1516+
raise EasyBuildError("Wrong patch spec '%s', when using a dict 'name' entry must be supplied",
1517+
str(patch_spec))
1518+
if 'copy' not in patch_info.keys():
1519+
validate_patch_spec(patch_info['name'])
1520+
else:
1521+
if 'sourcepath' in patch_info.keys() or 'level' in patch_info.keys():
1522+
raise EasyBuildError("Wrong patch spec '%s', you can't use 'sourcepath' or 'level' with 'copy' (since "
1523+
"this implies you want to copy a file to the 'copy' location)",
1524+
str(patch_spec))
15041525
else:
1505-
error_msg = "Wrong patch spec, should be string of 2-tuple with patch name + argument: %s"
1506-
raise EasyBuildError(error_msg, patch_spec)
1526+
error_msg = "Wrong patch spec, should be string, 2-tuple with patch name + argument, or a dict " \
1527+
"(with possible keys %s): %s" % (valid_keys, patch_spec)
1528+
raise EasyBuildError(error_msg)
15071529

15081530
return patch_info
15091531

15101532

1533+
def validate_patch_spec(patch_spec):
1534+
allowed_patch_exts = ['.patch' + x for x in ('',) + ZIPPED_PATCH_EXTS]
1535+
if not any(patch_spec.endswith(x) for x in allowed_patch_exts):
1536+
msg = "Use of patch file with filename that doesn't end with correct extension: %s " % patch_spec
1537+
msg += "(should be any of: %s)" % (', '.join(allowed_patch_exts))
1538+
_log.deprecated(msg, '5.0')
1539+
1540+
15111541
def apply_patch(patch_file, dest, fn=None, copy=False, level=None, use_git_am=False, use_git=False):
15121542
"""
15131543
Apply a patch to source code in directory dest
@@ -1592,7 +1622,8 @@ def apply_patch(patch_file, dest, fn=None, copy=False, level=None, use_git_am=Fa
15921622
else:
15931623
_log.debug("Using specified patch level %d for patch %s" % (level, patch_file))
15941624

1595-
patch_cmd = "patch -b -p%s -i %s" % (level, abs_patch_file)
1625+
backup_option = '-b ' if build_option('backup_patched_files') else ''
1626+
patch_cmd = "patch " + backup_option + "-p%s -i %s" % (level, abs_patch_file)
15961627

15971628
out, ec = run.run_cmd(patch_cmd, simple=False, path=abs_dest, log_ok=False, trace=False)
15981629

0 commit comments

Comments
 (0)