From 22be21aeb0437fe19d7c639f556ac5467e31bfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 6 Mar 2023 09:58:28 +0000 Subject: [PATCH 01/59] adding easyblocks: cargo.py --- easybuild/easyblocks/generic/cargo.py | 129 ++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 easybuild/easyblocks/generic/cargo.py diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py new file mode 100644 index 0000000000..d59e0fee16 --- /dev/null +++ b/easybuild/easyblocks/generic/cargo.py @@ -0,0 +1,129 @@ +## +# Copyright 2009-2023 Ghent University +# +# This file is part of EasyBuild, +# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), +# with support of Ghent University (http://ugent.be/hpc), +# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be), +# Flemish Research Foundation (FWO) (http://www.fwo.be/en) +# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). +# +# https://github.com/easybuilders/easybuild +# +# EasyBuild is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation v2. +# +# EasyBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with EasyBuild. If not, see . +## +""" +EasyBuild support for installing Cargo packages (Rust lang package system) + +@author: Mikael Oehman (Chalmers University of Technology) +""" + +import os +import glob + +import easybuild.tools.environment as env +from easybuild.framework.easyconfig import CUSTOM +from easybuild.framework.easyblock import EasyBlock +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.run import run_cmd +from easybuild.tools.config import build_option +from easybuild.tools.filetools import remove_file, write_file, extract_file, compute_checksum + +CRATESIO_SOURCE = "https://crates.io/api/v1/crates" + +class Cargo(EasyBlock): + """Support for installing Cargo packages (Rust)""" + + @staticmethod + def extra_options(extra_vars=None): + """Define extra easyconfig parameters specific to Cargo""" + extra_vars = EasyBlock.extra_options(extra_vars) + extra_vars.update({ + #'tests': [True, "Build tests", CUSTOM], + 'offline': [True, "Build tests", CUSTOM], + 'lto': [False, "Build with link time optimization", CUSTOM], + }) + + #if 'source_urls' not in extra_vars: + # extra_vars['source_urls'] = [CRATESIO_SOURCE] + + #extra_vars['download_filename'] = '%(name)s/%(version)s/download' + + return extra_vars + + def __init__(self, *args, **kwargs): + """Constructor for Simpack easyblock.""" + super(Cargo, self).__init__(*args, **kwargs) + env.setvar('CARGO_HOME', os.path.join(self.builddir, '.cargo')) + env.setvar('RUSTC', 'rustc') + env.setvar('RUSTDOC', 'rustdoc') + env.setvar('RUSTFMT', 'rustfmt') + optarch = build_option('optarch') + if not optarch: + optarch = 'native' + env.setvar('RUSTFLAGS', '-C target-cpu=%s' % optarch) + env.setvar('RUST_LOG', 'DEBUG') + env.setvar('RUST_BACKTRACE', '1') + + def configure_step(self): + pass + + def extract_step(self): + """Populate all vendored deps with required .cargo-checksum.json""" + EasyBlock.extract_step(self) + for source in self.src: + dirname = source["name"].rsplit('.', maxsplit=2)[0] + self.log.info('creating .cargo-checksums.json file for : %s', dirname) + chksum = compute_checksum(source['path'], checksum_type='sha256') + chkfile = '%s/%s/.cargo-checksum.json' % (self.builddir, dirname) + write_file(chkfile, '{"files":{},"package":"%s"}' % chksum) + + def build_step(self): + """Build with cargo""" + parallel = '' + if self.cfg['parallel']: + parallel = "-j %s" % self.cfg['parallel'] + + tests = '' + if self.cfg['tests']: + parallel = "--tests" + + offline = '' + if self.cfg['offline']: + parallel = "--offline" + + profile = 'debug' if self.toolchain.options.get('debug', None) else 'release' + + lto = '' + if self.cfg['lto']: + parallel = '--config profile.%s.lto=true' % profile + + run_cmd('rustc --print cfg', log_all=True, simple=True) # for tracking in log file + #remove_file('Cargo.lock') # attempt to circumvent the checksum-check that cargo build does, but it still looks for the checksum json file. + # Can't figure out how to supply this via command line + write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) + cmd = '%s cargo build --profile=%s %s %s %s %s %s' % (self.cfg['prebuildopts'], profile, offline, lto, tests, parallel, self.cfg['buildopts']) + run_cmd(cmd, log_all=True, simple=True) + + def test_step(self): + """Test with cargo""" + if self.cfg['tests']: + profile = 'debug' if self.toolchain.options.get('debug', None) else 'release' + cmd = "%s cargo test --profile=%s %s" % (self.cfg['pretestopts'], profile, self.cfg['testopts']) + run_cmd(cmd, log_all=True, simple=True) + + def install_step(self): + """Install with cargo""" + cmd = "%s cargo install --offline --root %s --path . %s" % (self.cfg['preinstallopts'], self.installdir, self.cfg['installopts']) + run_cmd(cmd, log_all=True, simple=True) + From 7cc78df9e16c19e52da8872301f13b192bb2d3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 6 Mar 2023 14:54:31 +0000 Subject: [PATCH 02/59] Fix hound errors --- easybuild/easyblocks/generic/cargo.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index d59e0fee16..6e5514b713 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -29,15 +29,14 @@ """ import os -import glob import easybuild.tools.environment as env from easybuild.framework.easyconfig import CUSTOM from easybuild.framework.easyblock import EasyBlock -from easybuild.tools.build_log import EasyBuildError from easybuild.tools.run import run_cmd from easybuild.tools.config import build_option -from easybuild.tools.filetools import remove_file, write_file, extract_file, compute_checksum +from easybuild.tools.filetools import write_file, compute_checksum +# from easybuild.tools.filetools import remove_file CRATESIO_SOURCE = "https://crates.io/api/v1/crates" @@ -49,15 +48,15 @@ def extra_options(extra_vars=None): """Define extra easyconfig parameters specific to Cargo""" extra_vars = EasyBlock.extra_options(extra_vars) extra_vars.update({ - #'tests': [True, "Build tests", CUSTOM], + # 'tests': [True, "Build tests", CUSTOM], 'offline': [True, "Build tests", CUSTOM], 'lto': [False, "Build with link time optimization", CUSTOM], }) - #if 'source_urls' not in extra_vars: + # if 'source_urls' not in extra_vars: # extra_vars['source_urls'] = [CRATESIO_SOURCE] - #extra_vars['download_filename'] = '%(name)s/%(version)s/download' + # extra_vars['download_filename_template'] = '%(name)s/%(version)s/download' return extra_vars @@ -109,10 +108,12 @@ def build_step(self): parallel = '--config profile.%s.lto=true' % profile run_cmd('rustc --print cfg', log_all=True, simple=True) # for tracking in log file - #remove_file('Cargo.lock') # attempt to circumvent the checksum-check that cargo build does, but it still looks for the checksum json file. + # attempt to circumvent the checksum-check that cargo build does, but it still looks for the checksum json file + # remove_file('Cargo.lock') # Can't figure out how to supply this via command line write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) - cmd = '%s cargo build --profile=%s %s %s %s %s %s' % (self.cfg['prebuildopts'], profile, offline, lto, tests, parallel, self.cfg['buildopts']) + cmd = '%s cargo build --profile=%s %s %s %s %s %s' % ( + self.cfg['prebuildopts'], profile, offline, lto, tests, parallel, self.cfg['buildopts']) run_cmd(cmd, log_all=True, simple=True) def test_step(self): @@ -124,6 +125,7 @@ def test_step(self): def install_step(self): """Install with cargo""" - cmd = "%s cargo install --offline --root %s --path . %s" % (self.cfg['preinstallopts'], self.installdir, self.cfg['installopts']) + cmd = "%s cargo install --offline --root %s --path . %s" % ( + self.cfg['preinstallopts'], self.installdir, self.cfg['installopts']) run_cmd(cmd, log_all=True, simple=True) From df16d823e370b15d75a2471c4dc43a2372894e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 6 Mar 2023 14:55:09 +0000 Subject: [PATCH 03/59] Fix hound errors --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 6e5514b713..1967a91686 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -40,6 +40,7 @@ CRATESIO_SOURCE = "https://crates.io/api/v1/crates" + class Cargo(EasyBlock): """Support for installing Cargo packages (Rust)""" @@ -128,4 +129,3 @@ def install_step(self): cmd = "%s cargo install --offline --root %s --path . %s" % ( self.cfg['preinstallopts'], self.installdir, self.cfg['installopts']) run_cmd(cmd, log_all=True, simple=True) - From 863dfb82bb27664becfad6d23983472aa492a7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 6 Mar 2023 14:55:41 +0000 Subject: [PATCH 04/59] Fix hound errors --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 1967a91686..fd717f11c5 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -114,7 +114,7 @@ def build_step(self): # Can't figure out how to supply this via command line write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) cmd = '%s cargo build --profile=%s %s %s %s %s %s' % ( - self.cfg['prebuildopts'], profile, offline, lto, tests, parallel, self.cfg['buildopts']) + self.cfg['prebuildopts'], profile, offline, lto, tests, parallel, self.cfg['buildopts']) run_cmd(cmd, log_all=True, simple=True) def test_step(self): From f93988fe1f6e4da05f3e43b14b3b4aa868dc6825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 6 Mar 2023 15:10:36 +0000 Subject: [PATCH 05/59] Use profile consistently --- easybuild/easyblocks/generic/cargo.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index fd717f11c5..29a9bf03d6 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -88,6 +88,10 @@ def extract_step(self): chkfile = '%s/%s/.cargo-checksum.json' % (self.builddir, dirname) write_file(chkfile, '{"files":{},"package":"%s"}' % chksum) + @property + def profile(self): + return 'debug' if self.toolchain.options.get('debug', None) else 'release' + def build_step(self): """Build with cargo""" parallel = '' @@ -102,11 +106,9 @@ def build_step(self): if self.cfg['offline']: parallel = "--offline" - profile = 'debug' if self.toolchain.options.get('debug', None) else 'release' - lto = '' if self.cfg['lto']: - parallel = '--config profile.%s.lto=true' % profile + parallel = '--config profile.%s.lto=true' % self.profile run_cmd('rustc --print cfg', log_all=True, simple=True) # for tracking in log file # attempt to circumvent the checksum-check that cargo build does, but it still looks for the checksum json file @@ -114,18 +116,17 @@ def build_step(self): # Can't figure out how to supply this via command line write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) cmd = '%s cargo build --profile=%s %s %s %s %s %s' % ( - self.cfg['prebuildopts'], profile, offline, lto, tests, parallel, self.cfg['buildopts']) + self.cfg['prebuildopts'], self.profile, offline, lto, tests, parallel, self.cfg['buildopts']) run_cmd(cmd, log_all=True, simple=True) def test_step(self): """Test with cargo""" if self.cfg['tests']: - profile = 'debug' if self.toolchain.options.get('debug', None) else 'release' - cmd = "%s cargo test --profile=%s %s" % (self.cfg['pretestopts'], profile, self.cfg['testopts']) + cmd = "%s cargo test --profile=%s %s" % (self.cfg['pretestopts'], self.profile, self.cfg['testopts']) run_cmd(cmd, log_all=True, simple=True) def install_step(self): """Install with cargo""" - cmd = "%s cargo install --offline --root %s --path . %s" % ( - self.cfg['preinstallopts'], self.installdir, self.cfg['installopts']) + cmd = "%s cargo install --profile=%s --offline --root %s --path . %s" % ( + self.cfg['preinstallopts'], self.profile, self.installdir, self.cfg['installopts']) run_cmd(cmd, log_all=True, simple=True) From 3740be163d3f7be92417a1b6f2d075d6c06c0237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 6 Mar 2023 15:14:58 +0000 Subject: [PATCH 06/59] Fix copy/paste typo --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 29a9bf03d6..86e4335d4f 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -62,7 +62,7 @@ def extra_options(extra_vars=None): return extra_vars def __init__(self, *args, **kwargs): - """Constructor for Simpack easyblock.""" + """Constructor for Cargo easyblock.""" super(Cargo, self).__init__(*args, **kwargs) env.setvar('CARGO_HOME', os.path.join(self.builddir, '.cargo')) env.setvar('RUSTC', 'rustc') From c2d40b20429e155209c9e9a87a4bf9317847224f Mon Sep 17 00:00:00 2001 From: Simon Branford <4967+branfosj@users.noreply.github.com> Date: Thu, 16 Mar 2023 08:57:27 +0000 Subject: [PATCH 07/59] Fail out if the MATLAB install key is not set --- easybuild/easyblocks/m/matlab.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index e1b65d77a8..50405f4a8d 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -159,7 +159,10 @@ def install_step(self): keys = self.cfg['key'] if keys is None: - keys = os.getenv('EB_MATLAB_KEY', '00000-00000-00000-00000-00000-00000-00000-00000-00000-00000') + try: + keys = os.environ['EB_MATLAB_KEY'] + except KeyError: + raise EasyBuildError("The MATLAB install key is not set.") if isinstance(keys, string_type): keys = keys.split(',') From 1b42d6feb7d1a52ff848c76a84beb94ee38e5510 Mon Sep 17 00:00:00 2001 From: Xin Wu Date: Thu, 16 Mar 2023 13:57:47 +0100 Subject: [PATCH 08/59] inform users that gpu package (instead of kokkos) is used for building LAMMPS --- easybuild/easyblocks/l/lammps.py | 1 + 1 file changed, 1 insertion(+) diff --git a/easybuild/easyblocks/l/lammps.py b/easybuild/easyblocks/l/lammps.py index 5c3d77fdb0..4bcfc42d9d 100644 --- a/easybuild/easyblocks/l/lammps.py +++ b/easybuild/easyblocks/l/lammps.py @@ -372,6 +372,7 @@ def configure_step(self, **kwargs): # CUDA only elif self.cuda: + print_msg("Using gpu (not Kokkos) arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) self.cfg.update('configopts', '-D%sGPU=on' % self.pkg_prefix) self.cfg.update('configopts', '-DGPU_API=cuda') self.cfg.update('configopts', '-DGPU_ARCH=%s' % get_cuda_gpu_arch(cuda_cc)) From b1a7072d0848d52b6f8c0e178e5663777aca1343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Sun, 19 Mar 2023 22:53:56 +0000 Subject: [PATCH 09/59] Add support for crate list, minor other fixes --- easybuild/easyblocks/generic/cargo.py | 31 +++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 86e4335d4f..a2093b642a 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -36,7 +36,6 @@ from easybuild.tools.run import run_cmd from easybuild.tools.config import build_option from easybuild.tools.filetools import write_file, compute_checksum -# from easybuild.tools.filetools import remove_file CRATESIO_SOURCE = "https://crates.io/api/v1/crates" @@ -49,16 +48,12 @@ def extra_options(extra_vars=None): """Define extra easyconfig parameters specific to Cargo""" extra_vars = EasyBlock.extra_options(extra_vars) extra_vars.update({ - # 'tests': [True, "Build tests", CUSTOM], - 'offline': [True, "Build tests", CUSTOM], + 'enable_tests': [True, "Enable building of tests", CUSTOM], + 'offline': [True, "Build offline", CUSTOM], 'lto': [False, "Build with link time optimization", CUSTOM], + 'crates': [[], "List of (crate, version) tuples to use", CUSTOM], }) - # if 'source_urls' not in extra_vars: - # extra_vars['source_urls'] = [CRATESIO_SOURCE] - - # extra_vars['download_filename_template'] = '%(name)s/%(version)s/download' - return extra_vars def __init__(self, *args, **kwargs): @@ -75,6 +70,16 @@ def __init__(self, *args, **kwargs): env.setvar('RUST_LOG', 'DEBUG') env.setvar('RUST_BACKTRACE', '1') + # Populate sources from "crates" list of tuples + sources = self.cfg['sources'] + for crate, version in self.cfg['crates']: + sources.append({ + 'download_filename': crate + '/' + version + '/download', + 'filename': crate + '-' + version + '.tar.gz', + 'source_urls': CRATESIO_SOURCE, + }) + self.cfg.update('sources', sources) + def configure_step(self): pass @@ -99,29 +104,27 @@ def build_step(self): parallel = "-j %s" % self.cfg['parallel'] tests = '' - if self.cfg['tests']: + if self.cfg['enable_tests']: parallel = "--tests" offline = '' if self.cfg['offline']: parallel = "--offline" + # Replace crates-io with vendored sources + write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) lto = '' if self.cfg['lto']: parallel = '--config profile.%s.lto=true' % self.profile run_cmd('rustc --print cfg', log_all=True, simple=True) # for tracking in log file - # attempt to circumvent the checksum-check that cargo build does, but it still looks for the checksum json file - # remove_file('Cargo.lock') - # Can't figure out how to supply this via command line - write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) cmd = '%s cargo build --profile=%s %s %s %s %s %s' % ( self.cfg['prebuildopts'], self.profile, offline, lto, tests, parallel, self.cfg['buildopts']) run_cmd(cmd, log_all=True, simple=True) def test_step(self): """Test with cargo""" - if self.cfg['tests']: + if self.cfg['enable_tests']: cmd = "%s cargo test --profile=%s %s" % (self.cfg['pretestopts'], self.profile, self.cfg['testopts']) run_cmd(cmd, log_all=True, simple=True) From 5fc85e06050286960f32548ac54a5e1f5784188d Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Mon, 20 Mar 2023 16:34:04 +0100 Subject: [PATCH 10/59] bump version to 4.7.2dev --- easybuild/easyblocks/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/__init__.py b/easybuild/easyblocks/__init__.py index d634d41d22..fdd68d6024 100644 --- a/easybuild/easyblocks/__init__.py +++ b/easybuild/easyblocks/__init__.py @@ -43,7 +43,7 @@ # recent setuptools versions will *TRANSFORM* something like 'X.Y.Zdev' into 'X.Y.Z.dev0', with a warning like # UserWarning: Normalizing '2.4.0dev' to '2.4.0.dev0' # This causes problems further up the dependency chain... -VERSION = LooseVersion('4.7.1') +VERSION = LooseVersion('4.7.2.dev0') UNKNOWN = 'UNKNOWN' From 20dca5b087a7ba26b4666d32dc6935184159d7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Mon, 20 Mar 2023 23:30:24 +0000 Subject: [PATCH 11/59] Use alt location for crates --- easybuild/easyblocks/generic/cargo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index a2093b642a..037cf9300c 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -76,7 +76,8 @@ def __init__(self, *args, **kwargs): sources.append({ 'download_filename': crate + '/' + version + '/download', 'filename': crate + '-' + version + '.tar.gz', - 'source_urls': CRATESIO_SOURCE, + 'source_urls': [CRATESIO_SOURCE], + 'alt_location': 'crates.io', }) self.cfg.update('sources', sources) From 0274027cca85e1fbb41146f7445ef7893f45160c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Wed, 22 Mar 2023 18:57:43 +0100 Subject: [PATCH 12/59] don't check for RPATH sections in binaries compiled with Go --- easybuild/easyblocks/generic/gopackage.py | 77 ++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/gopackage.py b/easybuild/easyblocks/generic/gopackage.py index c06f724437..aca57c99d0 100644 --- a/easybuild/easyblocks/generic/gopackage.py +++ b/easybuild/easyblocks/generic/gopackage.py @@ -28,14 +28,17 @@ @author: Pavel Grochal (INUITS) """ import os +import re from distutils.version import LooseVersion import easybuild.tools.environment as env -from easybuild.framework.easyblock import EasyBlock +from easybuild.framework.easyblock import DEFAULT_BIN_LIB_SUBDIRS, EasyBlock from easybuild.framework.easyconfig import CUSTOM from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.config import build_option from easybuild.tools.modules import get_software_root, get_software_version from easybuild.tools.run import run_cmd +from easybuild.tools.systemtools import get_linked_libs_raw class GoPackage(EasyBlock): @@ -149,3 +152,75 @@ def sanity_check_step(self): custom_commands = ['%s --help' % self.name.lower()] super(GoPackage, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands) + + def sanity_check_rpath(self, rpath_dirs=None): + """Sanity check binaries/libraries w.r.t. RPATH linking.""" + + self.log.info("Checking RPATH linkage for binaries/libraries...") + + fails = [] + + # hard reset $LD_LIBRARY_PATH before running RPATH sanity check + orig_env = env.unset_env_vars(['LD_LIBRARY_PATH']) + + self.log.debug("$LD_LIBRARY_PATH during RPATH sanity check: %s", os.getenv('LD_LIBRARY_PATH', '(empty)')) + self.log.debug("List of loaded modules: %s", self.modules_tool.list()) + + not_found_regex = re.compile(r'(\S+)\s*\=\>\s*not found') + readelf_rpath_regex = re.compile('(RPATH)', re.M) + + # List of libraries that should be exempt from the RPATH sanity check; + # For example, libcuda.so.1 should never be RPATH-ed by design, + # see https://github.com/easybuilders/easybuild-framework/issues/4095 + filter_rpath_sanity_libs = build_option('filter_rpath_sanity_libs') + msg = "Ignoring the following libraries if they are not found by RPATH sanity check: %s" + self.log.info(msg, filter_rpath_sanity_libs) + + if rpath_dirs is None: + rpath_dirs = self.cfg['bin_lib_subdirs'] or self.bin_lib_subdirs() + + if not rpath_dirs: + rpath_dirs = DEFAULT_BIN_LIB_SUBDIRS + self.log.info("Using default subdirectories for binaries/libraries to verify RPATH linking: %s", + rpath_dirs) + else: + self.log.info("Using specified subdirectories for binaries/libraries to verify RPATH linking: %s", + rpath_dirs) + + for dirpath in [os.path.join(self.installdir, d) for d in rpath_dirs]: + if os.path.exists(dirpath): + self.log.debug("Sanity checking RPATH for files in %s", dirpath) + + for path in [os.path.join(dirpath, x) for x in os.listdir(dirpath)]: + self.log.debug("Sanity checking RPATH for %s", path) + + out = get_linked_libs_raw(path) + + if out is None: + msg = "Failed to determine dynamically linked libraries for %s, " + msg += "so skipping it in RPATH sanity check" + self.log.debug(msg, path) + else: + # check whether all required libraries are found via 'ldd' + matches = re.findall(not_found_regex, out) + if len(matches) > 0: # Some libraries are not found via 'ldd' + # For each match, check if the library is in the exception list + for match in matches: + if match in filter_rpath_sanity_libs: + msg = "Library %s not found for %s, but ignored " + msg += "since it is on the rpath exception list: %s" + self.log.info(msg, match, path, filter_rpath_sanity_libs) + else: + fail_msg = "Library %s not found for %s; " % (match, path) + fail_msg += "RPATH linking is enabled, but not implemented for Go packages." + fail_msg += "See https://github.com/easybuilders/easybuild-easyconfigs/issues/17516" + self.log.warning(fail_msg) + fails.append(fail_msg) + else: + self.log.debug("Output of 'ldd %s' checked, looks OK", path) + else: + self.log.debug("Not sanity checking files in non-existing directory %s", dirpath) + + env.restore_env_vars(orig_env) + + return fails From bb3a98fc0a2f885d45a11c48f3f8de774981ab05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Wed, 22 Mar 2023 22:12:33 +0100 Subject: [PATCH 13/59] remove unused variable --- easybuild/easyblocks/generic/gopackage.py | 1 - 1 file changed, 1 deletion(-) diff --git a/easybuild/easyblocks/generic/gopackage.py b/easybuild/easyblocks/generic/gopackage.py index aca57c99d0..16e2a2d1d7 100644 --- a/easybuild/easyblocks/generic/gopackage.py +++ b/easybuild/easyblocks/generic/gopackage.py @@ -167,7 +167,6 @@ def sanity_check_rpath(self, rpath_dirs=None): self.log.debug("List of loaded modules: %s", self.modules_tool.list()) not_found_regex = re.compile(r'(\S+)\s*\=\>\s*not found') - readelf_rpath_regex = re.compile('(RPATH)', re.M) # List of libraries that should be exempt from the RPATH sanity check; # For example, libcuda.so.1 should never be RPATH-ed by design, From e4553ff3a0117e5654f2e07d76bef79fc3f336a1 Mon Sep 17 00:00:00 2001 From: Simon Branford <4967+branfosj@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:13:43 +0100 Subject: [PATCH 14/59] use string '0' instead of to avoid problems when opensll version is not determined --- easybuild/easyblocks/o/openssl_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/o/openssl_wrapper.py b/easybuild/easyblocks/o/openssl_wrapper.py index bd6c50341e..f73a5e5295 100644 --- a/easybuild/easyblocks/o/openssl_wrapper.py +++ b/easybuild/easyblocks/o/openssl_wrapper.py @@ -162,7 +162,7 @@ def __init__(self, *args, **kwargs): for solib in solibs: system_solib = find_library_path(solib) if system_solib: - openssl_version = 0 + openssl_version = '0' # get version of system library filename try: openssl_version = full_version_regex.search(os.path.realpath(system_solib)).group(0) From 2fff8d2e5eb4d4fb69b2847da492a113e9116c6c Mon Sep 17 00:00:00 2001 From: Simon Branford <4967+branfosj@users.noreply.github.com> Date: Wed, 29 Mar 2023 08:53:48 +0100 Subject: [PATCH 15/59] better error message --- easybuild/easyblocks/m/matlab.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index 50405f4a8d..7c493abb4e 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -162,7 +162,8 @@ def install_step(self): try: keys = os.environ['EB_MATLAB_KEY'] except KeyError: - raise EasyBuildError("The MATLAB install key is not set.") + raise EasyBuildError("The MATLAB install key is not set. This can be set either with the environment " + "variable EB_MATLAB_KEY or by the easyconfig variable 'key'.") if isinstance(keys, string_type): keys = keys.split(',') From a98f4a5aa26d40b7d51f89bdf2de364ee924047a Mon Sep 17 00:00:00 2001 From: Simon Branford <4967+branfosj@users.noreply.github.com> Date: Wed, 29 Mar 2023 08:54:25 +0100 Subject: [PATCH 16/59] spaces vs tabs --- easybuild/easyblocks/m/matlab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index 7c493abb4e..643fa73878 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -163,7 +163,7 @@ def install_step(self): keys = os.environ['EB_MATLAB_KEY'] except KeyError: raise EasyBuildError("The MATLAB install key is not set. This can be set either with the environment " - "variable EB_MATLAB_KEY or by the easyconfig variable 'key'.") + "variable EB_MATLAB_KEY or by the easyconfig variable 'key'.") if isinstance(keys, string_type): keys = keys.split(',') From f10d6a1f3daa4f904e2be455ca6cc22462d8fd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 29 Mar 2023 18:52:38 +0200 Subject: [PATCH 17/59] Join argument list, fix typos --- easybuild/easyblocks/generic/cargo.py | 62 ++++++++++++++++++++------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 037cf9300c..e99457857a 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -85,14 +85,25 @@ def configure_step(self): pass def extract_step(self): - """Populate all vendored deps with required .cargo-checksum.json""" - EasyBlock.extract_step(self) - for source in self.src: - dirname = source["name"].rsplit('.', maxsplit=2)[0] - self.log.info('creating .cargo-checksums.json file for : %s', dirname) - chksum = compute_checksum(source['path'], checksum_type='sha256') - chkfile = '%s/%s/.cargo-checksum.json' % (self.builddir, dirname) - write_file(chkfile, '{"files":{},"package":"%s"}' % chksum) + """ + Unpack the source files and populate them with required .cargo-checksum.json if offline + """ + for src in self.src: + self.log.info("Unpacking source %s" % src['name']) + srcdir = extract_file(src['path'], self.builddir, cmd=src['cmd'], + extra_options=self.cfg['unpack_options'], change_into_dir=False) + change_dir(srcdir) + if srcdir: + self.src[self.src.index(src)]['finalpath'] = srcdir + else: + raise EasyBuildError("Unpacking source %s failed", src['name']) + + # Create checksum file for all sources required for + if self.cfg['offline']: + self.log.info('creating .cargo-checksums.json file for : %s', srcdir) + chksum = compute_checksum(src['path'], checksum_type='sha256') + chkfile = '%s/%s/.cargo-checksum.json' % (self.builddir, srcdir) + write_file(chkfile, '{"files":{},"package":"%s"}' % chksum) @property def profile(self): @@ -106,31 +117,50 @@ def build_step(self): tests = '' if self.cfg['enable_tests']: - parallel = "--tests" + tests = "--tests" offline = '' if self.cfg['offline']: - parallel = "--offline" + offline = "--offline" # Replace crates-io with vendored sources write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) lto = '' if self.cfg['lto']: - parallel = '--config profile.%s.lto=true' % self.profile + lto = '--config profile.%s.lto=true' % self.profile run_cmd('rustc --print cfg', log_all=True, simple=True) # for tracking in log file - cmd = '%s cargo build --profile=%s %s %s %s %s %s' % ( - self.cfg['prebuildopts'], self.profile, offline, lto, tests, parallel, self.cfg['buildopts']) + cmd = ' '.join([ + self.cfg['prebuildopts'], + 'cargo build', + '--profile=' + self.profile, + offline, + lto, + tests, + parallel, + self.cfg['buildopts'], + ]) run_cmd(cmd, log_all=True, simple=True) def test_step(self): """Test with cargo""" if self.cfg['enable_tests']: - cmd = "%s cargo test --profile=%s %s" % (self.cfg['pretestopts'], self.profile, self.cfg['testopts']) + cmd = ' '.join([ + self.cfg['pretestopts'], + 'cargo test', + '--profile=' + self.profile, + self.cfg['testopts'], + ]) run_cmd(cmd, log_all=True, simple=True) def install_step(self): """Install with cargo""" - cmd = "%s cargo install --profile=%s --offline --root %s --path . %s" % ( - self.cfg['preinstallopts'], self.profile, self.installdir, self.cfg['installopts']) + cmd = ' '.join([ + self.cfg['preinstallopts'], + 'cargo install' + '--profile=' + self.profile, + '--root=' + self.installdir, + '--path=.', + self.cfg['installopts'], + ]) run_cmd(cmd, log_all=True, simple=True) From 7904bf08fdad4dc4a400a2682706f8b9893f48bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 29 Mar 2023 19:15:17 +0200 Subject: [PATCH 18/59] Add missing import for change_dir --- easybuild/easyblocks/generic/cargo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index e99457857a..f184b70b8b 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -31,8 +31,10 @@ import os import easybuild.tools.environment as env +from easybuild.tools.build_log import EasyBuildError from easybuild.framework.easyconfig import CUSTOM from easybuild.framework.easyblock import EasyBlock +from easybuild.tools.filetools import extract_file, change_dir from easybuild.tools.run import run_cmd from easybuild.tools.config import build_option from easybuild.tools.filetools import write_file, compute_checksum From ecf69fd3caabd71330af83fc8796a97b91ac24b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 29 Mar 2023 19:19:15 +0200 Subject: [PATCH 19/59] Fix trailing space --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index f184b70b8b..e658ec15c8 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -100,7 +100,7 @@ def extract_step(self): else: raise EasyBuildError("Unpacking source %s failed", src['name']) - # Create checksum file for all sources required for + # Create checksum file for all sources required by vendored crates.io sources if self.cfg['offline']: self.log.info('creating .cargo-checksums.json file for : %s', srcdir) chksum = compute_checksum(src['path'], checksum_type='sha256') From 9d4225bcdf220ea5d928b57c502d9da805a00797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 29 Mar 2023 20:26:06 +0200 Subject: [PATCH 20/59] Fix cargo checksum into each extracted dir --- easybuild/easyblocks/generic/cargo.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index e658ec15c8..c33d3b3551 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -90,7 +90,9 @@ def extract_step(self): """ Unpack the source files and populate them with required .cargo-checksum.json if offline """ + dirs = set() for src in self.src: + existing_dirs = set(os.listdir(self.builddir)) self.log.info("Unpacking source %s" % src['name']) srcdir = extract_file(src['path'], self.builddir, cmd=src['cmd'], extra_options=self.cfg['unpack_options'], change_into_dir=False) @@ -101,10 +103,12 @@ def extract_step(self): raise EasyBuildError("Unpacking source %s failed", src['name']) # Create checksum file for all sources required by vendored crates.io sources - if self.cfg['offline']: - self.log.info('creating .cargo-checksums.json file for : %s', srcdir) + new_dirs = set(os.listdir(self.builddir)) - existing_dirs + if self.cfg['offline'] and len(new_dirs) == 1: + cratedir = new_dirs.pop() + self.log.info('creating .cargo-checksums.json file for : %s', cratedir) chksum = compute_checksum(src['path'], checksum_type='sha256') - chkfile = '%s/%s/.cargo-checksum.json' % (self.builddir, srcdir) + chkfile = os.path.join(self.builddir, cratedir, '.cargo-checksum.json') write_file(chkfile, '{"files":{},"package":"%s"}' % chksum) @property @@ -159,7 +163,7 @@ def install_step(self): """Install with cargo""" cmd = ' '.join([ self.cfg['preinstallopts'], - 'cargo install' + 'cargo install', '--profile=' + self.profile, '--root=' + self.installdir, '--path=.', From 10b604dc3d2b614198ca6daa82ca492b8222b27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 29 Mar 2023 20:27:39 +0200 Subject: [PATCH 21/59] Remove unused var --- easybuild/easyblocks/generic/cargo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index c33d3b3551..b87898ad9a 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -90,7 +90,6 @@ def extract_step(self): """ Unpack the source files and populate them with required .cargo-checksum.json if offline """ - dirs = set() for src in self.src: existing_dirs = set(os.listdir(self.builddir)) self.log.info("Unpacking source %s" % src['name']) From 827e30092811aa8b537c0b94b46ebf3363cacf94 Mon Sep 17 00:00:00 2001 From: ocaisa Date: Thu, 30 Mar 2023 09:18:45 +0200 Subject: [PATCH 22/59] Update both messages for Kokkos and GPU package --- easybuild/easyblocks/l/lammps.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/easybuild/easyblocks/l/lammps.py b/easybuild/easyblocks/l/lammps.py index 4bcfc42d9d..d026696a4d 100644 --- a/easybuild/easyblocks/l/lammps.py +++ b/easybuild/easyblocks/l/lammps.py @@ -346,7 +346,7 @@ def configure_step(self, **kwargs): # https://lammps.sandia.gov/doc/Build_extras.html # KOKKOS if self.cfg['kokkos']: - print_msg("Using Kokkos arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) + print_msg("Using Kokkos package with arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) self.cfg.update('configopts', '-D%sKOKKOS=on' % self.pkg_prefix) if self.toolchain.options.get('openmp', None): @@ -372,7 +372,7 @@ def configure_step(self, **kwargs): # CUDA only elif self.cuda: - print_msg("Using gpu (not Kokkos) arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) + print_msg("Using GPU package (not Kokkos) with arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) self.cfg.update('configopts', '-D%sGPU=on' % self.pkg_prefix) self.cfg.update('configopts', '-DGPU_API=cuda') self.cfg.update('configopts', '-DGPU_ARCH=%s' % get_cuda_gpu_arch(cuda_cc)) From 1ee031d9de457a0003b47320f31e0c7ecc79aa0b Mon Sep 17 00:00:00 2001 From: Simon Branford Date: Sat, 1 Apr 2023 14:22:02 +0100 Subject: [PATCH 23/59] use FlexiBLAS for newer PyTorch versions --- easybuild/easyblocks/p/pytorch.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/easybuild/easyblocks/p/pytorch.py b/easybuild/easyblocks/p/pytorch.py index 252bc09741..2783db4707 100644 --- a/easybuild/easyblocks/p/pytorch.py +++ b/easybuild/easyblocks/p/pytorch.py @@ -155,6 +155,9 @@ def configure_step(self): if get_software_root('imkl'): options.append('BLAS=MKL') options.append('INTEL_MKL_DIR=$MKLROOT') + elif pytorch_version >= '1.11.0' and get_software_root('FlexiBLAS'): + options.append('BLAS=FlexiBLAS') + options.append('WITH_BLAS=flexi') elif pytorch_version >= '1.9.0' and get_software_root('BLIS'): options.append('BLAS=BLIS') options.append('BLIS_HOME=' + get_software_root('BLIS')) From d04f012061fa8a559834b1b22afdf8bd32019bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 13 Apr 2023 04:13:17 +0200 Subject: [PATCH 24/59] Include script for generating crate list --- easybuild/easyblocks/generic/cargo.py | 55 +++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index b87898ad9a..588c0be6a1 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -52,7 +52,7 @@ def extra_options(extra_vars=None): extra_vars.update({ 'enable_tests': [True, "Enable building of tests", CUSTOM], 'offline': [True, "Build offline", CUSTOM], - 'lto': [False, "Build with link time optimization", CUSTOM], + 'lto': [None, "Override default LTO flag ('fat', 'thin', 'off')", CUSTOM], 'crates': [[], "List of (crate, version) tuples to use", CUSTOM], }) @@ -131,8 +131,8 @@ def build_step(self): write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) lto = '' - if self.cfg['lto']: - lto = '--config profile.%s.lto=true' % self.profile + if self.cfg['lto'] is not None: + lto = '--config profile.%s.lto=\\"%s\\"' % (self.profile, self.cfg['lto']) run_cmd('rustc --print cfg', log_all=True, simple=True) # for tracking in log file cmd = ' '.join([ @@ -150,22 +150,71 @@ def build_step(self): def test_step(self): """Test with cargo""" if self.cfg['enable_tests']: + offline = '' + if self.cfg['offline']: + offline = "--offline" + cmd = ' '.join([ self.cfg['pretestopts'], 'cargo test', '--profile=' + self.profile, + offline, self.cfg['testopts'], ]) run_cmd(cmd, log_all=True, simple=True) def install_step(self): """Install with cargo""" + offline = '' + if self.cfg['offline']: + offline = "--offline" + cmd = ' '.join([ self.cfg['preinstallopts'], 'cargo install', '--profile=' + self.profile, + offline, '--root=' + self.installdir, '--path=.', self.cfg['installopts'], ]) run_cmd(cmd, log_all=True, simple=True) + + +def generate_crate_list(sourcedir): + """Helper for generating crate list""" + import toml + + cargo_toml = toml.load(os.path.join(sourcedir, 'Cargo.toml')) + cargo_lock = toml.load(os.path.join(sourcedir, 'Cargo.lock')) + + app_name = cargo_toml['package']['name'] + deps = cargo_lock['package'] + + app_in_cratesio = False + crates = [] + other_crates = [] + for dep in deps: + name = dep['name'] + version = dep['version'] + if 'source' in dep and dep['source'] == 'registry+https://github.com/rust-lang/crates.io-index': + if name == app_name: + app_in_cratesio = True # exclude app itself, needs to be first in crates list + else: + crates.append((name, version)) + else: + other_crates.append((name, version)) + return app_in_cratesio, crates, other_crates + + +if __name__ == '__main__': + import sys + app_in_cratesio, crates, _ = generate_crate_list(sys.argv[1]) + if app_in_cratesio or crates: + print('crates = [') + if app_in_cratesio: + print(' (name, version),') + for name, version in crates: + print(" ('" + name + "', '" + version + "'),") + print(']') + From e83b8c6efc5e05499cc803a79ea84b71e0d3322d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 13 Apr 2023 10:19:47 +0200 Subject: [PATCH 25/59] Trailing whitespace --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 588c0be6a1..4187edaeae 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -217,4 +217,4 @@ def generate_crate_list(sourcedir): for name, version in crates: print(" ('" + name + "', '" + version + "'),") print(']') - + From 00c0f101c78e3d29c091544ee5540b3e3a453582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 13 Apr 2023 11:06:35 +0200 Subject: [PATCH 26/59] blank line --- easybuild/easyblocks/generic/cargo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 4187edaeae..1890d373aa 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -217,4 +217,3 @@ def generate_crate_list(sourcedir): for name, version in crates: print(" ('" + name + "', '" + version + "'),") print(']') - From 94b8c73743b1e2086c5433b74254d74a3068fd6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Fri, 21 Apr 2023 17:29:24 +0200 Subject: [PATCH 27/59] prevent copy-pasting of code by using the parameter added in https://github.com/easybuilders/easybuild-framework/pull/4249 --- easybuild/easyblocks/generic/gopackage.py | 78 +---------------------- 1 file changed, 2 insertions(+), 76 deletions(-) diff --git a/easybuild/easyblocks/generic/gopackage.py b/easybuild/easyblocks/generic/gopackage.py index 16e2a2d1d7..55695fc51e 100644 --- a/easybuild/easyblocks/generic/gopackage.py +++ b/easybuild/easyblocks/generic/gopackage.py @@ -28,17 +28,14 @@ @author: Pavel Grochal (INUITS) """ import os -import re from distutils.version import LooseVersion import easybuild.tools.environment as env -from easybuild.framework.easyblock import DEFAULT_BIN_LIB_SUBDIRS, EasyBlock +from easybuild.framework.easyblock import EasyBlock from easybuild.framework.easyconfig import CUSTOM from easybuild.tools.build_log import EasyBuildError -from easybuild.tools.config import build_option from easybuild.tools.modules import get_software_root, get_software_version from easybuild.tools.run import run_cmd -from easybuild.tools.systemtools import get_linked_libs_raw class GoPackage(EasyBlock): @@ -134,9 +131,6 @@ def install_step(self): self.cfg['preinstallopts'], 'go', 'install', - # print commands as they are executed, - # including downloading and installing of package deps as listed in the go.mod file - '-x', self.cfg['installopts'], ]) run_cmd(cmd, log_all=True, log_ok=True, simple=True) @@ -154,72 +148,4 @@ def sanity_check_step(self): super(GoPackage, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands) def sanity_check_rpath(self, rpath_dirs=None): - """Sanity check binaries/libraries w.r.t. RPATH linking.""" - - self.log.info("Checking RPATH linkage for binaries/libraries...") - - fails = [] - - # hard reset $LD_LIBRARY_PATH before running RPATH sanity check - orig_env = env.unset_env_vars(['LD_LIBRARY_PATH']) - - self.log.debug("$LD_LIBRARY_PATH during RPATH sanity check: %s", os.getenv('LD_LIBRARY_PATH', '(empty)')) - self.log.debug("List of loaded modules: %s", self.modules_tool.list()) - - not_found_regex = re.compile(r'(\S+)\s*\=\>\s*not found') - - # List of libraries that should be exempt from the RPATH sanity check; - # For example, libcuda.so.1 should never be RPATH-ed by design, - # see https://github.com/easybuilders/easybuild-framework/issues/4095 - filter_rpath_sanity_libs = build_option('filter_rpath_sanity_libs') - msg = "Ignoring the following libraries if they are not found by RPATH sanity check: %s" - self.log.info(msg, filter_rpath_sanity_libs) - - if rpath_dirs is None: - rpath_dirs = self.cfg['bin_lib_subdirs'] or self.bin_lib_subdirs() - - if not rpath_dirs: - rpath_dirs = DEFAULT_BIN_LIB_SUBDIRS - self.log.info("Using default subdirectories for binaries/libraries to verify RPATH linking: %s", - rpath_dirs) - else: - self.log.info("Using specified subdirectories for binaries/libraries to verify RPATH linking: %s", - rpath_dirs) - - for dirpath in [os.path.join(self.installdir, d) for d in rpath_dirs]: - if os.path.exists(dirpath): - self.log.debug("Sanity checking RPATH for files in %s", dirpath) - - for path in [os.path.join(dirpath, x) for x in os.listdir(dirpath)]: - self.log.debug("Sanity checking RPATH for %s", path) - - out = get_linked_libs_raw(path) - - if out is None: - msg = "Failed to determine dynamically linked libraries for %s, " - msg += "so skipping it in RPATH sanity check" - self.log.debug(msg, path) - else: - # check whether all required libraries are found via 'ldd' - matches = re.findall(not_found_regex, out) - if len(matches) > 0: # Some libraries are not found via 'ldd' - # For each match, check if the library is in the exception list - for match in matches: - if match in filter_rpath_sanity_libs: - msg = "Library %s not found for %s, but ignored " - msg += "since it is on the rpath exception list: %s" - self.log.info(msg, match, path, filter_rpath_sanity_libs) - else: - fail_msg = "Library %s not found for %s; " % (match, path) - fail_msg += "RPATH linking is enabled, but not implemented for Go packages." - fail_msg += "See https://github.com/easybuilders/easybuild-easyconfigs/issues/17516" - self.log.warning(fail_msg) - fails.append(fail_msg) - else: - self.log.debug("Output of 'ldd %s' checked, looks OK", path) - else: - self.log.debug("Not sanity checking files in non-existing directory %s", dirpath) - - env.restore_env_vars(orig_env) - - return fails + super(GoPackage, self).sanity_check_rpath(rpath_dirs=rpath_dirs, check_readelf_rpath=False) From d4e6a94c5b4124a67aa700d72ec8c4c445c170fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Fri, 21 Apr 2023 17:36:04 +0200 Subject: [PATCH 28/59] Merge latest changes from develop --- easybuild/easyblocks/generic/gopackage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/easybuild/easyblocks/generic/gopackage.py b/easybuild/easyblocks/generic/gopackage.py index 55695fc51e..5c2d96bdc9 100644 --- a/easybuild/easyblocks/generic/gopackage.py +++ b/easybuild/easyblocks/generic/gopackage.py @@ -131,6 +131,9 @@ def install_step(self): self.cfg['preinstallopts'], 'go', 'install', + # print commands as they are executed, + # including downloading and installing of package deps as listed in the go.mod file + '-x', self.cfg['installopts'], ]) run_cmd(cmd, log_all=True, log_ok=True, simple=True) From 55ec455c6adbc05a6e5beb6f0b69167311370ed0 Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Fri, 21 Apr 2023 21:57:03 +0200 Subject: [PATCH 29/59] ensure that --sysroot is passed to linker --- easybuild/easyblocks/g/gcc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/easybuild/easyblocks/g/gcc.py b/easybuild/easyblocks/g/gcc.py index 9069e3ea37..9bf640253c 100644 --- a/easybuild/easyblocks/g/gcc.py +++ b/easybuild/easyblocks/g/gcc.py @@ -357,9 +357,6 @@ def configure_step(self): # (see https://gcc.gnu.org/install/configure.html) self.cfg.update('configopts', '--with-sysroot=%s' % sysroot) - # avoid that --sysroot is passed to linker by patching value for SYSROOT_SPEC in gcc/gcc.c - apply_regex_substitutions(os.path.join('gcc', 'gcc.c'), [('--sysroot=%R', '')]) - # prefix dynamic linkers with sysroot # this patches lines like: # #define GLIBC_DYNAMIC_LINKER64 "/lib64/ld-linux-x86-64.so.2" From f15f3006b5ee7d99ce3934bf3d4a6655564b49ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Tue, 2 May 2023 01:13:28 +0200 Subject: [PATCH 30/59] Add cargopythonpackage --- easybuild/easyblocks/generic/cargo.py | 30 ++++------ .../easyblocks/generic/cargopythonpackage.py | 60 +++++++++++++++++++ 2 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 easybuild/easyblocks/generic/cargopythonpackage.py diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 1890d373aa..29e990e31a 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -83,6 +83,14 @@ def __init__(self, *args, **kwargs): }) self.cfg.update('sources', sources) + if self.cfg['offline']: + # Replace crates-io with vendored sources using build dir wide toml file in CARGO_HOME + # because the rust source subdirectories might differ with python packages + config_toml = os.path.join(self.builddir, '.cargo', 'config.toml') + write_file(config_toml, '[source.crates-io]\ndirectory="%s"' % self.builddir) + # Use environment variable since it would also be passed along to builds triggered via python packages + env.setvar('CARGO_NET_OFFLINE', 'true') + def configure_step(self): pass @@ -124,12 +132,6 @@ def build_step(self): if self.cfg['enable_tests']: tests = "--tests" - offline = '' - if self.cfg['offline']: - offline = "--offline" - # Replace crates-io with vendored sources - write_file('.cargo/config.toml', '[source.crates-io]\ndirectory=".."', append=True) - lto = '' if self.cfg['lto'] is not None: lto = '--config profile.%s.lto=\\"%s\\"' % (self.profile, self.cfg['lto']) @@ -139,7 +141,6 @@ def build_step(self): self.cfg['prebuildopts'], 'cargo build', '--profile=' + self.profile, - offline, lto, tests, parallel, @@ -150,30 +151,20 @@ def build_step(self): def test_step(self): """Test with cargo""" if self.cfg['enable_tests']: - offline = '' - if self.cfg['offline']: - offline = "--offline" - cmd = ' '.join([ self.cfg['pretestopts'], 'cargo test', '--profile=' + self.profile, - offline, self.cfg['testopts'], ]) run_cmd(cmd, log_all=True, simple=True) def install_step(self): """Install with cargo""" - offline = '' - if self.cfg['offline']: - offline = "--offline" - cmd = ' '.join([ self.cfg['preinstallopts'], 'cargo install', '--profile=' + self.profile, - offline, '--root=' + self.installdir, '--path=.', self.cfg['installopts'], @@ -189,6 +180,7 @@ def generate_crate_list(sourcedir): cargo_lock = toml.load(os.path.join(sourcedir, 'Cargo.lock')) app_name = cargo_toml['package']['name'] + print(app_name) deps = cargo_lock['package'] app_in_cratesio = False @@ -199,6 +191,7 @@ def generate_crate_list(sourcedir): version = dep['version'] if 'source' in dep and dep['source'] == 'registry+https://github.com/rust-lang/crates.io-index': if name == app_name: + print('check') app_in_cratesio = True # exclude app itself, needs to be first in crates list else: crates.append((name, version)) @@ -209,7 +202,8 @@ def generate_crate_list(sourcedir): if __name__ == '__main__': import sys - app_in_cratesio, crates, _ = generate_crate_list(sys.argv[1]) + app_in_cratesio, crates, other = generate_crate_list(sys.argv[1]) + print(other) if app_in_cratesio or crates: print('crates = [') if app_in_cratesio: diff --git a/easybuild/easyblocks/generic/cargopythonpackage.py b/easybuild/easyblocks/generic/cargopythonpackage.py new file mode 100644 index 0000000000..ae1292512b --- /dev/null +++ b/easybuild/easyblocks/generic/cargopythonpackage.py @@ -0,0 +1,60 @@ +## +# Copyright 2009-2023 Ghent University +# +# This file is part of EasyBuild, +# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), +# with support of Ghent University (http://ugent.be/hpc), +# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be), +# Flemish Research Foundation (FWO) (http://www.fwo.be/en) +# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). +# +# https://github.com/easybuilders/easybuild +# +# EasyBuild is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation v2. +# +# EasyBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with EasyBuild. If not, see . +## +""" +EasyBuild support for installing Cargo packages (Rust lang package system) + +@author: Mikael Oehman (Chalmers University of Technology) +""" + +import os + +from easybuild.easyblocks.generic.cargo import Cargo +from easybuild.easyblocks.generic.pythonpackage import PythonPackage + + +class CargoPythonPackage(PythonPackage, Cargo): # PythonPackage must come first to take precedence + """Build a Python package with setup from Cargo but build/install step from PythonPackage + + The cargo init step will set up the environment variables for rustc and vendor sources + but all the build steps are triggered via normal PythonPackage steps like normal. + """ + + @staticmethod + def extra_options(extra_vars=None): + """Define extra easyconfig parameters specific to Cargo""" + extra_vars = PythonPackage.extra_options(extra_vars) + extra_vars = Cargo.extra_options(extra_vars) # not all extra options here will used here + + return extra_vars + + def __init__(self, *args, **kwargs): + """Constructor for CargoPythonPackage easyblock.""" + Cargo.__init__(self, *args, **kwargs) + return PythonPackage.__init__(self, *args, **kwargs) + + def extract_step(self): + """Specifically use the overloaded variant from Cargo as is populates vendored sources with checksums.""" + return Cargo.extract_step(self) + From 13807fb9ab1a869c135d87c2eb4b13d5b411f3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Tue, 2 May 2023 01:28:58 +0200 Subject: [PATCH 31/59] Fix code style --- easybuild/easyblocks/generic/cargopythonpackage.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/easybuild/easyblocks/generic/cargopythonpackage.py b/easybuild/easyblocks/generic/cargopythonpackage.py index ae1292512b..71a8778fa4 100644 --- a/easybuild/easyblocks/generic/cargopythonpackage.py +++ b/easybuild/easyblocks/generic/cargopythonpackage.py @@ -28,8 +28,6 @@ @author: Mikael Oehman (Chalmers University of Technology) """ -import os - from easybuild.easyblocks.generic.cargo import Cargo from easybuild.easyblocks.generic.pythonpackage import PythonPackage @@ -57,4 +55,3 @@ def __init__(self, *args, **kwargs): def extract_step(self): """Specifically use the overloaded variant from Cargo as is populates vendored sources with checksums.""" return Cargo.extract_step(self) - From 85113256cd16e38edcce8c0ae10f813652f6bc04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Tue, 2 May 2023 02:28:33 +0200 Subject: [PATCH 32/59] Move config.toml modifications to extract step --- easybuild/easyblocks/generic/cargo.py | 20 ++++++++++--------- .../easyblocks/generic/cargopythonpackage.py | 2 ++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 29e990e31a..562a1f69fe 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -61,7 +61,8 @@ def extra_options(extra_vars=None): def __init__(self, *args, **kwargs): """Constructor for Cargo easyblock.""" super(Cargo, self).__init__(*args, **kwargs) - env.setvar('CARGO_HOME', os.path.join(self.builddir, '.cargo')) + self.cargo_home = os.path.join(self.builddir, '.cargo') + env.setvar('CARGO_HOME', self.cargo_home) env.setvar('RUSTC', 'rustc') env.setvar('RUSTDOC', 'rustdoc') env.setvar('RUSTFMT', 'rustfmt') @@ -83,14 +84,6 @@ def __init__(self, *args, **kwargs): }) self.cfg.update('sources', sources) - if self.cfg['offline']: - # Replace crates-io with vendored sources using build dir wide toml file in CARGO_HOME - # because the rust source subdirectories might differ with python packages - config_toml = os.path.join(self.builddir, '.cargo', 'config.toml') - write_file(config_toml, '[source.crates-io]\ndirectory="%s"' % self.builddir) - # Use environment variable since it would also be passed along to builds triggered via python packages - env.setvar('CARGO_NET_OFFLINE', 'true') - def configure_step(self): pass @@ -98,6 +91,15 @@ def extract_step(self): """ Unpack the source files and populate them with required .cargo-checksum.json if offline """ + if self.cfg['offline']: + self.log.info("Setting vendored crates-io dir") + # Replace crates-io with vendored sources using build dir wide toml file in CARGO_HOME + # because the rust source subdirectories might differ with python packages + config_toml = os.path.join(self.cargo_home, 'config.toml') + write_file(config_toml, '[source.crates-io]\ndirectory="%s"' % self.builddir) + # Use environment variable since it would also be passed along to builds triggered via python packages + env.setvar('CARGO_NET_OFFLINE', 'true') + for src in self.src: existing_dirs = set(os.listdir(self.builddir)) self.log.info("Unpacking source %s" % src['name']) diff --git a/easybuild/easyblocks/generic/cargopythonpackage.py b/easybuild/easyblocks/generic/cargopythonpackage.py index 71a8778fa4..21011d9e97 100644 --- a/easybuild/easyblocks/generic/cargopythonpackage.py +++ b/easybuild/easyblocks/generic/cargopythonpackage.py @@ -49,7 +49,9 @@ def extra_options(extra_vars=None): def __init__(self, *args, **kwargs): """Constructor for CargoPythonPackage easyblock.""" + print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2") Cargo.__init__(self, *args, **kwargs) + self.log.info("CHECK B") return PythonPackage.__init__(self, *args, **kwargs) def extract_step(self): From 9067045460fa50f78577b34cb3a73c57b7be5c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Tue, 2 May 2023 02:34:27 +0200 Subject: [PATCH 33/59] Remove debug prints --- easybuild/easyblocks/generic/cargopythonpackage.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/easybuild/easyblocks/generic/cargopythonpackage.py b/easybuild/easyblocks/generic/cargopythonpackage.py index 21011d9e97..71a8778fa4 100644 --- a/easybuild/easyblocks/generic/cargopythonpackage.py +++ b/easybuild/easyblocks/generic/cargopythonpackage.py @@ -49,9 +49,7 @@ def extra_options(extra_vars=None): def __init__(self, *args, **kwargs): """Constructor for CargoPythonPackage easyblock.""" - print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2") Cargo.__init__(self, *args, **kwargs) - self.log.info("CHECK B") return PythonPackage.__init__(self, *args, **kwargs) def extract_step(self): From 86aca20d15def4261c22a8af57b1aee467daa893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 3 May 2023 03:33:17 +0200 Subject: [PATCH 34/59] Add output log to matlab installs, parse for common errors --- easybuild/easyblocks/m/matlab.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index 643fa73878..1bd4ef1b6b 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -55,6 +55,7 @@ def __init__(self, *args, **kwargs): super(EB_MATLAB, self).__init__(*args, **kwargs) self.comp_fam = None self.configfile = os.path.join(self.builddir, 'my_installer_input.txt') + self.outputfile = os.path.join(self.builddir, 'my_installer_output.txt') @staticmethod def extra_options(): @@ -98,12 +99,14 @@ def configure_step(self): regagree = re.compile(br"^# agreeToLicense=.*", re.M) regmode = re.compile(br"^# mode=.*", re.M) reglicpath = re.compile(br"^# licensePath=.*", re.M) + regoutfile = re.compile(br"^# outputFile=.*", re.M) # must use byte-strings here when using Python 3, see above config = regdest.sub(b"destinationFolder=%s" % self.installdir.encode('utf-8'), config) config = regagree.sub(b"agreeToLicense=Yes", config) config = regmode.sub(b"mode=silent", config) config = reglicpath.sub(b"licensePath=%s" % licfile.encode('utf-8'), config) + config = regoutfile.sub(b"outputFile=\"%s\"" % self.outputfile, config) write_file(self.configfile, config) @@ -188,6 +191,9 @@ def install_step(self): # check installer output for known signs of trouble patterns = [ "Error: You have entered an invalid File Installation Key", + "Not a valid key", + "Exiting with status -2", + "End - Unsuccessful", ] for pattern in patterns: @@ -195,6 +201,12 @@ def install_step(self): if regex.search(out): raise EasyBuildError("Found error pattern '%s' in output of installation command '%s': %s", regex.pattern, cmd, out) + + with open(self.outputfile) as f: + if regex.search(f.read()): + raise EasyBuildError("Found error pattern '%s' in output file of installer", + regex.pattern) + def sanity_check_step(self): """Custom sanity check for MATLAB.""" From 0264c37d531156e1fe89361afb3d3f0da3a6922a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 3 May 2023 03:36:54 +0200 Subject: [PATCH 35/59] Fix style --- easybuild/easyblocks/m/matlab.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index 1bd4ef1b6b..575cf94b4f 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -201,13 +201,11 @@ def install_step(self): if regex.search(out): raise EasyBuildError("Found error pattern '%s' in output of installation command '%s': %s", regex.pattern, cmd, out) - with open(self.outputfile) as f: if regex.search(f.read()): raise EasyBuildError("Found error pattern '%s' in output file of installer", regex.pattern) - def sanity_check_step(self): """Custom sanity check for MATLAB.""" custom_paths = { From 5f3d769ab3c38308e4fbd06e22fc2619e51fa197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 3 May 2023 03:47:42 +0200 Subject: [PATCH 36/59] Add missing utf-8 encoding --- easybuild/easyblocks/m/matlab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index 575cf94b4f..8c1a4df514 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -106,7 +106,7 @@ def configure_step(self): config = regagree.sub(b"agreeToLicense=Yes", config) config = regmode.sub(b"mode=silent", config) config = reglicpath.sub(b"licensePath=%s" % licfile.encode('utf-8'), config) - config = regoutfile.sub(b"outputFile=\"%s\"" % self.outputfile, config) + config = regoutfile.sub(b"outputFile=\"%s\"" % self.outputfile.encode('utf-8'), config) write_file(self.configfile, config) From c1fbbae8beb821bc348f26a099baf8fe572822e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 3 May 2023 03:58:47 +0200 Subject: [PATCH 37/59] Remove quotes around file path as matlab doesn't like that --- easybuild/easyblocks/m/matlab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index 8c1a4df514..f147bc993c 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -106,7 +106,7 @@ def configure_step(self): config = regagree.sub(b"agreeToLicense=Yes", config) config = regmode.sub(b"mode=silent", config) config = reglicpath.sub(b"licensePath=%s" % licfile.encode('utf-8'), config) - config = regoutfile.sub(b"outputFile=\"%s\"" % self.outputfile.encode('utf-8'), config) + config = regoutfile.sub(b"outputFile=%s" % self.outputfile.encode('utf-8'), config) write_file(self.configfile, config) From f0ededc1afc7e6261d330797eab67e877465ea31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 3 May 2023 16:18:29 +0200 Subject: [PATCH 38/59] Broaden patterns to find in matlab errors --- easybuild/easyblocks/m/matlab.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index f147bc993c..a0f04b1748 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -192,7 +192,9 @@ def install_step(self): patterns = [ "Error: You have entered an invalid File Installation Key", "Not a valid key", - "Exiting with status -2", + "All selected products are already installed", + "The application encountered an unexpected error and needs to close", + "Exiting with status -\\d", "End - Unsuccessful", ] From f04ea9604ff3c13070a2388978d87962d22c52ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 4 May 2023 00:16:00 +0200 Subject: [PATCH 39/59] Allow gurobi to use EB_GUROBI_LICENSE_FILE environment variable --- easybuild/easyblocks/g/gurobi.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/easybuild/easyblocks/g/gurobi.py b/easybuild/easyblocks/g/gurobi.py index a02938ac12..923cc28f2f 100644 --- a/easybuild/easyblocks/g/gurobi.py +++ b/easybuild/easyblocks/g/gurobi.py @@ -55,22 +55,25 @@ def __init__(self, *args, **kwargs): """Easyblock constructor, define custom class variables specific to Gurobi.""" super(EB_Gurobi, self).__init__(*args, **kwargs) - self.license_file = self.cfg['license_file'] - + # make sure license file is available + self.orig_license_file = self.cfg['license_file'] + if self.orig_license_file is None: + self.orig_license_file = os.getenv('EB_GUROBI_LICENSE_FILE', None) + + if self.orig_license_file is None or not os.path.exists(self.cfg['license_file']): + raise EasyBuildError("No existing license file specified: %s", self.orig_license_file) + if self.cfg['copy_license_file']: self.license_file = os.path.join(self.installdir, 'gurobi.lic') + else: + self.license_file = self.orig_license_file def install_step(self): """Install Gurobi and license file.""" - - # make sure license file is available - if self.cfg['license_file'] is None or not os.path.exists(self.cfg['license_file']): - raise EasyBuildError("No existing license file specified: %s", self.cfg['license_file']) - super(EB_Gurobi, self).install_step() if self.cfg['copy_license_file']: - copy_file(self.cfg['license_file'], self.license_file) + copy_file(self.orig_license_file, self.license_file) if get_software_root('Python'): run_cmd("python setup.py install --prefix=%s" % self.installdir) From 5b357e482825ef0ff52d4584537169ab26e5df3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 4 May 2023 00:17:40 +0200 Subject: [PATCH 40/59] Fix code style in gurobi.py --- easybuild/easyblocks/g/gurobi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/easybuild/easyblocks/g/gurobi.py b/easybuild/easyblocks/g/gurobi.py index 923cc28f2f..45b6506916 100644 --- a/easybuild/easyblocks/g/gurobi.py +++ b/easybuild/easyblocks/g/gurobi.py @@ -59,10 +59,10 @@ def __init__(self, *args, **kwargs): self.orig_license_file = self.cfg['license_file'] if self.orig_license_file is None: self.orig_license_file = os.getenv('EB_GUROBI_LICENSE_FILE', None) - + if self.orig_license_file is None or not os.path.exists(self.cfg['license_file']): raise EasyBuildError("No existing license file specified: %s", self.orig_license_file) - + if self.cfg['copy_license_file']: self.license_file = os.path.join(self.installdir, 'gurobi.lic') else: From d1fa20a71c1e2d9fc5920f5a2d51311cb8815843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 4 May 2023 00:32:59 +0200 Subject: [PATCH 41/59] Move check for non-noneness of gurobi license file into install step --- easybuild/easyblocks/g/gurobi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/easybuild/easyblocks/g/gurobi.py b/easybuild/easyblocks/g/gurobi.py index 45b6506916..309511bb29 100644 --- a/easybuild/easyblocks/g/gurobi.py +++ b/easybuild/easyblocks/g/gurobi.py @@ -60,9 +60,6 @@ def __init__(self, *args, **kwargs): if self.orig_license_file is None: self.orig_license_file = os.getenv('EB_GUROBI_LICENSE_FILE', None) - if self.orig_license_file is None or not os.path.exists(self.cfg['license_file']): - raise EasyBuildError("No existing license file specified: %s", self.orig_license_file) - if self.cfg['copy_license_file']: self.license_file = os.path.join(self.installdir, 'gurobi.lic') else: @@ -73,6 +70,9 @@ def install_step(self): super(EB_Gurobi, self).install_step() if self.cfg['copy_license_file']: + if self.orig_license_file is None or not os.path.exists(self.cfg['license_file']): + raise EasyBuildError("No existing license file specified: %s", self.orig_license_file) + copy_file(self.orig_license_file, self.license_file) if get_software_root('Python'): From 2bc61b48c70fa5161c180a96f8d8da5cbe229115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 4 May 2023 13:52:33 +0200 Subject: [PATCH 42/59] Fix use of incorrect license file variable --- easybuild/easyblocks/g/gurobi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/g/gurobi.py b/easybuild/easyblocks/g/gurobi.py index 309511bb29..49147d9a2f 100644 --- a/easybuild/easyblocks/g/gurobi.py +++ b/easybuild/easyblocks/g/gurobi.py @@ -70,7 +70,7 @@ def install_step(self): super(EB_Gurobi, self).install_step() if self.cfg['copy_license_file']: - if self.orig_license_file is None or not os.path.exists(self.cfg['license_file']): + if self.orig_license_file is None or not os.path.exists(self.orig_license_file): raise EasyBuildError("No existing license file specified: %s", self.orig_license_file) copy_file(self.orig_license_file, self.license_file) From 53410d2989a45214a951a831782b9901792f4c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 4 May 2023 15:55:28 +0200 Subject: [PATCH 43/59] Update easybuild/easyblocks/m/matlab.py Co-authored-by: Sam Moors --- easybuild/easyblocks/m/matlab.py | 1 + 1 file changed, 1 insertion(+) diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py index a0f04b1748..b260e703de 100644 --- a/easybuild/easyblocks/m/matlab.py +++ b/easybuild/easyblocks/m/matlab.py @@ -194,6 +194,7 @@ def install_step(self): "Not a valid key", "All selected products are already installed", "The application encountered an unexpected error and needs to close", + "Error: Unable to write to", "Exiting with status -\\d", "End - Unsuccessful", ] From 84af134d2d983ff795680e38ebd8566906cc4335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Thu, 4 May 2023 15:56:03 +0200 Subject: [PATCH 44/59] Add partial support for vendoring of non-crates.io crates --- easybuild/easyblocks/generic/cargo.py | 61 +++++++++++++------ .../easyblocks/generic/cargopythonpackage.py | 2 +- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 562a1f69fe..43d9c29bcb 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -53,7 +53,7 @@ def extra_options(extra_vars=None): 'enable_tests': [True, "Enable building of tests", CUSTOM], 'offline': [True, "Build offline", CUSTOM], 'lto': [None, "Override default LTO flag ('fat', 'thin', 'off')", CUSTOM], - 'crates': [[], "List of (crate, version) tuples to use", CUSTOM], + 'crates': [[], "List of (crate, version, [repo, rev]) tuples to use", CUSTOM], }) return extra_vars @@ -74,14 +74,25 @@ def __init__(self, *args, **kwargs): env.setvar('RUST_BACKTRACE', '1') # Populate sources from "crates" list of tuples - sources = self.cfg['sources'] - for crate, version in self.cfg['crates']: - sources.append({ - 'download_filename': crate + '/' + version + '/download', - 'filename': crate + '-' + version + '.tar.gz', - 'source_urls': [CRATESIO_SOURCE], - 'alt_location': 'crates.io', - }) + sources = [] + for crate_info in self.cfg['crates']: + if len(crate_info) == 2: + crate, version = crate_info + sources.append({ + 'download_filename': crate + '/' + version + '/download', + 'filename': crate + '-' + version + '.tar.gz', + 'source_urls': [CRATESIO_SOURCE], + 'alt_location': 'crates.io', + }) + else: + crate, version, repo, rev = crate_info + url, repo_name_git = repo.rsplit('/', maxsplit=1) + sources.append({ + 'git_config': {'url': url, 'repo_name': repo_name_git[:-4], 'commit': rev}, + 'filename': crate + '-' + version + '.tar.gz', + 'source_urls': [CRATESIO_SOURCE], + }) + self.cfg.update('sources', sources) def configure_step(self): @@ -96,10 +107,24 @@ def extract_step(self): # Replace crates-io with vendored sources using build dir wide toml file in CARGO_HOME # because the rust source subdirectories might differ with python packages config_toml = os.path.join(self.cargo_home, 'config.toml') - write_file(config_toml, '[source.crates-io]\ndirectory="%s"' % self.builddir) + write_file(config_toml, '[source.vendored-sources]\ndirectory = "%s"\n\n' % self.builddir, append=True) + write_file(config_toml, '[source.crates-io]\ndirectory = "vendored-sources"\n\n', append=True) + + # also vendor sources from other git sources: + # note that one repo can contain multiple packages but we should specify the source once + git_sources = set() + for crate_info in self.cfg['crates']: + if len(crate_info) == 4: + _, _, repo, rev = crate_info + git_sources.add((repo, rev)) + for repo, rev in git_sources: + write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\ndirectory = "vendored-sources"\n\n' % ( + repo, repo, rev), append=True) + # Use environment variable since it would also be passed along to builds triggered via python packages env.setvar('CARGO_NET_OFFLINE', 'true') + # More work is needed here for git sources to work, especially those repos with multiple packages. for src in self.src: existing_dirs = set(os.listdir(self.builddir)) self.log.info("Unpacking source %s" % src['name']) @@ -182,7 +207,6 @@ def generate_crate_list(sourcedir): cargo_lock = toml.load(os.path.join(sourcedir, 'Cargo.lock')) app_name = cargo_toml['package']['name'] - print(app_name) deps = cargo_lock['package'] app_in_cratesio = False @@ -191,12 +215,15 @@ def generate_crate_list(sourcedir): for dep in deps: name = dep['name'] version = dep['version'] - if 'source' in dep and dep['source'] == 'registry+https://github.com/rust-lang/crates.io-index': + if 'source' in dep: if name == app_name: - print('check') - app_in_cratesio = True # exclude app itself, needs to be first in crates list + app_in_cratesio = True # exclude app itself, needs to be first in crates list or taken from pypi else: - crates.append((name, version)) + if dep['source'] == 'registry+https://github.com/rust-lang/crates.io-index': + crates.append((name, version)) + else: + # Lock file has revision#revision in the url for some reason. + crates.append((name, version, dep['source'].rsplit('#', maxsplit=1)[0])) else: other_crates.append((name, version)) return app_in_cratesio, crates, other_crates @@ -210,6 +237,6 @@ def generate_crate_list(sourcedir): print('crates = [') if app_in_cratesio: print(' (name, version),') - for name, version in crates: - print(" ('" + name + "', '" + version + "'),") + for crate_info in crates: + print(" ('" + "', '".join(crate_info) + "'),") print(']') diff --git a/easybuild/easyblocks/generic/cargopythonpackage.py b/easybuild/easyblocks/generic/cargopythonpackage.py index 71a8778fa4..a935e190a0 100644 --- a/easybuild/easyblocks/generic/cargopythonpackage.py +++ b/easybuild/easyblocks/generic/cargopythonpackage.py @@ -50,7 +50,7 @@ def extra_options(extra_vars=None): def __init__(self, *args, **kwargs): """Constructor for CargoPythonPackage easyblock.""" Cargo.__init__(self, *args, **kwargs) - return PythonPackage.__init__(self, *args, **kwargs) + PythonPackage.__init__(self, *args, **kwargs) def extract_step(self): """Specifically use the overloaded variant from Cargo as is populates vendored sources with checksums.""" From 348332b4fd004f9ab457677b9b7c9fd70f6babce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Fri, 5 May 2023 16:56:58 +0200 Subject: [PATCH 45/59] Fix mistake in vendoring of sources --- easybuild/easyblocks/generic/cargo.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 43d9c29bcb..69fbfb62ae 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -103,22 +103,21 @@ def extract_step(self): Unpack the source files and populate them with required .cargo-checksum.json if offline """ if self.cfg['offline']: - self.log.info("Setting vendored crates-io dir") + self.log.info("Setting vendored crates dir") # Replace crates-io with vendored sources using build dir wide toml file in CARGO_HOME # because the rust source subdirectories might differ with python packages config_toml = os.path.join(self.cargo_home, 'config.toml') write_file(config_toml, '[source.vendored-sources]\ndirectory = "%s"\n\n' % self.builddir, append=True) - write_file(config_toml, '[source.crates-io]\ndirectory = "vendored-sources"\n\n', append=True) + write_file(config_toml, '[source.crates-io]\nreplace-with = "vendored-sources"\n\n', append=True) - # also vendor sources from other git sources: - # note that one repo can contain multiple packages but we should specify the source once + # also vendor sources from other git sources (could be many crates for one git source) git_sources = set() for crate_info in self.cfg['crates']: if len(crate_info) == 4: _, _, repo, rev = crate_info git_sources.add((repo, rev)) for repo, rev in git_sources: - write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\ndirectory = "vendored-sources"\n\n' % ( + write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\nreplace-with = "vendored-sources"\n\n' % ( repo, repo, rev), append=True) # Use environment variable since it would also be passed along to builds triggered via python packages From 0803ce991acf3c2494669f7a1701293c827e9bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Fri, 5 May 2023 16:59:13 +0200 Subject: [PATCH 46/59] Break up long line --- easybuild/easyblocks/generic/cargo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 69fbfb62ae..323573eb5b 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -117,8 +117,8 @@ def extract_step(self): _, _, repo, rev = crate_info git_sources.add((repo, rev)) for repo, rev in git_sources: - write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\nreplace-with = "vendored-sources"\n\n' % ( - repo, repo, rev), append=True) + write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\n' \ + 'replace-with = "vendored-sources"\n\n' % (repo, repo, rev), append=True) # Use environment variable since it would also be passed along to builds triggered via python packages env.setvar('CARGO_NET_OFFLINE', 'true') From 480ffdc0076f5069a0e8be3b68decbdd2cbe2133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Fri, 5 May 2023 17:09:42 +0200 Subject: [PATCH 47/59] Fix style --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 323573eb5b..c538f5c244 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -117,7 +117,7 @@ def extract_step(self): _, _, repo, rev = crate_info git_sources.add((repo, rev)) for repo, rev in git_sources: - write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\n' \ + write_file(config_toml, '[source."%s"]\ngit = "%s"\nrev = "%s"\n' 'replace-with = "vendored-sources"\n\n' % (repo, repo, rev), append=True) # Use environment variable since it would also be passed along to builds triggered via python packages From b34fd4613ff19950b1ea911d7184578e618a7097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=96hman?= Date: Wed, 10 May 2023 18:29:14 +0200 Subject: [PATCH 48/59] Switch cargo to extensioneasyblock to allow use as an extension --- easybuild/easyblocks/generic/cargo.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index c538f5c244..50ef5542b5 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -33,7 +33,7 @@ import easybuild.tools.environment as env from easybuild.tools.build_log import EasyBuildError from easybuild.framework.easyconfig import CUSTOM -from easybuild.framework.easyblock import EasyBlock +from easybuild.framework.extensioneasyblock import ExtensionEasyBlock from easybuild.tools.filetools import extract_file, change_dir from easybuild.tools.run import run_cmd from easybuild.tools.config import build_option @@ -42,13 +42,13 @@ CRATESIO_SOURCE = "https://crates.io/api/v1/crates" -class Cargo(EasyBlock): +class Cargo(ExtensionEasyBlock): """Support for installing Cargo packages (Rust)""" @staticmethod def extra_options(extra_vars=None): """Define extra easyconfig parameters specific to Cargo""" - extra_vars = EasyBlock.extra_options(extra_vars) + extra_vars = ExtensionEasyBlock.extra_options(extra_vars) extra_vars.update({ 'enable_tests': [True, "Enable building of tests", CUSTOM], 'offline': [True, "Build offline", CUSTOM], From 6a9cba4ee8eac503ab68378ff4287cfb60d05f67 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Tue, 23 May 2023 15:32:28 +0200 Subject: [PATCH 49/59] force building torchvision with CUDA support if CUDA is included as dependency by setting $FORCE_CUDA --- easybuild/easyblocks/t/torchvision.py | 48 +++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/easybuild/easyblocks/t/torchvision.py b/easybuild/easyblocks/t/torchvision.py index 197ff15c67..7ef971a8b9 100644 --- a/easybuild/easyblocks/t/torchvision.py +++ b/easybuild/easyblocks/t/torchvision.py @@ -26,12 +26,12 @@ EasyBuild support for building and installing torchvision, implemented as an easyblock @author: Alexander Grund (TU Dresden) +@author: Kenneth Hoste (HPC-UGent) """ - from easybuild.easyblocks.generic.pythonpackage import PythonPackage from easybuild.tools.build_log import EasyBuildError from easybuild.tools.config import build_option -from easybuild.tools.modules import get_software_root, get_software_version +from easybuild.tools.modules import get_software_version import easybuild.tools.environment as env @@ -40,24 +40,60 @@ class EB_torchvision(PythonPackage): @staticmethod def extra_options(): - """Change some defaults.""" + """Change some defaults for easyconfig parameters.""" extra_vars = PythonPackage.extra_options() extra_vars['use_pip'][0] = True extra_vars['download_dep_fail'][0] = True extra_vars['sanity_pip_check'][0] = True return extra_vars + def __init__(self, *args, **kwargs): + """Initialize torchvision easyblock.""" + super(EB_torchvision, self).__init__(*args, **kwargs) + + dep_names = set(dep['name'] for dep in self.cfg.dependencies()) + + # require that PyTorch is listed as dependency + if 'PyTorch' not in dep_names: + raise EasyBuildError('PyTorch not found as a dependency') + + # enable building with GPU support if CUDA is included as dependency + if 'CUDA' in dep_names: + self.with_cuda = True + else: + self.with_cuda = False + def configure_step(self): """Set up torchvision config""" - if not get_software_root('PyTorch'): - raise EasyBuildError('PyTorch not found as a dependency') # Note: Those can be overwritten by e.g. preinstallopts env.setvar('BUILD_VERSION', self.version) env.setvar('PYTORCH_VERSION', get_software_version('PyTorch')) - if get_software_root('CUDA'): + + if self.with_cuda: + # make sure that torchvision is installed with CUDA support by setting $FORCE_CUDA + env.setvar('FORCE_CUDA', '1') + # specify CUDA compute capabilities via $TORCH_CUDA_ARCH_LIST cuda_cc = self.cfg['cuda_compute_capabilities'] or build_option('cuda_compute_capabilities') if cuda_cc: env.setvar('TORCH_CUDA_ARCH_LIST', ';'.join(cuda_cc)) super(EB_torchvision, self).configure_step() + + def sanity_check_step(self): + """Custom sanity check for torchvision.""" + custom_commands = [] + + # check whether torchvision was indeed built with CUDA support, + # cfr. https://discuss.pytorch.org/t/notimplementederror-could-not-run-torchvision-nms-with-arguments-from-\ + # the-cuda-backend-this-could-be-because-the-operator-doesnt-exist-for-this-backend/132352/4 + if self.with_cuda: + python_code = '; '.join([ + "import torch, torchvision", + "boxes = torch.tensor([[0., 1., 2., 3.]]).to('cuda')", + "scores = torch.randn(1).to('cuda')", + "print(torchvision.ops.nms(boxes, scores, 0.5))", + ]) + custom_commands.append('python -c "%s"' % python_code) + + super(EB_torchvision, self).sanity_check_step(custom_commands=custom_commands) From f912a8416e00095d46681af5519a829a0cb43ceb Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Tue, 23 May 2023 16:20:35 +0200 Subject: [PATCH 50/59] add required PyTorch dependency to test easyconfig used to initialize torchvision easyblock --- test/easyblocks/init_easyblocks.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/easyblocks/init_easyblocks.py b/test/easyblocks/init_easyblocks.py index 9f7a2a1a09..9a53f4b898 100644 --- a/test/easyblocks/init_easyblocks.py +++ b/test/easyblocks/init_easyblocks.py @@ -96,7 +96,7 @@ def tearDown(self): self.log.error("Failed to remove %s: %s" % (self.eb_file, err)) -def template_init_test(self, easyblock, name='foo', version='1.3.2', toolchain=None): +def template_init_test(self, easyblock, name='foo', version='1.3.2', toolchain=None, deps=None): """Test whether all easyblocks can be initialized.""" def check_extra_options_format(extra_options): @@ -164,6 +164,9 @@ def check_extra_options_format(extra_options): test_param = 'foo' extra_txt += '%s = "%s"\n' % (key, test_param) + if deps: + extra_txt += 'dependencies = %s' % str(deps) + # write easyconfig file self.write_ec(ebname, name=name, version=version, toolchain=toolchain, extratxt=extra_txt) @@ -224,6 +227,9 @@ def innertest(self): elif easyblock_fn == 'openssl_wrapper.py': # easyblock to create OpenSSL wrapper expects an OpenSSL version innertest = make_inner_test(easyblock, version='1.1') + elif easyblock_fn == 'torchvision.py': + # torchvision easyblock requires that PyTorch is listed as dependency + innertest = make_inner_test(easyblock, name='torchvision', deps=[('PyTorch', '1.12.1')]) else: innertest = make_inner_test(easyblock) From d48fdc9ed1e2dacbad71ded5d6c5d5c4b930373c Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Tue, 23 May 2023 16:27:13 +0200 Subject: [PATCH 51/59] also add required PyTorch dependency when test torchvision easyblock with --module-only --- test/easyblocks/module.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/easyblocks/module.py b/test/easyblocks/module.py index 65b91f942c..e75a707532 100644 --- a/test/easyblocks/module.py +++ b/test/easyblocks/module.py @@ -333,7 +333,7 @@ def template_module_only_test(self, easyblock, name, version='1.3.2', extra_txt= self.writeEC(ebname, name=name, version=version, extratxt=extra_txt, toolchain=toolchain) # take into account that for some easyblock, particular dependencies are hard required early on - # (in prepare_step for exampel); + # (in prepare_step for example); # we just set the corresponding $EBROOT* environment variables here to fool it... req_deps = { # QScintilla easyblock requires that either PyQt or PyQt5 are available as dependency @@ -460,6 +460,10 @@ def innertest(self): elif eb_fn == 'openssl_wrapper.py': # easyblock to create OpenSSL wrapper expects an OpenSSL version innertest = make_inner_test(easyblock, name='OpenSSL-wrapper', version='1.1') + elif eb_fn == 'torchvision.py': + # torchvision easyblock requires that PyTorch is listed as dependency + extra_txt = "dependencies = [('PyTorch', '1.12.1')]" + innertest = make_inner_test(easyblock, name='torchvision', extra_txt=extra_txt) elif eb_fn == 'ucx_plugins.py': # install fake ucx_info command (used in make_module_extra) tmpdir = tempfile.mkdtemp() From eaab6fafd5ea9148687a2aeef1e0025cc8b22744 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Tue, 23 May 2023 16:41:36 +0200 Subject: [PATCH 52/59] create empty module file for requied PyTorch dependency when testing torchvision easyblock --- test/easyblocks/module.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/easyblocks/module.py b/test/easyblocks/module.py index e75a707532..db44834031 100644 --- a/test/easyblocks/module.py +++ b/test/easyblocks/module.py @@ -118,7 +118,7 @@ class ModuleOnlyTest(TestCase): def writeEC(self, easyblock, name='foo', version='1.3.2', extratxt='', toolchain=None): """ create temporary easyconfig file """ if toolchain is None: - toolchain = {'name': 'dummy', 'version': 'dummy'} + toolchain = {'name': 'system', 'version': 'system'} txt = '\n'.join([ 'easyblock = "%s"', @@ -434,8 +434,9 @@ def innertest(self): for prgenv in ['PrgEnv-cray', 'PrgEnv-gnu', 'PrgEnv-intel', 'PrgEnv-pgi']: write_file(os.path.join(TMPDIR, 'modules', 'all', prgenv, '1.2.3'), "#%Module") - # add foo/1.3.2.1.1 module, required for testing ModuleAlias easyblock - write_file(os.path.join(TMPDIR, 'modules', 'all', 'foo', '1.2.3.4.5'), "#%Module") + # add empty module files for dependencies that are required for testing easyblocks + for dep_mod_name in ('foo/1.2.3.4.5', 'PyTorch/1.12.1'): + write_file(os.path.join(TMPDIR, 'modules', 'all', dep_mod_name), "#%Module") for easyblock in easyblocks: eb_fn = os.path.basename(easyblock) From 45202911698f35a307f7bbc350ef6de4bb7e8929 Mon Sep 17 00:00:00 2001 From: Ake Sandgren Date: Tue, 23 May 2023 16:50:50 +0200 Subject: [PATCH 53/59] comsol: Fix exec permission on files in arch bindir --- easybuild/easyblocks/c/comsol.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/easybuild/easyblocks/c/comsol.py b/easybuild/easyblocks/c/comsol.py index 09b6e44fcd..38d778a623 100644 --- a/easybuild/easyblocks/c/comsol.py +++ b/easybuild/easyblocks/c/comsol.py @@ -114,6 +114,11 @@ def install_step(self): # make sure setup script is executable adjust_permissions(setup_script, stat.S_IXUSR) + # make sure binaries in arch bindir is executable + archpath = os.path.join(self.start_dir, 'bin', 'glnxa64') + adjust_permissions(os.path.join(archpath, 'inflate'), stat.S_IXUSR) + adjust_permissions(os.path.join(archpath, 'setuplauncher'), stat.S_IXUSR) + # make sure $DISPLAY is not defined, which may lead to (hard to trace) problems # this is a workaround for not being able to specify --nodisplay to the install scripts env.unset_env_vars(['DISPLAY']) From 8c1662302a02b74e2fbfcd5640d3fd96a97f6245 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Wed, 24 May 2023 16:54:22 +0200 Subject: [PATCH 54/59] enhance Cargo constructor to avoid processing list of crates multiple times into sources --- easybuild/easyblocks/generic/cargo.py | 56 ++++++++++++++++----------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 50ef5542b5..0918f9b881 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -73,30 +73,36 @@ def __init__(self, *args, **kwargs): env.setvar('RUST_LOG', 'DEBUG') env.setvar('RUST_BACKTRACE', '1') - # Populate sources from "crates" list of tuples - sources = [] - for crate_info in self.cfg['crates']: - if len(crate_info) == 2: - crate, version = crate_info - sources.append({ - 'download_filename': crate + '/' + version + '/download', - 'filename': crate + '-' + version + '.tar.gz', - 'source_urls': [CRATESIO_SOURCE], - 'alt_location': 'crates.io', - }) - else: - crate, version, repo, rev = crate_info - url, repo_name_git = repo.rsplit('/', maxsplit=1) - sources.append({ - 'git_config': {'url': url, 'repo_name': repo_name_git[:-4], 'commit': rev}, - 'filename': crate + '-' + version + '.tar.gz', - 'source_urls': [CRATESIO_SOURCE], - }) + # Populate sources from "crates" list of tuples (only once) + if self.cfg['crates']: + # copy list of crates, so we can wipe 'crates' easyconfig paramter, + # to avoid that creates are processed into 'sources' easyconfig parameter again + # when easyblock is initialized again using same parsed easyconfig + # (for example when check_sha256_checksums function is called, like in easyconfigs test suite) + self.crates = self.cfg['crates'][:] + sources = [] + for crate_info in self.cfg['crates']: + if len(crate_info) == 2: + crate, version = crate_info + sources.append({ + 'download_filename': crate + '/' + version + '/download', + 'filename': crate + '-' + version + '.tar.gz', + 'source_urls': [CRATESIO_SOURCE], + 'alt_location': 'crates.io', + }) + else: + crate, version, repo, rev = crate_info + url, repo_name_git = repo.rsplit('/', maxsplit=1) + sources.append({ + 'git_config': {'url': url, 'repo_name': repo_name_git[:-4], 'commit': rev}, + 'filename': crate + '-' + version + '.tar.gz', + 'source_urls': [CRATESIO_SOURCE], + }) - self.cfg.update('sources', sources) + self.cfg.update('sources', sources) - def configure_step(self): - pass + # set 'crates' easyconfig parameter to empty list to prevent re-processing into sources + self.cfg['crates'] = [] def extract_step(self): """ @@ -112,7 +118,7 @@ def extract_step(self): # also vendor sources from other git sources (could be many crates for one git source) git_sources = set() - for crate_info in self.cfg['crates']: + for crate_info in self.crates: if len(crate_info) == 4: _, _, repo, rev = crate_info git_sources.add((repo, rev)) @@ -144,6 +150,10 @@ def extract_step(self): chkfile = os.path.join(self.builddir, cratedir, '.cargo-checksum.json') write_file(chkfile, '{"files":{},"package":"%s"}' % chksum) + def configure_step(self): + """Empty configuration step.""" + pass + @property def profile(self): return 'debug' if self.toolchain.options.get('debug', None) else 'release' From f6c717a5383ef6f5b02b0b7814884c5ac458de6f Mon Sep 17 00:00:00 2001 From: ocaisa Date: Wed, 24 May 2023 17:08:02 +0200 Subject: [PATCH 55/59] Update easybuild/easyblocks/generic/cargo.py --- easybuild/easyblocks/generic/cargo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/generic/cargo.py b/easybuild/easyblocks/generic/cargo.py index 0918f9b881..b511b851bc 100644 --- a/easybuild/easyblocks/generic/cargo.py +++ b/easybuild/easyblocks/generic/cargo.py @@ -75,7 +75,7 @@ def __init__(self, *args, **kwargs): # Populate sources from "crates" list of tuples (only once) if self.cfg['crates']: - # copy list of crates, so we can wipe 'crates' easyconfig paramter, + # copy list of crates, so we can wipe 'crates' easyconfig parameter, # to avoid that creates are processed into 'sources' easyconfig parameter again # when easyblock is initialized again using same parsed easyconfig # (for example when check_sha256_checksums function is called, like in easyconfigs test suite) From 37ffbf6d001b82e1c3b117ddfc4f53a7b406bcdd Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Thu, 25 May 2023 11:59:41 +0000 Subject: [PATCH 56/59] Patch gcc.c* only for older sysroot-ed installations. Check the contents of libc.so: only if the entries are prefixed, patch gcc.c (or gcc.cc for GCC 12+), to account for the changes in https://github.com/gentoo/gentoo/pull/28851 --- easybuild/easyblocks/g/gcc.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/g/gcc.py b/easybuild/easyblocks/g/gcc.py index 9bf640253c..7ee469763e 100644 --- a/easybuild/easyblocks/g/gcc.py +++ b/easybuild/easyblocks/g/gcc.py @@ -48,7 +48,7 @@ from easybuild.tools.build_log import EasyBuildError from easybuild.tools.config import build_option from easybuild.tools.filetools import apply_regex_substitutions, change_dir, copy_file, move_file, symlink -from easybuild.tools.filetools import which, write_file +from easybuild.tools.filetools import which, read_file, write_file from easybuild.tools.modules import get_software_root from easybuild.tools.run import run_cmd from easybuild.tools.systemtools import RISCV, check_os_dependency, get_cpu_architecture, get_cpu_family @@ -357,6 +357,20 @@ def configure_step(self): # (see https://gcc.gnu.org/install/configure.html) self.cfg.update('configopts', '--with-sysroot=%s' % sysroot) + libc_so_candidates = [os.path.join(sysroot, x, 'libc.so') for x in + ['lib', 'lib64', os.path.join('usr', 'lib'), os.path.join('usr', 'lib64')]] + for libc_so in libc_so_candidates: + if os.path.exists(libc_so): + # only patch gcc.c or gcc.cc if entries in libc.so are prefixed with sysroot + if '\nGROUP ( ' + sysroot in read_file(libc_so): + gccfile = os.path.join('gcc', 'gcc.c') + # renamed to gcc.cc in GCC 12 + if not os.path.exists(gccfile): + gccfile = os.path.join('gcc', 'gcc.cc') + # avoid that --sysroot is passed to linker by patching value for SYSROOT_SPEC in gcc/gcc.c* + apply_regex_substitutions(gccfile, [('--sysroot=%R', '')]) + break + # prefix dynamic linkers with sysroot # this patches lines like: # #define GLIBC_DYNAMIC_LINKER64 "/lib64/ld-linux-x86-64.so.2" From cb078d85a9bb12c447a73577137fcd8d5568b819 Mon Sep 17 00:00:00 2001 From: Sebastian Achilles Date: Fri, 26 May 2023 11:40:45 +0200 Subject: [PATCH 57/59] prepare release notes for EasyBuild v4.7.2 + bump version to 4.7.2 --- RELEASE_NOTES | 17 +++++++++++++++++ easybuild/easyblocks/__init__.py | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 96346e430c..4210cd2941 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -5,6 +5,23 @@ These release notes can also be consulted at http://easybuild.readthedocs.org/en The latest version of easybuild-easyblocks provides 248 software-specific easyblocks and 39 generic easyblocks. +v4.7.2 (May 30th 2023) +---------------------- + +- new generic easyblock for installing Rust crates with cargo (#2902) +- minor enhancements and updates, including: + - let MATLAB easyblock raise an error if the MATLAB installation key is not provided (#2905) + - print message to inform that GPU package (instead of Kokkos) is used for LAMMPS (#2906) + - enhance PyTorch easyblock to use FlexiBLAS for PyTorch >= 1.11.0 (#2915) +- various bug fixes, including: + - use custom RPATH sanity check for Go packages that doesn't actually check for an RPATH section in the binary (#2913) + - use string '0' to avoid problems when openssl version is not determined (#2914) + - add output log to MATLAB installs, actually parse for common errors (#2924) + - enhance Gurobi easyblock to allow using $EB_GUROBI_LICENSE_FILE environment variable (#2926) + - force building torchvision with CUDA support if CUDA is included as dependency by setting `$FORCE_CUDA` (#2931) + - fix exec permission on files in arch bindir for COMSOL (#2932) + - enhance Cargo constructor to avoid processing list of crates multiple times into sources (#2934) + v4.7.1 (March 20th 2023) ------------------------ diff --git a/easybuild/easyblocks/__init__.py b/easybuild/easyblocks/__init__.py index fdd68d6024..f740a2523e 100644 --- a/easybuild/easyblocks/__init__.py +++ b/easybuild/easyblocks/__init__.py @@ -43,7 +43,7 @@ # recent setuptools versions will *TRANSFORM* something like 'X.Y.Zdev' into 'X.Y.Z.dev0', with a warning like # UserWarning: Normalizing '2.4.0dev' to '2.4.0.dev0' # This causes problems further up the dependency chain... -VERSION = LooseVersion('4.7.2.dev0') +VERSION = LooseVersion('4.7.2') UNKNOWN = 'UNKNOWN' From 7c7e756a17f5111ae83d1980d274f75f0e0b89d0 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Sat, 27 May 2023 11:24:43 +0200 Subject: [PATCH 58/59] minor tweaks for EasyBuild v4.7.2 in release notes + fix release date --- RELEASE_NOTES | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 4210cd2941..350cf6b031 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -3,12 +3,13 @@ For more detailed information, please see the git log. These release notes can also be consulted at http://easybuild.readthedocs.org/en/latest/Release_notes.html. -The latest version of easybuild-easyblocks provides 248 software-specific easyblocks and 39 generic easyblocks. +The latest version of easybuild-easyblocks provides 248 software-specific easyblocks and 41 generic easyblocks. -v4.7.2 (May 30th 2023) ----------------------- -- new generic easyblock for installing Rust crates with cargo (#2902) +v4.7.2 (27 May 2023) +-------------------- + +- new generic easyblock for installing Rust crates with cargo: Cargo and CargoPythonPackage (#2902, #2934) - minor enhancements and updates, including: - let MATLAB easyblock raise an error if the MATLAB installation key is not provided (#2905) - print message to inform that GPU package (instead of Kokkos) is used for LAMMPS (#2906) @@ -20,7 +21,6 @@ v4.7.2 (May 30th 2023) - enhance Gurobi easyblock to allow using $EB_GUROBI_LICENSE_FILE environment variable (#2926) - force building torchvision with CUDA support if CUDA is included as dependency by setting `$FORCE_CUDA` (#2931) - fix exec permission on files in arch bindir for COMSOL (#2932) - - enhance Cargo constructor to avoid processing list of crates multiple times into sources (#2934) v4.7.1 (March 20th 2023) ------------------------ From 42c96e4d81ee56ad8a2f308b3bd1c99745f6617f Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Sat, 27 May 2023 21:01:56 +0200 Subject: [PATCH 59/59] include #2921 in release notes for EasyBuild v4.7.2 --- RELEASE_NOTES | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 350cf6b031..f117aa07a1 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -17,6 +17,7 @@ v4.7.2 (27 May 2023) - various bug fixes, including: - use custom RPATH sanity check for Go packages that doesn't actually check for an RPATH section in the binary (#2913) - use string '0' to avoid problems when openssl version is not determined (#2914) + - update GCC easyblock to ensure that --sysroot is passed to linker (but only when it needs to be) (#2921) - add output log to MATLAB installs, actually parse for common errors (#2924) - enhance Gurobi easyblock to allow using $EB_GUROBI_LICENSE_FILE environment variable (#2926) - force building torchvision with CUDA support if CUDA is included as dependency by setting `$FORCE_CUDA` (#2931)