Skip to content
Snippets Groups Projects
Commit 6e372e3f authored by Lukáš Krupčík's avatar Lukáš Krupčík
Browse files

Merge branch 'it4i-karolina' into 'master'

fix

See merge request !6
parents 47f9e057 9cdc7233
No related branches found
No related tags found
1 merge request!6fix
##
# Copyright 2009-2021 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 <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for AMD Core Math Library (AOCL), implemented as an easyblock
@author: Lukas Krupcik (IT4Innovations)
"""
import os
from distutils.version import LooseVersion
from easybuild.framework.easyblock import EasyBlock
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.run import run_cmd_qa
from easybuild.tools.systemtools import get_shared_lib_ext
class EB_AOCL(EasyBlock):
def __init__(self, *args, **kwargs):
"""Constructor, adds extra class variables."""
super(EB_AOCL, self).__init__(*args, **kwargs)
self.basedir = '%s' % (self.version)
def configure_step(self):
"""No custom configure step for AOCL."""
pass
def build_step(self):
"""No custom build step for AOCL."""
pass
def install_step(self):
"""Install by running install script."""
cmd = "./install.sh -t %s" % (self.installdir)
qa = {'The directory will be created if it does not already exist. >': self.installdir}
run_cmd_qa(cmd, qa, log_all=True, simple=True)
def make_module_extra(self):
"""Add extra entries in module file (various paths)."""
txt = super(EB_AOCL, self).make_module_extra()
basepaths = ["%s" % (self.basedir)]
txt += self.module_generator.set_environment('AOCL_ROOT', "%s/%s" % (self.installdir, self.basedir))
for path in basepaths:
txt += self.module_generator.prepend_paths('PATH', os.path.join(path, 'amd-fftw/bin'))
for path in basepaths:
txt += self.module_generator.prepend_paths('CPATH', os.path.join(path, 'include'))
for key in ['LD_LIBRARY_PATH', 'LIBRARY_PATH']:
for path in basepaths:
txt += self.module_generator.prepend_paths(key, os.path.join(path, 'lib'))
return txt
def sanity_check_step(self):
"""Custom sanity check for AOCL."""
custom_paths = {
'files': [],
'dirs': ['%s/aocc/include' % (self.version), '%s/aocc/lib' % (self.version), '%s/aocc/amd-fftw' % (self.version)]
}
super(EB_AOCL, self).sanity_check_step(custom_paths=custom_paths)
# #
# 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 <http://www.gnu.org/licenses/>.
# #
"""
EasyBuild support for installing the Intel MPI library, implemented as an easyblock
@author: Stijn De Weirdt (Ghent University)
@author: Dries Verdegem (Ghent University)
@author: Kenneth Hoste (Ghent University)
@author: Pieter De Baets (Ghent University)
@author: Jens Timmerman (Ghent University)
@author: Damian Alvarez (Forschungszentrum Juelich GmbH)
@author: Alex Domingo (Vrije Universiteit Brussel)
"""
import os
from distutils.version import LooseVersion
import easybuild.tools.toolchain as toolchain
from easybuild.easyblocks.generic.intelbase import IntelBase, ACTIVATION_NAME_2012, LICENSE_FILE_NAME_2012
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.config import build_option
from easybuild.tools.filetools import apply_regex_substitutions, change_dir, extract_file, mkdir, write_file
from easybuild.tools.modules import get_software_root
from easybuild.tools.run import run_cmd
from easybuild.tools.systemtools import get_shared_lib_ext
from easybuild.tools.toolchain.mpi import get_mpi_cmd_template
class EB_impi(IntelBase):
"""
Support for installing Intel MPI library
"""
@staticmethod
def extra_options():
extra_vars = {
'libfabric_configopts': ['', 'Configure options for the provided libfabric', CUSTOM],
'libfabric_rebuild': [True, 'Try to rebuild internal libfabric instead of using provided binary', CUSTOM],
'ofi_internal': [True, 'Use internal shipped libfabric instead of external libfabric', CUSTOM],
'set_mpi_wrappers_compiler': [False, 'Override default compiler used by MPI wrapper commands', CUSTOM],
'set_mpi_wrapper_aliases_gcc': [False, 'Set compiler for mpigcc/mpigxx via aliases', CUSTOM],
'set_mpi_wrapper_aliases_intel': [False, 'Set compiler for mpiicc/mpiicpc/mpiifort via aliases', CUSTOM],
'set_mpi_wrappers_all': [False, 'Set (default) compiler for all MPI wrapper commands', CUSTOM],
}
return IntelBase.extra_options(extra_vars)
def prepare_step(self, *args, **kwargs):
if LooseVersion(self.version) >= LooseVersion('2017.2.174'):
kwargs['requires_runtime_license'] = False
super(EB_impi, self).prepare_step(*args, **kwargs)
else:
super(EB_impi, self).prepare_step(*args, **kwargs)
def install_step(self):
"""
Actual installation
- create silent cfg file
- execute command
"""
impiver = LooseVersion(self.version)
if impiver >= LooseVersion('2021'):
super(EB_impi, self).install_step()
elif impiver >= LooseVersion('4.0.1'):
# impi starting from version 4.0.1.x uses standard installation procedure.
silent_cfg_names_map = {}
if impiver < LooseVersion('4.1.1'):
# since impi v4.1.1, silent.cfg has been slightly changed to be 'more standard'
silent_cfg_names_map.update({
'activation_name': ACTIVATION_NAME_2012,
'license_file_name': LICENSE_FILE_NAME_2012,
})
super(EB_impi, self).install_step(silent_cfg_names_map=silent_cfg_names_map)
# impi v4.1.1 and v5.0.1 installers create impi/<version> subdir, so stuff needs to be moved afterwards
if impiver == LooseVersion('4.1.1.036') or impiver >= LooseVersion('5.0.1.035'):
super(EB_impi, self).move_after_install()
else:
# impi up until version 4.0.0.x uses custom installation procedure.
silent = """[mpi]
INSTALLDIR=%(ins)s
LICENSEPATH=%(lic)s
INSTALLMODE=NONRPM
INSTALLUSER=NONROOT
UPDATE_LD_SO_CONF=NO
PROCEED_WITHOUT_PYTHON=yes
AUTOMOUNTED_CLUSTER=yes
EULA=accept
[mpi-rt]
INSTALLDIR=%(ins)s
LICENSEPATH=%(lic)s
INSTALLMODE=NONRPM
INSTALLUSER=NONROOT
UPDATE_LD_SO_CONF=NO
PROCEED_WITHOUT_PYTHON=yes
AUTOMOUNTED_CLUSTER=yes
EULA=accept
""" % {'lic': self.license_file, 'ins': self.installdir}
# already in correct directory
silentcfg = os.path.join(os.getcwd(), "silent.cfg")
write_file(silentcfg, silent)
self.log.debug("Contents of %s: %s", silentcfg, silent)
tmpdir = os.path.join(os.getcwd(), self.version, 'mytmpdir')
mkdir(tmpdir, parents=True)
cmd = "./install.sh --tmp-dir=%s --silent=%s" % (tmpdir, silentcfg)
run_cmd(cmd, log_all=True, simple=True)
# recompile libfabric (if requested)
# some Intel MPI versions (like 2019 update 6) no longer ship libfabric sources
libfabric_path = os.path.join(self.installdir, 'libfabric')
if impiver >= LooseVersion('2019') and self.cfg['libfabric_rebuild']:
if self.cfg['ofi_internal']:
libfabric_src_tgz_fn = 'src.tgz'
if os.path.exists(os.path.join(libfabric_path, libfabric_src_tgz_fn)):
change_dir(libfabric_path)
srcdir = extract_file(libfabric_src_tgz_fn, os.getcwd(), change_into_dir=False)
change_dir(srcdir)
libfabric_installpath = os.path.join(self.installdir, 'intel64', 'libfabric')
make = 'make'
if self.cfg['parallel']:
make += ' -j %d' % self.cfg['parallel']
cmds = [
'./configure --prefix=%s %s' % (libfabric_installpath, self.cfg['libfabric_configopts']),
make,
'make install'
]
for cmd in cmds:
run_cmd(cmd, log_all=True, simple=True)
else:
self.log.info("Rebuild of libfabric is requested, but %s does not exist, so skipping...",
libfabric_src_tgz_fn)
else:
raise EasyBuildError("Rebuild of libfabric is requested, but ofi_internal is set to False.")
def post_install_step(self):
"""Custom post install step for IMPI, fix broken env scripts after moving installed files."""
super(EB_impi, self).post_install_step()
impiver = LooseVersion(self.version)
if impiver >= LooseVersion('2021'):
self.log.info("No post-install action for impi v%s", self.version)
elif impiver == LooseVersion('4.1.1.036') or impiver >= LooseVersion('5.0.1.035'):
if impiver >= LooseVersion('2018.0.128'):
script_paths = [os.path.join('intel64', 'bin')]
else:
script_paths = [os.path.join('intel64', 'bin'), os.path.join('mic', 'bin')]
# fix broken env scripts after the move
regex_subs = [(r"^setenv I_MPI_ROOT.*", r"setenv I_MPI_ROOT %s" % self.installdir)]
for script in [os.path.join(script_path, 'mpivars.csh') for script_path in script_paths]:
apply_regex_substitutions(os.path.join(self.installdir, script), regex_subs)
regex_subs = [(r"^(\s*)I_MPI_ROOT=[^;\n]*", r"\1I_MPI_ROOT=%s" % self.installdir)]
for script in [os.path.join(script_path, 'mpivars.sh') for script_path in script_paths]:
apply_regex_substitutions(os.path.join(self.installdir, script), regex_subs)
# fix 'prefix=' in compiler wrapper scripts after moving installation (see install_step)
wrappers = ['mpif77', 'mpif90', 'mpigcc', 'mpigxx', 'mpiicc', 'mpiicpc', 'mpiifort']
regex_subs = [(r"^prefix=.*", r"prefix=%s" % self.installdir)]
for script_dir in script_paths:
for wrapper in wrappers:
wrapper_path = os.path.join(self.installdir, script_dir, wrapper)
if os.path.exists(wrapper_path):
apply_regex_substitutions(wrapper_path, regex_subs)
def sanity_check_step(self):
"""Custom sanity check paths for IMPI."""
impi_ver = LooseVersion(self.version)
suff = '64'
if self.cfg['m32']:
suff = ''
mpi_mods = ['mpi.mod']
if impi_ver > LooseVersion('4.0'):
mpi_mods.extend(['mpi_base.mod', 'mpi_constants.mod', 'mpi_sizeofs.mod'])
if impi_ver >= LooseVersion('2021'):
mpi_subdir = os.path.join('mpi', self.version)
bin_dir = os.path.join(mpi_subdir, 'bin')
include_dir = os.path.join(mpi_subdir, 'include')
lib_dir = os.path.join(mpi_subdir, 'lib', 'release')
elif impi_ver >= LooseVersion('2019'):
bin_dir = os.path.join('intel64', 'bin')
include_dir = os.path.join('intel64', 'include')
lib_dir = os.path.join('intel64', 'lib', 'release')
else:
bin_dir = 'bin%s' % suff
include_dir = 'include%s' % suff
lib_dir = 'lib%s' % suff
mpi_mods.extend(['i_malloc.h'])
shlib_ext = get_shared_lib_ext()
custom_paths = {
'files': [os.path.join(bin_dir, 'mpi%s' % x) for x in ['icc', 'icpc', 'ifort']] +
[os.path.join(include_dir, 'mpi%s.h' % x) for x in ['cxx', 'f', '', 'o', 'of']] +
[os.path.join(include_dir, x) for x in mpi_mods] +
[os.path.join(lib_dir, 'libmpi.%s' % shlib_ext)] +
[os.path.join(lib_dir, 'libmpi.a')],
'dirs': [],
}
custom_commands = []
if build_option('mpi_tests'):
if impi_ver >= LooseVersion('2017'):
# Add minimal test program to sanity checks
if impi_ver >= LooseVersion('2021'):
impi_testsrc = os.path.join(self.installdir, 'mpi', self.version, 'test', 'test.c')
else:
impi_testsrc = os.path.join(self.installdir, 'test', 'test.c')
impi_testexe = os.path.join(self.builddir, 'mpi_test')
self.log.info("Adding minimal MPI test program to sanity checks: %s", impi_testsrc)
# Build test program with appropriate compiler from current toolchain
comp_fam = self.toolchain.comp_family()
if comp_fam == toolchain.INTELCOMP:
build_comp = 'mpiicc'
else:
build_comp = 'mpicc'
build_cmd = "%s %s -o %s" % (build_comp, impi_testsrc, impi_testexe)
# Execute test program with appropriate MPI executable for target toolchain
params = {'nr_ranks': self.cfg['parallel'], 'cmd': impi_testexe}
mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.INTELMPI, params, mpi_version=self.version)
custom_commands.extend([
build_cmd, # build test program
#mpi_cmd_tmpl % params, # run test program
])
super(EB_impi, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
def make_module_req_guess(self):
"""
A dictionary of possible directories to look for
"""
guesses = super(EB_impi, self).make_module_req_guess()
if self.cfg['m32']:
lib_dirs = ['lib', 'lib/ia32', 'ia32/lib']
guesses.update({
'PATH': ['bin', 'bin/ia32', 'ia32/bin'],
'LD_LIBRARY_PATH': lib_dirs,
'LIBRARY_PATH': lib_dirs,
'MIC_LD_LIBRARY_PATH': ['mic/lib'],
})
else:
manpath = 'man'
impi_ver = LooseVersion(self.version)
if impi_ver >= LooseVersion('2021'):
mpi_subdir = os.path.join('mpi', self.version)
lib_dirs = [
os.path.join(mpi_subdir, 'lib'),
os.path.join(mpi_subdir, 'lib', 'release'),
os.path.join(mpi_subdir, 'libfabric', 'lib'),
]
include_dirs = [os.path.join(mpi_subdir, 'include')]
path_dirs = [
os.path.join(mpi_subdir, 'bin'),
os.path.join(mpi_subdir, 'libfabric', 'bin'),
]
manpath = os.path.join(mpi_subdir, 'man')
if self.cfg['ofi_internal']:
libfabric_dir = os.path.join('mpi', self.version, 'libfabric')
lib_dirs.append(os.path.join(libfabric_dir, 'lib'))
path_dirs.append(os.path.join(libfabric_dir, 'bin'))
guesses['FI_PROVIDER_PATH'] = [os.path.join(libfabric_dir, 'lib', 'prov')]
elif impi_ver >= LooseVersion('2019'):
# The "release" library is default in v2019. Give it precedence over intel64/lib.
# (remember paths are *prepended*, so the last path in the list has highest priority)
lib_dirs = [os.path.join('intel64', x) for x in ['lib', os.path.join('lib', 'release')]]
include_dirs = [os.path.join('intel64', 'include')]
path_dirs = [os.path.join('intel64', 'bin')]
if self.cfg['ofi_internal']:
lib_dirs.append(os.path.join('intel64', 'libfabric', 'lib'))
path_dirs.append(os.path.join('intel64', 'libfabric', 'bin'))
guesses['FI_PROVIDER_PATH'] = [os.path.join('intel64', 'libfabric', 'lib', 'prov')]
else:
lib_dirs = [os.path.join('lib', 'em64t'), 'lib64']
include_dirs = ['include64']
path_dirs = [os.path.join('bin', 'intel64'), 'bin64']
guesses['MIC_LD_LIBRARY_PATH'] = [os.path.join('mic', 'lib')]
guesses.update({
'PATH': path_dirs,
'LD_LIBRARY_PATH': lib_dirs,
'LIBRARY_PATH': lib_dirs,
'MANPATH': [manpath],
'CPATH': include_dirs,
})
return guesses
def make_module_extra(self, *args, **kwargs):
"""Overwritten from Application to add extra txt"""
if LooseVersion(self.version) >= LooseVersion('2021'):
mpiroot = os.path.join(self.installdir, 'mpi', self.version)
else:
mpiroot = self.installdir
txt = super(EB_impi, self).make_module_extra(*args, **kwargs)
txt += self.module_generator.set_environment('I_MPI_ROOT', mpiroot)
if self.cfg['set_mpi_wrappers_compiler'] or self.cfg['set_mpi_wrappers_all']:
for var in ['CC', 'CXX', 'F77', 'F90', 'FC']:
if var == 'FC':
# $FC isn't defined by EasyBuild framework, so use $F90 instead
src_var = 'F90'
else:
src_var = var
target_var = 'I_MPI_%s' % var
val = os.getenv(src_var)
if val:
txt += self.module_generator.set_environment(target_var, val)
else:
raise EasyBuildError("Environment variable $%s not set, can't define $%s", src_var, target_var)
if self.cfg['set_mpi_wrapper_aliases_gcc'] or self.cfg['set_mpi_wrappers_all']:
# force mpigcc/mpigxx to use GCC compilers, as would be expected based on their name
txt += self.module_generator.set_alias('mpigcc', 'mpigcc -cc=gcc')
txt += self.module_generator.set_alias('mpigxx', 'mpigxx -cxx=g++')
if self.cfg['set_mpi_wrapper_aliases_intel'] or self.cfg['set_mpi_wrappers_all']:
# do the same for mpiicc/mpiipc/mpiifort to be consistent, even if they may not exist
txt += self.module_generator.set_alias('mpiicc', 'mpiicc -cc=icc')
txt += self.module_generator.set_alias('mpiicpc', 'mpiicpc -cxx=icpc')
# -fc also works, but -f90 takes precedence
txt += self.module_generator.set_alias('mpiifort', 'mpiifort -f90=ifort')
# set environment variable UCX_TLS to 'all', this works in all hardware configurations
# needed with UCX regardless of the transports available (even without a Mellanox HCA)
# more information in easybuilders/easybuild-easyblocks#2253
if get_software_root('UCX'):
# do not overwrite settings in the easyconfig
if 'UCX_TLS' not in self.cfg['modextravars']:
txt += self.module_generator.set_environment('UCX_TLS', 'all')
return txt
##
# Copyright 2019-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 <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for OpenMPI, implemented as an easyblock
@author: Kenneth Hoste (Ghent University)
@author: Robert Mijakovic (LuxProvide)
"""
import os
import re
from easybuild.tools import LooseVersion
import easybuild.tools.toolchain as toolchain
from easybuild.easyblocks.generic.configuremake import ConfigureMake
from easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.config import build_option
from easybuild.tools.modules import get_software_root
from easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext
from easybuild.tools.toolchain.mpi import get_mpi_cmd_template
class EB_OpenMPI(ConfigureMake):
"""OpenMPI easyblock."""
def configure_step(self):
"""Custom configuration step for OpenMPI."""
def config_opt_used(key, enable_opt=False):
"""Helper function to check whether a configure option is already specified in 'configopts'."""
if enable_opt:
regex = '--(disable|enable)-%s' % key
else:
regex = '--(with|without)-%s' % key
return bool(re.search(regex, self.cfg['configopts']))
config_opt_names = [
# suppress failure modes in relation to mpirun path
'mpirun-prefix-by-default',
# build shared libraries
'shared',
]
for key in config_opt_names:
if not config_opt_used(key, enable_opt=True):
self.cfg.update('configopts', '--enable-%s' % key)
# List of EasyBuild dependencies for which OMPI has known options
known_dependencies = ('CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX', 'UCC')
# Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig
# No entry is interpreted as no option added at all
# This is to make builds reproducible even when the system libraries are changed and avoids failures
# due to e.g. finding only PMIx but not libevent on the system
unused_dep_value = dict()
# Known options since version 3.0 (no earlier ones checked)
if LooseVersion(self.version) >= LooseVersion('3.0'):
# Default to disable the option with "no"
unused_dep_value = {dep: 'no' for dep in known_dependencies}
# For these the default is to use an internal copy and not using any is not supported
for dep in ('hwloc', 'libevent', 'PMIx'):
unused_dep_value[dep] = 'internal'
# handle dependencies
for dep in known_dependencies:
opt_name = dep.lower()
# If the option is already used, don't add it
if config_opt_used(opt_name):
continue
# libfabric option renamed in OpenMPI 3.1.0 to ofi
if dep == 'libfabric' and LooseVersion(self.version) >= LooseVersion('3.1'):
opt_name = 'ofi'
# Check new option name. They are synonyms since 3.1.0 for backward compatibility
if config_opt_used(opt_name):
continue
dep_root = get_software_root(dep)
# If the dependency is loaded, specify its path, else use the "unused" value, if any
if dep_root:
opt_value = dep_root
else:
opt_value = unused_dep_value.get(dep)
if opt_value is not None:
self.cfg.update('configopts', '--with-%s=%s' % (opt_name, opt_value))
if bool(get_software_root('PMIx')) != bool(get_software_root('libevent')):
raise EasyBuildError('You must either use both PMIx and libevent as dependencies or none of them. '
'This is to enforce the same libevent is used for OpenMPI as for PMIx or '
'the behavior may be unpredictable.')
# check whether VERBS support should be enabled
if not config_opt_used('verbs'):
# for OpenMPI v4.x, the openib BTL should be disabled when UCX is used;
# this is required to avoid "error initializing an OpenFabrics device" warnings,
# see also https://www.open-mpi.org/faq/?category=all#ofa-device-error
is_ucx_enabled = ('--with-ucx' in self.cfg['configopts'] and
'--with-ucx=no' not in self.cfg['configopts'])
if LooseVersion(self.version) >= LooseVersion('4.0.0') and is_ucx_enabled:
verbs = False
else:
# auto-detect based on available OS packages
os_packages = EASYCONFIG_CONSTANTS['OS_PKG_IBVERBS_DEV'][0]
verbs = any(check_os_dependency(osdep) for osdep in os_packages)
# for OpenMPI v5.x, the verbs support is removed, only UCX is available
# see https://github.com/open-mpi/ompi/pull/6270
if LooseVersion(self.version) <= LooseVersion('5.0.0'):
if verbs:
self.cfg.update('configopts', '--with-verbs')
else:
self.cfg.update('configopts', '--without-verbs')
super(EB_OpenMPI, self).configure_step()
def test_step(self):
"""Test step for OpenMPI"""
# Default to `make check` if nothing is set. Disable with "runtest = False" in the EC
if self.cfg['runtest'] is None:
self.cfg['runtest'] = 'check'
super(EB_OpenMPI, self).test_step()
def load_module(self, *args, **kwargs):
"""
Load (temporary) module file, after resetting to initial environment.
Also put RPATH wrappers back in place if needed, to ensure that sanity check commands work as expected.
"""
super(EB_OpenMPI, self).load_module(*args, **kwargs)
# ensure RPATH wrappers are in place, otherwise compiling minimal test programs will fail
if build_option('rpath'):
if self.toolchain.options.get('rpath', True):
self.toolchain.prepare_rpath_wrappers(rpath_filter_dirs=self.rpath_filter_dirs,
rpath_include_dirs=self.rpath_include_dirs)
def sanity_check_step(self):
"""Custom sanity check for OpenMPI."""
bin_names = ['mpicc', 'mpicxx', 'mpif90', 'mpifort', 'mpirun', 'ompi_info', 'opal_wrapper']
if LooseVersion(self.version) >= LooseVersion('5.0.0'):
bin_names.append('prterun')
else:
bin_names.append('orterun')
bin_files = [os.path.join('bin', x) for x in bin_names]
shlib_ext = get_shared_lib_ext()
lib_names = ['mpi_mpifh', 'mpi', 'open-pal']
if LooseVersion(self.version) >= LooseVersion('5.0.0'):
lib_names.append('prrte')
else:
lib_names.extend(['ompitrace', 'open-rte'])
lib_files = [os.path.join('lib', 'lib%s.%s' % (x, shlib_ext)) for x in lib_names]
inc_names = ['mpi-ext', 'mpif-config', 'mpif', 'mpi', 'mpi_portable_platform']
if LooseVersion(self.version) >= LooseVersion('5.0.0'):
inc_names.append('prte')
inc_files = [os.path.join('include', x + '.h') for x in inc_names]
custom_paths = {
'files': bin_files + inc_files + lib_files,
'dirs': [],
}
# make sure MPI compiler wrappers pick up correct compilers
expected = {
'mpicc': os.getenv('CC', 'gcc'),
'mpicxx': os.getenv('CXX', 'g++'),
'mpifort': os.getenv('FC', 'gfortran'),
'mpif90': os.getenv('F90', 'gfortran'),
}
# actual pattern for gfortran is "GNU Fortran"
for key in ['mpifort', 'mpif90']:
if expected[key] == 'gfortran':
expected[key] = "GNU Fortran"
# for PGI, correct pattern is "pgfortran" with mpif90
if expected['mpif90'] == 'pgf90':
expected['mpif90'] = 'pgfortran'
# for Clang the pattern is always clang
for key in ['mpicxx', 'mpifort', 'mpif90']:
if expected[key] in ['clang++', 'flang']:
expected[key] = 'clang'
custom_commands = ["%s --version | grep '%s'" % (key, expected[key]) for key in sorted(expected.keys())]
# Add minimal test program to sanity checks
# Run with correct MPI launcher
mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, dict(), mpi_version=self.version)
# Limit number of ranks to 8 to avoid it failing due to hyperthreading
ranks = min(8, self.cfg['parallel'])
for srcdir, src, compiler in (
('examples', 'hello_c.c', 'mpicc'),
('examples', 'hello_mpifh.f', 'mpifort'),
('examples', 'hello_usempi.f90', 'mpif90'),
('examples', 'ring_c.c', 'mpicc'),
('examples', 'ring_mpifh.f', 'mpifort'),
#('examples', 'ring_usempi.f90', 'mpif90'),
('test/simple', 'thread_init.c', 'mpicc'),
('test/simple', 'intercomm1.c', 'mpicc'),
('test/simple', 'mpi_barrier.c', 'mpicc'),
):
src_path = os.path.join(self.cfg['start_dir'], srcdir, src)
if os.path.exists(src_path):
test_exe = os.path.join(self.builddir, 'mpi_test_' + os.path.splitext(src)[0])
self.log.info("Adding minimal MPI test program to sanity checks: %s", test_exe)
# Build test binary
custom_commands.append("%s %s -o %s" % (compiler, src_path, test_exe))
# Run the test if chosen
if build_option('mpi_tests'):
params.update({'nr_ranks': ranks, 'cmd': test_exe})
# Allow oversubscription for this test (in case of hyperthreading)
custom_commands.append("OMPI_MCA_rmaps_base_oversubscribe=1 " + mpi_cmd_tmpl % params)
# Run with 1 process which may trigger other bugs
# See https://github.com/easybuilders/easybuild-easyconfigs/issues/12978
params['nr_ranks'] = 1
custom_commands.append(mpi_cmd_tmpl % params)
super(EB_OpenMPI, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
##
# Copyright 2021-2024 Vrije Universiteit Brussel
#
# 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 <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for ORCA, implemented as an easyblock
@author: Alex Domingo (Vrije Universiteit Brussel)
"""
import glob
import os
from easybuild.tools import LooseVersion
from easybuild.easyblocks.generic.makecp import MakeCp
from easybuild.easyblocks.generic.packedbinary import PackedBinary
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.filetools import write_file
from easybuild.tools.py2vs3 import string_type
from easybuild.tools.systemtools import X86_64, get_cpu_architecture
class EB_ORCA(PackedBinary, MakeCp):
"""
ORCA installation files are extracted and placed in standard locations using 'files_to_copy' from MakeCp.
Sanity checks on files are automatically generated based on the contents of 'files_to_copy' by gathering
the target files in the build directory and checking their presence in the installation directory.
Sanity checks also include a quick test calculating the HF energy of a water molecule.
"""
@staticmethod
def extra_options(extra_vars=None):
"""Extra easyconfig parameters for ORCA."""
extra_vars = MakeCp.extra_options()
extra_vars.update(PackedBinary.extra_options())
# files_to_copy is not mandatory here, since we set it by default in install_step
extra_vars['files_to_copy'][2] = CUSTOM
return extra_vars
def __init__(self, *args, **kwargs):
"""Init and validate easyconfig parameters and system architecture"""
super(EB_ORCA, self).__init__(*args, **kwargs)
# If user overwrites 'files_to_copy', custom 'sanity_check_paths' must be present
if self.cfg['files_to_copy'] and not self.cfg['sanity_check_paths']:
raise EasyBuildError("Found 'files_to_copy' option in easyconfig without 'sanity_check_paths'")
# Add orcaarch template for supported architectures
myarch = get_cpu_architecture()
if myarch == X86_64:
orcaarch = 'x86-64'
else:
raise EasyBuildError("Architecture %s is not supported by ORCA on EasyBuild", myarch)
self.cfg.template_values['orcaarch'] = orcaarch
self.cfg.generate_template_values()
def install_step(self):
"""Install ORCA with MakeCp easyblock"""
if not self.cfg['files_to_copy']:
# Put installation files in standard locations
files_to_copy = [
(['auto*', 'orca*', 'otool*'], 'bin'),
(['*.pdf'], 'share'),
]
# Version 5 extra files
if LooseVersion('5.0.0') <= LooseVersion(self.version) < LooseVersion('6.0.0'):
compoundmethods = (['ORCACompoundMethods'], 'bin')
files_to_copy.append(compoundmethods)
# Shared builds have additional libraries
libs_to_copy = (['liborca*'], 'lib')
if all([glob.glob(p) for p in libs_to_copy[0]]):
files_to_copy.append(libs_to_copy)
self.cfg['files_to_copy'] = files_to_copy
MakeCp.install_step(self)
def sanity_check_step(self):
"""Custom sanity check for ORCA"""
custom_paths = None
if not self.cfg['sanity_check_paths']:
custom_paths = {'files': [], 'dirs': []}
if self.cfg['files_to_copy']:
# Convert 'files_to_copy' to list of files in build directory
for spec in self.cfg['files_to_copy']:
if isinstance(spec, tuple):
file_pattern = spec[0]
dest_dir = spec[1]
elif isinstance(spec, string_type):
file_pattern = spec
dest_dir = ''
else:
raise EasyBuildError(
"Found neither string nor tuple as file to copy: '%s' (type %s)", spec, type(spec)
)
if isinstance(file_pattern, string_type):
file_pattern = [file_pattern]
source_files = []
for pattern in file_pattern:
source_files.extend(glob.glob(pattern))
# Add files to custom sanity checks
for source in source_files:
if os.path.isfile(source):
custom_paths['files'].append(os.path.join(dest_dir, source))
else:
custom_paths['dirs'].append(os.path.join(dest_dir, source))
else:
# Minimal check of files (needed by --module-only)
custom_paths['files'] = ['bin/orca']
# # Simple test: HF energy of water molecule
# test_input_content = """
#!HF DEF2-SVP
#%%PAL NPROCS %(nprocs)s END
#* xyz 0 1
#O 0.0000 0.0000 0.0626
#H -0.7920 0.0000 -0.4973
#H 0.7920 0.0000 -0.4973
#*
#"""
# nprocs = self.cfg.get('parallel', 1)
# test_input_content = test_input_content % {'nprocs': nprocs}
# test_input_path = os.path.join(self.builddir, 'eb_test_hf_water.inp')
# write_file(test_input_path, test_input_content)
#
# # Reference total energy
# test_output_energy = '-75.95934031'
# test_output_regex = 'FINAL SINGLE POINT ENERGY[ \t]*%s' % test_output_energy
#
# # Instruct openmpi to treat hardware threads as slot
# test_ompi_env = 'env OMPI_MCA_hwloc_base_use_hwthreads_as_cpus=1'
#
# # ORCA has to be executed using its full path to run in parallel
# if os.path.isdir(os.path.join(self.installdir, 'bin')):
# orca_bin = '$EBROOTORCA/bin/orca'
# else:
# orca_bin = '$(which orca)'
#
# test_orca_cmd = "%s %s %s" % (test_ompi_env, orca_bin, test_input_path)
#
# custom_commands = [
# # Execute test in ORCA
# test_orca_cmd,
# # Repeat test and check total energy
# "%s | grep -c '%s'" % (test_orca_cmd, test_output_regex),
# ]
#
# super(EB_ORCA, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
#!/usr/bin/env python #!/usr/bin/env python
""" """
EasyBuild support for building and installing VisIt 3.1.0, EasyBuild support for building and installing VisIt 3.3.3,
implemented as an easyblock. implemented as an easyblock.
@author: Lukas Krupcik (IT4Innovations) @author: Lukas Krupcik (IT4Innovations)
...@@ -31,9 +31,11 @@ class EB_VisIt(EasyBlock): ...@@ -31,9 +31,11 @@ class EB_VisIt(EasyBlock):
"""Simply run installation script with configuration options""" """Simply run installation script with configuration options"""
self.log.info("Changing VisIt installer permission") self.log.info("Changing VisIt installer permission")
os.chdir(self.cfg['start_dir']) os.chdir(self.cfg['start_dir'])
chmod_cmd = "chmod 755 visit-install3_1_0" #chmod_cmd = "chmod 755 visit-install3_3_3"
chmod_cmd = "chmod 755 visit-install2_13_3"
run_cmd(chmod_cmd, log_all=True) run_cmd(chmod_cmd, log_all=True)
install_cmd = "./visit-install3_1_0 -c none 3.1.0 \ #install_cmd = "./visit-install3_3_3 -c none 3.3.3 \
install_cmd = "./visit-install2_13_3 -c none 2.13.3 \
linux-x86_64-rhel7 %s" % self.installdir linux-x86_64-rhel7 %s" % self.installdir
self.log.info("Running VisIt installer") self.log.info("Running VisIt installer")
run_cmd(install_cmd, log_all=True) run_cmd(install_cmd, log_all=True)
......
##
# 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 <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for building and installing WRF-Fire, implemented as an easyblock
author: Kenneth Hoste (HPC-UGent)
"""
import os
import easybuild.tools.environment as env
import easybuild.tools.toolchain as toolchain
from easybuild.framework.easyblock import EasyBlock
from easybuild.framework.easyconfig import CUSTOM, MANDATORY
from easybuild.tools.filetools import apply_regex_substitutions, change_dir, patch_perl_script_autoflush
from easybuild.tools.modules import get_software_root
from easybuild.tools.run import run_cmd, run_cmd_qa
from easybuild.tools.build_log import EasyBuildError
class EB_WRF_minus_Sfire(EasyBlock):
"""Support for building/installing WRF-Sfire."""
@staticmethod
def extra_options():
"""Custom easyconfig parameters for WRF-Sfire."""
extra_vars = {
'buildtype': [None, "Specify the type of build (serial, smpar (OpenMP), "
"dmpar (MPI), dm+sm (hybrid OpenMP/MPI)).", MANDATORY],
'runtest': [True, "Build and run WRF tests", CUSTOM],
}
return EasyBlock.extra_options(extra_vars)
def __init__(self, *args, **kwargs):
"""Add extra config options specific to WRF."""
super(EB_WRF_minus_Sfire, self).__init__(*args, **kwargs)
self.build_in_installdir = True
def extract_step(self):
"""Extract WRF-Sfire sources."""
self.cfg.update('unpack_options', '--strip-components=1')
super(EB_WRF_minus_Sfire, self).extract_step()
def configure_step(self):
"""Custom configuration procedure for WRF-Sfire."""
comp_fam = self.toolchain.comp_family()
# define $NETCDF* for netCDF dependency
netcdf_fortran = get_software_root('netCDF-Fortran')
if netcdf_fortran:
env.setvar('NETCDF', netcdf_fortran)
else:
raise EasyBuildError("Required dependendy netCDF-Fortran is missing")
# define $PHDF5 for parallel HDF5 dependency
hdf5 = get_software_root('HDF5')
if hdf5 and os.path.exists(os.path.join(hdf5, 'bin', 'h5pcc')):
env.setvar('PHDF5', hdf5)
# first, configure WRF part
change_dir(os.path.join(self.cfg['start_dir'], 'WRFV3'))
# instruct WRF-Sfire to create netCDF v4 output files
env.setvar('WRFIO_NETCDF4_FILE_SUPPORT', '1')
# patch arch/Config_new.pl script, so that run_cmd_qa receives all output to answer questions
patch_perl_script_autoflush(os.path.join('arch', 'Config_new.pl'))
# determine build type option to look for
known_build_type_options = {
toolchain.INTELCOMP: "Linux x86_64 i486 i586 i686, ifort compiler with icc",
toolchain.GCC: "x86_64 Linux, gfortran compiler with gcc",
toolchain.PGI: "Linux x86_64, PGI compiler with pgcc",
}
build_type_option = known_build_type_options.get(comp_fam)
if build_type_option is None:
raise EasyBuildError("Don't know which WPS configure option to select for compiler family %s", comp_fam)
build_type_question = r"\s*(?P<nr>[0-9]+).\s*%s\s*\(%s\)" % (build_type_option, self.cfg['buildtype'])
qa = {
"Compile for nesting? (1=basic, 2=preset moves, 3=vortex following) [default 1]:": '1',
}
std_qa = {
# named group in match will be used to construct answer
r"%s.*\n(.*\n)*Enter selection\s*\[[0-9]+-[0-9]+\]\s*:" % build_type_question: '%(nr)s',
}
run_cmd_qa('./configure', qa, std_qa=std_qa, log_all=True, simple=True)
cpp_flag = None
if comp_fam == toolchain.INTELCOMP:
cpp_flag = '-fpp'
elif comp_fam == toolchain.GCC:
cpp_flag = '-cpp'
else:
raise EasyBuildError("Don't know which flag to use to specify that Fortran files were preprocessed")
# patch configure.wrf to get things right
comps = {
'CFLAGS_LOCAL': os.getenv('CFLAGS'),
'DM_FC': os.getenv('MPIF90'),
'DM_CC': "%s -DMPI2_SUPPORT" % os.getenv('MPICC'),
'FCOPTIM': os.getenv('FFLAGS'),
# specify that Fortran files have been preprocessed with cpp,
# see http://forum.wrfforum.com/viewtopic.php?f=5&t=6086
'FORMAT_FIXED': "-FI %s" % cpp_flag,
'FORMAT_FREE': "-FR %s" % cpp_flag,
}
regex_subs = [(r"^(%s\s*=\s*).*$" % k, r"\1 %s" % v) for (k, v) in comps.items()]
apply_regex_substitutions('configure.wrf', regex_subs)
# also configure WPS part
change_dir(os.path.join(self.cfg['start_dir'], 'WPS'))
# patch arch/Config_new.pl script, so that run_cmd_qa receives all output to answer questions
patch_perl_script_autoflush(os.path.join('arch', 'Config.pl'))
# determine build type option to look for
known_build_type_options = {
toolchain.INTELCOMP: "PC Linux x86_64, Intel compiler",
toolchain.GCC: "PC Linux x86_64, g95 compiler",
toolchain.PGI: "PC Linux x86_64 (IA64 and Opteron), PGI compiler 5.2 or higher",
}
build_type_option = known_build_type_options.get(comp_fam)
if build_type_option is None:
raise EasyBuildError("Don't know which WPS configure option to select for compiler family %s", comp_fam)
known_wps_build_types = {
'dmpar': 'DM parallel',
'smpar': 'serial',
}
wps_build_type = known_wps_build_types.get(self.cfg['buildtype'])
if wps_build_type is None:
raise EasyBuildError("Don't know which WPS build type to pick for '%s'", self.cfg['builddtype'])
build_type_question = r"\s*(?P<nr>[0-9]+).\s*%s.*%s(?!NO GRIB2)" % (build_type_option, wps_build_type)
std_qa = {
# named group in match will be used to construct answer
r"%s.*\n(.*\n)*Enter selection\s*\[[0-9]+-[0-9]+\]\s*:" % build_type_question: '%(nr)s',
}
run_cmd_qa('./configure', {}, std_qa=std_qa, log_all=True, simple=True)
# patch configure.wps to get things right
comps = {
'CC': '%s %s' % (os.getenv('MPICC'), os.getenv('CFLAGS')),
'FC': '%s %s' % (os.getenv('MPIF90'), os.getenv('F90FLAGS'))
}
regex_subs = [(r"^(%s\s*=\s*).*$" % k, r"\1 %s" % v) for (k, v) in comps.items()]
# specify that Fortran90 files have been preprocessed with cpp
regex_subs.extend([
(r"^(F77FLAGS\s*=\s*)", r"\1 %s " % cpp_flag),
(r"^(FFLAGS\s*=\s*)", r"\1 %s " % cpp_flag),
])
apply_regex_substitutions('configure.wps', regex_subs)
def build_step(self):
"""Custom build procedure for WRF-Sfire."""
cmd = './compile'
if self.cfg['parallel']:
cmd += " -j %d" % self.cfg['parallel']
# first, build WRF part
change_dir(os.path.join(self.cfg['start_dir'], 'WRFV3'))
(out, ec) = run_cmd(cmd + ' em_fire', log_all=True, simple=False, log_ok=True)
# next, build WPS part
change_dir(os.path.join(self.cfg['start_dir'], 'WPS'))
(out, ec) = run_cmd('./compile', log_all=True, simple=False, log_ok=True)
def test_step(self):
"""Custom built-in test procedure for WRF-Sfire."""
if self.cfg['runtest']:
change_dir(os.path.join(self.cfg['start_dir'], 'WRFV3', 'test', 'em_fire', 'hill'))
if self.cfg['buildtype'] in ['dmpar', 'smpar', 'dm+sm']:
test_cmd = "ulimit -s unlimited && %s && %s" % (self.toolchain.mpi_cmd_for("./ideal.exe", 1),
self.toolchain.mpi_cmd_for("./wrf.exe", 2))
else:
test_cmd = "ulimit -s unlimited && ./ideal.exe && ./wrf.exe"
run_cmd(test_cmd, simple=True, log_all=True, log_ok=True)
# building/installing is done in build_step, so we can run tests
def install_step(self):
"""Building was done in install dir, so nothing to do in install_step."""
pass
def sanity_check_step(self):
"""Custom sanity check for WRF-Sfire."""
custom_paths = {
'files': [os.path.join('WRFV3', 'main', f) for f in ['ideal.exe', 'libwrflib.a', 'wrf.exe']] +
[os.path.join('WPS', f) for f in ['geogrid.exe', 'metgrid.exe', 'ungrib.exe']],
'dirs': [os.path.join('WRFV3', d) for d in ['main', 'run']],
}
super(EB_WRF_minus_Sfire, self).sanity_check_step(custom_paths=custom_paths)
def make_module_req_guess(self):
"""Custom guesses for generated WRF-Sfire module file."""
wrf_maindir = os.path.join('WRFV3', 'main')
return {
'LD_LIBRARY_PATH': [wrf_maindir],
'PATH': [wrf_maindir, 'WPS'],
}
def make_module_extra(self):
"""Add netCDF environment variables to module file."""
txt = super(EB_WRF_minus_Sfire, self).make_module_extra()
netcdf_fortran = get_software_root('netCDF-Fortran')
if netcdf_fortran:
txt += self.module_generator.set_environment('NETCDF', netcdf_fortran)
return txt
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment