diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py new file mode 100644 index 0000000000..e80b8d24cc --- /dev/null +++ b/easybuild/easyblocks/x/xalt.py @@ -0,0 +1,172 @@ +## +# Copyright 2020 NVIDIA +# +# This file is triple-licensed under GPLv2 (see below), MIT, and +# BSD three-clause licenses. +# +# 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 XALT, implemented as an easyblock +@author: Scott McMillan (NVIDIA) +""" +import os + +from easybuild.easyblocks.generic.configuremake import ConfigureMake +from easybuild.framework.easyconfig import CUSTOM, MANDATORY +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.modules import get_software_root +from easybuild.tools.systemtools import get_shared_lib_ext + + +class EB_XALT(ConfigureMake): + """Support for building and installing XALT.""" + + @staticmethod + def extra_options(): + extra_vars = { + 'config_py': [None, "XALT site filter file", MANDATORY], + 'executable_tracking': [True, "Enable executable tracking", CUSTOM], + 'gpu_tracking': [None, "Enable GPU tracking", CUSTOM], + 'logging_url': [None, "Logging URL for transmission", CUSTOM], + 'mysql': [False, "Build with MySQL support", CUSTOM], + 'scalar_sampling': [True, "Enable scalar sampling", CUSTOM], + 'static_cxx': [False, "Statically link libstdc++ and libgcc_s", CUSTOM], + 'syshost': [None, "System name", MANDATORY], + 'transmission': [None, "Data tranmission method", MANDATORY], + } + return ConfigureMake.extra_options(extra_vars) + + def configure_step(self): + """Custom configuration step for XALT.""" + + # By default, XALT automatically appends 'xalt/' to the + # prefix, i.e., --prefix=/opt will actually install in + # /opt/xalt/. To precisely control the install prefix and + # not append anything to the prefix, use the configure option + # '--with-siteControlledPrefix=yes'. + # See https://xalt.readthedocs.io/en/latest/050_install_and_test.html + self.cfg.update('configopts', '--with-siteControlledPrefix=yes') + + # XALT site filter config file is mandatory + config_py = self.cfg['config_py'] + if config_py: + if os.path.exists(config_py): + self.cfg.update('configopts', '--with-config=%s' % config_py) + else: + raise EasyBuildError("Specified XALT configuration file %s does not exist!", config_py) + else: + error_msg = "Location of XALT configuration file must be specified via 'config_py' easyconfig parameter. " + error_msg += "You can edit the easyconfig file, or use 'eb --try-amend=config_py='. " + error_msg += "See https://xalt.readthedocs.io/en/latest/030_site_filtering.html for more information." + raise EasyBuildError(error_msg) + + # XALT system name is mandatory + if self.cfg['syshost']: + self.cfg.update('configopts', '--with-syshostConfig=%s' % self.cfg['syshost']) + else: + error_msg = "The name of the system must be specified via the 'syshost' easyconfig parameter. " + error_msg += "You can edit the easyconfig file, or use 'eb --try-amend=syshost='. " + error_msg += "See https://xalt.readthedocs.io/en/latest/020_site_configuration.html for more information." + raise EasyBuildError(error_msg) + + # Transmission method is mandatory + if self.cfg['transmission']: + self.cfg.update('configopts', '--with-transmission=%s' % self.cfg['transmission']) + else: + error_msg = "The XALT transmission method must be specified via the 'transmission' easyconfig parameter. " + error_msg = "You can edit the easyconfig file, or use 'eb --try-amend=transmission='. " + error_msg += "See https://xalt.readthedocs.io/en/latest/020_site_configuration.html for more information." + raise EasyBuildError(error_msg) + + # GPU tracking + if self.cfg['gpu_tracking'] is True: + # User enabled + self.cfg.update('configopts', '--with-trackGPU=yes') + elif self.cfg['gpu_tracking'] is None: + # Default value, enable GPU tracking if nvml.h is present + # and the CUDA module is loaded + cuda_root = get_software_root('CUDA') + if cuda_root: + nvml_h = os.path.join(cuda_root, "include", "nvml.h") + if os.path.isfile(nvml_h): + self.cfg.update('configopts', '--with-trackGPU=yes') + self.cfg['gpu_tracking'] = True + else: + # User disabled + self.cfg.update('configopts', '--with-trackGPU=no') + + # MySQL + if self.cfg['mysql'] is True: + self.cfg.update('configopts', '--with-MySQL=yes') + else: + self.cfg.update('configopts', '--with-MySQL=no') + + # If XALT is built with a more recent compiler than the system + # compiler, then XALT likely will depend on symbol versions not + # available in the system libraries. Link statically as a workaround. + if self.cfg['static_cxx'] is True: + self.cfg.update('configopts', 'LDFLAGS="${LDFLAGS} -static-libstdc++ -static-libgcc"') + + # Configure + super(EB_XALT, self).configure_step() + + def make_module_extra(self, *args, **kwargs): + txt = super(EB_XALT, self).make_module_extra(*args, **kwargs) + + txt += self.module_generator.prepend_paths('LD_PRELOAD', 'lib64/libxalt_init.%s' % get_shared_lib_ext()) + txt += self.module_generator.set_environment('XALT_DIR', self.installdir) + txt += self.module_generator.set_environment('XALT_ETC_DIR', '%s' % os.path.join(self.installdir, 'etc')) + txt += self.module_generator.set_environment('XALT_EXECUTABLE_TRACKING', + ('no', 'yes')[bool(self.cfg['executable_tracking'])]) + txt += self.module_generator.set_environment('XALT_GPU_TRACKING', + ('no', 'yes')[bool(self.cfg['gpu_tracking'])]) + if self.cfg['transmission'].lower() == 'curl' and self.cfg['logging_url']: + txt += self.module_generator.set_environment('XALT_LOGGING_URL', self.cfg['logging_url']) + txt += self.module_generator.set_environment('XALT_SCALAR_SAMPLING', + ('no', 'yes')[bool(self.cfg['scalar_sampling'])]) + + # In order to track containerized executables, bind mount the XALT + # directory in the Singularity container and preload the XALT library + # https://xalt.readthedocs.io/en/latest/050_install_and_test.html#xalt-modulefile + txt += self.module_generator.prepend_paths('SINGULARITY_BINDPATH', '') + txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', + 'lib64/libxalt_init.%s' % get_shared_lib_ext()) + + return txt + + def make_module_req_guess(self): + """Custom guesses for environment variables""" + return {'COMPILER_PATH': 'bin', + 'PATH': 'bin'} + + def sanity_check_step(self): + """Custom sanity check""" + custom_paths = { + 'files': ['bin/ld', 'bin/ld.gold', 'bin/xalt_extract_record', + 'lib64/libxalt_init.%s' % get_shared_lib_ext()], + 'dirs': ['bin', 'libexec', 'sbin'], + } + custom_commands = ['xalt_configuration_report'] + + super(EB_XALT, self).sanity_check_step(custom_commands=custom_commands, + custom_paths=custom_paths)