diff --git "a/easyblocks/c/\\" "b/easyblocks/c/\\" new file mode 100644 index 0000000000000000000000000000000000000000..e372a40480272df5fc9280f10b4c4b2696f50a54 --- /dev/null +++ "b/easyblocks/c/\\" @@ -0,0 +1,432 @@ +## +# Copyright 2013 Dmitri Gribenko +# Copyright 2013-2017 Ghent University +# Copyright 2017 IT4Innovations +# +# 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 <http://www.gnu.org/licenses/>. +## +""" +Support for building and installing Clang, implemented as an easyblock. + +@author: Dmitri Gribenko (National Technical University of Ukraine "KPI") +@author: Ward Poelmans (Ghent University) +@author: Josef Hrabal, Lukas Krupcik (IT4innovations, Czechia) +""" + +import fileinput +import glob +import os +import re +import shutil +import sys +from distutils.version import LooseVersion + +from easybuild.easyblocks.generic.cmakemake import CMakeMake +from easybuild.framework.easyconfig import CUSTOM +from easybuild.tools import run +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.config import build_option +from easybuild.tools.filetools import mkdir +from easybuild.tools.modules import get_software_root +from easybuild.tools.run import run_cmd +from easybuild.tools.systemtools import get_os_name, get_os_version, get_shared_lib_ext + +# List of all possible build targets for Clang +CLANG_TARGETS = ["all", "AArch64", "ARM", "CppBackend", "Hexagon", "Mips", + "MBlaze", "MSP430", "NVPTX", "PowerPC", "R600", "Sparc", + "SystemZ", "X86", "XCore"] + + +class EB_Clang(CMakeMake): + """Support for bootstrapping Clang.""" + + @staticmethod + def extra_options(): + extra_vars = { + 'assertions': [True, "Enable assertions. Helps to catch bugs in Clang.", CUSTOM], + 'build_targets': [["X86"], "Build targets for LLVM. Possible values: " + ', '.join(CLANG_TARGETS), CUSTOM], + 'bootstrap': [True, "Bootstrap Clang using GCC", CUSTOM], + 'usepolly': [False, "Build Clang with polly", CUSTOM], + 'static_analyzer': [True, "Install the static analyser of Clang", CUSTOM], + # The sanitizer tests often fail on HPC systems due to the 'weird' environment. + 'skip_sanitizer_tests': [False, "Do not run the sanitizer tests", CUSTOM], + } + + return CMakeMake.extra_options(extra_vars) + + def __init__(self, *args, **kwargs): + """Initialize custom class variables for Clang.""" + + super(EB_Clang, self).__init__(*args, **kwargs) + self.llvm_src_dir = None + self.llvm_obj_dir_stage1 = None + self.llvm_obj_dir_stage2 = None + self.llvm_obj_dir_stage3 = None + self.make_parallel_opts = "" + + unknown_targets = [target for target in self.cfg['build_targets'] if target not in CLANG_TARGETS] + + if unknown_targets: + raise EasyBuildError("Some of the chosen build targets (%s) are not in %s.", + ', '.join(unknown_targets), ', '.join(CLANG_TARGETS)) + + if LooseVersion(self.version) < LooseVersion('3.4') and "R600" in self.cfg['build_targets']: + raise EasyBuildError("Build target R600 not supported in < Clang-3.4") + + if LooseVersion(self.version) > LooseVersion('3.3') and "MBlaze" in self.cfg['build_targets']: + raise EasyBuildError("Build target MBlaze is not supported anymore in > Clang-3.3") + + def check_readiness_step(self): + """Fail early on RHEL 5.x and derivatives because of known bug in libc.""" + super(EB_Clang, self).check_readiness_step() + # RHEL 5.x have a buggy libc. Building stage 2 will fail. + if get_os_name() in ['redhat', 'RHEL', 'centos', 'SL'] and get_os_version().startswith('5.'): + raise EasyBuildError("Can not build Clang on %s v5.x: libc is buggy, building stage 2 will fail. " + "See http://stackoverflow.com/questions/7276828/", get_os_name()) + + def extract_step(self): + """ + Prepare a combined LLVM source tree. The layout is: + llvm/ Unpack llvm-*.tar.gz here + projects/ + compiler-rt/ Unpack compiler-rt-*.tar.gz here + openmp/ Unpack openmp-*.tar.xz here + libcxx/ Unpack libcxx-*.tar.xz here + libcxxabi/ Unpack libcxxapbi-*.tar.xz here + tools/ + clang/ Unpack cfe-*.tar.gz here + tools/extra Unpack clang-*.tar.gz here + polly/ Unpack polly-*.tar.gz here + """ + + # Extract everything into separate directories. + super(EB_Clang, self).extract_step() + + # Find the full path to the directory that was unpacked from llvm-*.tar.gz. + for tmp in self.src: + if tmp['name'].startswith("llvm-"): + self.llvm_src_dir = tmp['finalpath'] + break + + if self.llvm_src_dir is None: + raise EasyBuildError("Could not determine LLVM source root (LLVM source was not unpacked?)") + + src_dirs = {} + + def find_source_dir(globpatterns, targetdir): + """Search for directory with globpattern and rename it to targetdir""" + if not isinstance(globpatterns, list): + globpatterns = [globpatterns] + + glob_src_dirs = [glob_dir for globpattern in globpatterns for glob_dir in glob.glob(globpattern)] + if len(glob_src_dirs) != 1: + raise EasyBuildError("Failed to find exactly one source directory for pattern %s: %s", globpatterns, + glob_src_dirs) + src_dirs[glob_src_dirs[0]] = targetdir + + find_source_dir('compiler-rt-*', os.path.join(self.llvm_src_dir, 'projects', 'compiler-rt')) + + if self.cfg["usepolly"]: + find_source_dir('polly-*', os.path.join(self.llvm_src_dir, 'tools', 'polly')) + + find_source_dir('cfe-*', os.path.join(self.llvm_src_dir, 'tools', 'clang')) + + find_source_dir('clang-*', os.path.join(self.llvm_src_dir, 'tools', 'clang', 'tools', 'extra')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libcxx-*', os.path.join(self.llvm_src_dir, 'projects', 'libcxx')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libcxxabi-*', os.path.join(self.llvm_src_dir, 'projects', 'libcxxabi')) + + if LooseVersion(self.version) >= LooseVersion('3.8'): + find_source_dir('openmp-*', os.path.join(self.llvm_src_dir, 'projects', 'openmp')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('ldd-*', os.path.join(self.llvm_src_dir, 'tools', 'ldd')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('lddb-*', os.path.join(self.llvm_src_dir, 'tools', 'lddb')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libunwind-*', os.path.join(self.llvm_src_dir, 'tools', 'libunwind')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('test-*', os.path.join(self.llvm_src_dir, 'tools', 'testsuite')) + + for src in self.src: + for (dirname, new_path) in src_dirs.items(): + if src['name'].startswith(dirname): + old_path = os.path.join(src['finalpath'], dirname) + try: + shutil.move(old_path, new_path) + except IOError, err: + raise EasyBuildError("Failed to move %s to %s: %s", old_path, new_path, err) + src['finalpath'] = new_path + break + + def configure_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).configure_step() + return + + """Run CMake for stage 1 Clang.""" + self.llvm_obj_dir_stage1 = os.path.join(self.builddir, 'llvm.obj.1') + if self.cfg['bootstrap']: + self.llvm_obj_dir_stage2 = os.path.join(self.builddir, 'llvm.obj.2') + self.llvm_obj_dir_stage3 = os.path.join(self.builddir, 'llvm.obj.3') + + if LooseVersion(self.version) >= LooseVersion('3.3'): + disable_san_tests = False + # all sanitizer tests will fail when there's a limit on the vmem + # this is ugly but I haven't found a cleaner way so far + (vmemlim, ec) = run_cmd("ulimit -v", regexp=False) + if not vmemlim.startswith("unlimited"): + disable_san_tests = True + self.log.warn("There is a virtual memory limit set of %s KB. The tests of the " + "sanitizers will be disabled as they need unlimited virtual " + "memory unless --strict=error is used." % vmemlim.strip()) + + # the same goes for unlimited stacksize + (stacklim, ec) = run_cmd("ulimit -s", regexp=False) + if stacklim.startswith("unlimited"): + disable_san_tests = True + self.log.warn("The stacksize limit is set to unlimited. This causes the ThreadSanitizer " + "to fail. The sanitizers tests will be disabled unless --strict=error is used.") + + if (disable_san_tests or self.cfg['skip_sanitizer_tests']) and build_option('strict') != run.ERROR: + self.log.debug("Disabling the sanitizer tests") + self.disable_sanitizer_tests() + + # Create and enter build directory. + mkdir(self.llvm_obj_dir_stage1) + os.chdir(self.llvm_obj_dir_stage1) + + # GCC and Clang are installed in different prefixes and Clang will not + # find the GCC installation on its own. + # First try with GCCcore, as GCC built on top of GCCcore is just a wrapper for GCCcore and binutils, + # instead of a full-fledge compiler + gcc_prefix = get_software_root('GCCcore') + + # If that doesn't work, try with GCC + if gcc_prefix is None: + gcc_prefix = get_software_root('GCC') + + # If that doesn't work either, print error and exit + if gcc_prefix is None: + raise EasyBuildError("Can't find GCC or GCCcore to use") + + self.cfg.update('configopts', "-DGCC_INSTALL_PREFIX='%s' " % gcc_prefix) + self.log.debug("Using %s as GCC_INSTALL_PREFIX", gcc_prefix) + + self.cfg['configopts'] += "-DCMAKE_BUILD_TYPE=Release " + if self.cfg['assertions']: + self.cfg['configopts'] += "-DLLVM_ENABLE_ASSERTIONS=ON " + else: + self.cfg['configopts'] += "-DLLVM_ENABLE_ASSERTIONS=OFF " + + self.cfg['configopts'] += '-DLLVM_TARGETS_TO_BUILD="%s" ' % ';'.join(self.cfg['build_targets']) + + if self.cfg['parallel']: + self.make_parallel_opts = "-j %s" % self.cfg['parallel'] + + self.log.info("Configuring") + super(EB_Clang, self).configure_step(srcdir=self.llvm_src_dir) + + def disable_sanitizer_tests(self): + """Disable the tests of all the sanitizers by removing the test directories from the build system""" + if LooseVersion(self.version) < LooseVersion('3.6'): + # for Clang 3.5 and lower, the tests are scattered over several CMakeLists. + # We loop over them, and patch out the rule that adds the sanitizers tests to the testsuite + patchfiles = [ + "lib/asan", + "lib/dfsan", + "lib/lsan", + "lib/msan", + "lib/tsan", + "lib/ubsan", + ] + + for patchfile in patchfiles: + patchfile_fp = os.path.join(self.llvm_src_dir, "projects/compiler-rt", patchfile, "CMakeLists.txt") + if os.path.exists(patchfile_fp): + self.log.debug("Patching %s in %s" % (patchfile, self.llvm_src_dir)) + try: + for line in fileinput.input(patchfile_fp, inplace=1, backup='.orig'): + if "add_subdirectory(lit_tests)" not in line: + sys.stdout.write(line) + except (IOError, OSError), err: + raise EasyBuildError("Failed to patch %s: %s", patchfile_fp, err) + else: + self.log.debug("Not patching non-existent %s in %s" % (patchfile, self.llvm_src_dir)) + + # There is a common part seperate for the specific saniters, we disable all + # the common tests + patchfile = "projects/compiler-rt/lib/sanitizer_common/CMakeLists.txt" + try: + for line in fileinput.input("%s/%s" % (self.llvm_src_dir, patchfile), inplace=1, backup='.orig'): + if "add_subdirectory(tests)" not in line: + sys.stdout.write(line) + except IOError, err: + raise EasyBuildError("Failed to patch %s/%s: %s", self.llvm_src_dir, patchfile, err) + else: + # In Clang 3.6, the sanitizer tests are grouped together in one CMakeLists + # We patch out adding the subdirectories with the sanitizer tests + patchfile = "projects/compiler-rt/test/CMakeLists.txt" + patchfile_fp = os.path.join(self.llvm_src_dir, patchfile) + self.log.debug("Patching %s in %s" % (patchfile, self.llvm_src_dir)) + patch_regex = re.compile(r'add_subdirectory\((.*san|sanitizer_common)\)') + try: + for line in fileinput.input(patchfile_fp, inplace=1, backup='.orig'): + if not patch_regex.search(line): + sys.stdout.write(line) + except IOError, err: + raise EasyBuildError("Failed to patch %s: %s", patchfile_fp, err) + + def build_with_prev_stage(self, prev_obj, next_obj): + """Build Clang stage N using Clang stage N-1""" + + # Create and enter build directory. + mkdir(next_obj) + os.chdir(next_obj) + + # Configure. + CC = os.path.join(prev_obj, 'bin', 'clang') + CXX = os.path.join(prev_obj, 'bin', 'clang++') + + options = "-DCMAKE_INSTALL_PREFIX=%s " % self.installdir + options += "-DCMAKE_C_COMPILER='%s' " % CC + options += "-DCMAKE_CXX_COMPILER='%s' " % CXX + options += self.cfg['configopts'] + + self.log.info("Configuring") + run_cmd("cmake %s %s" % (options, self.llvm_src_dir), log_all=True) + + self.log.info("Building") + run_cmd("make %s" % self.make_parallel_opts, log_all=True) + + def run_clang_tests(self, obj_dir): + os.chdir(obj_dir) + + self.log.info("Running tests") + run_cmd("make %s check-all" % self.make_parallel_opts, log_all=True) + + def build_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).build_step() + return + + """Build Clang stage 1, 2, 3""" + + # Stage 1: build using system compiler. + self.log.info("Building stage 1") + os.chdir(self.llvm_obj_dir_stage1) + super(EB_Clang, self).build_step() + + if self.cfg['bootstrap']: + # Stage 1: run tests. + self.run_clang_tests(self.llvm_obj_dir_stage1) + + self.log.info("Building stage 2") + self.build_with_prev_stage(self.llvm_obj_dir_stage1, self.llvm_obj_dir_stage2) + self.run_clang_tests(self.llvm_obj_dir_stage2) + + self.log.info("Building stage 3") + self.build_with_prev_stage(self.llvm_obj_dir_stage2, self.llvm_obj_dir_stage3) + # Don't run stage 3 tests here, do it in the test step. + + def test_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).test_step() + return + + if self.cfg['bootstrap']: + self.run_clang_tests(self.llvm_obj_dir_stage3) + else: + self.run_clang_tests(self.llvm_obj_dir_stage1) + + def install_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).install_step() + return + + """Install stage 3 binaries.""" + + if self.cfg['bootstrap']: + os.chdir(self.llvm_obj_dir_stage3) + else: + os.chdir(self.llvm_obj_dir_stage1) + super(EB_Clang, self).install_step() + + # the static analyzer is not installed by default + # we do it by hand + if self.cfg['static_analyzer'] and LooseVersion(self.version) < LooseVersion('3.8'): + try: + tools_src_dir = os.path.join(self.llvm_src_dir, 'tools', 'clang', 'tools') + analyzer_target_dir = os.path.join(self.installdir, 'libexec', 'clang-analyzer') + bindir = os.path.join(self.installdir, 'bin') + for scan_dir in ['scan-build', 'scan-view']: + shutil.copytree(os.path.join(tools_src_dir, scan_dir), os.path.join(analyzer_target_dir, scan_dir)) + os.symlink(os.path.relpath(bindir, os.path.join(analyzer_target_dir, scan_dir)), + os.path.join(analyzer_target_dir, scan_dir, 'bin')) + os.symlink(os.path.relpath(os.path.join(analyzer_target_dir, scan_dir, scan_dir), bindir), + os.path.join(bindir, scan_dir)) + + mandir = os.path.join(self.installdir, 'share', 'man', 'man1') + os.makedirs(mandir) + shutil.copy2(os.path.join(tools_src_dir, 'scan-build', 'scan-build.1'), mandir) + except OSError, err: + raise EasyBuildError("Failed to copy static analyzer dirs to install dir: %s", err) + + def sanity_check_step(self): + """Custom sanity check for Clang.""" + shlib_ext = get_shared_lib_ext() + custom_paths = { + 'files': [ + "bin/clang", "bin/clang++", "bin/llvm-ar", "bin/llvm-nm", "bin/llvm-as", "bin/opt", "bin/llvm-link", + "bin/llvm-config", "bin/llvm-symbolizer", "include/llvm-c/Core.h", "include/clang-c/Index.h", + "lib/libclang.%s" % shlib_ext, "lib/clang/%s/include/stddef.h" % self.version, + ], + 'dirs': ["include/clang", "include/llvm", "lib/clang/%s/lib" % self.version], + } + if self.cfg['static_analyzer']: + custom_paths['files'].extend(["bin/scan-build", "bin/scan-view"]) + + if self.cfg["usepolly"]: + custom_paths['files'].extend(["lib/LLVMPolly.%s" % shlib_ext]) + custom_paths['dirs'].extend(["include/polly"]) + + if LooseVersion(self.version) >= LooseVersion('3.8'): + custom_paths['files'].extend(["lib/libomp.%s" % shlib_ext, "lib/clang/%s/include/omp.h" % self.version]) + + super(EB_Clang, self).sanity_check_step(custom_paths=custom_paths) + + def make_module_extra(self): + """Custom variables for Clang module.""" + txt = super(EB_Clang, self).make_module_extra() + # we set the symbolizer path so that asan/tsan give meanfull output by default + asan_symbolizer_path = os.path.join(self.installdir, 'bin', 'llvm-symbolizer') + txt += self.module_generator.set_environment('ASAN_SYMBOLIZER_PATH', asan_symbolizer_path) + return txt diff --git a/easyblocks/c/clang.py b/easyblocks/c/clang.py new file mode 100644 index 0000000000000000000000000000000000000000..18edaee51acf8411cde3da4a46708c90cfd8f0a8 --- /dev/null +++ b/easyblocks/c/clang.py @@ -0,0 +1,420 @@ +## +# Copyright 2013 Dmitri Gribenko +# Copyright 2013-2017 Ghent University +# Copyright 2017 IT4Innovations +# +# 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 <http://www.gnu.org/licenses/>. +## +""" +Support for building and installing Clang, implemented as an easyblock. + +@author: Dmitri Gribenko (National Technical University of Ukraine "KPI") +@author: Ward Poelmans (Ghent University) +@author: Josef Hrabal, Lukas Krupcik (IT4innovations, Czechia) +""" + +import fileinput +import glob +import os +import re +import shutil +import sys +from distutils.version import LooseVersion + +from easybuild.easyblocks.generic.cmakemake import CMakeMake +from easybuild.framework.easyconfig import CUSTOM +from easybuild.tools import run +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.config import build_option +from easybuild.tools.filetools import mkdir +from easybuild.tools.modules import get_software_root +from easybuild.tools.run import run_cmd +from easybuild.tools.systemtools import get_os_name, get_os_version, get_shared_lib_ext + +# List of all possible build targets for Clang +CLANG_TARGETS = ["all", "AArch64", "ARM", "CppBackend", "Hexagon", "Mips", + "MBlaze", "MSP430", "NVPTX", "PowerPC", "R600", "Sparc", + "SystemZ", "X86", "XCore"] + + +class EB_Clang(CMakeMake): + """Support for bootstrapping Clang.""" + + @staticmethod + def extra_options(): + extra_vars = { + 'assertions': [True, "Enable assertions. Helps to catch bugs in Clang.", CUSTOM], + 'build_targets': [["X86"], "Build targets for LLVM. Possible values: " + ', '.join(CLANG_TARGETS), CUSTOM], + 'bootstrap': [True, "Bootstrap Clang using GCC", CUSTOM], + 'usepolly': [False, "Build Clang with polly", CUSTOM], + 'static_analyzer': [True, "Install the static analyser of Clang", CUSTOM], + # The sanitizer tests often fail on HPC systems due to the 'weird' environment. + 'skip_sanitizer_tests': [False, "Do not run the sanitizer tests", CUSTOM], + } + + return CMakeMake.extra_options(extra_vars) + + def __init__(self, *args, **kwargs): + """Initialize custom class variables for Clang.""" + + super(EB_Clang, self).__init__(*args, **kwargs) + self.llvm_src_dir = None + self.llvm_obj_dir_stage1 = None + self.llvm_obj_dir_stage2 = None + self.llvm_obj_dir_stage3 = None + self.make_parallel_opts = "" + + unknown_targets = [target for target in self.cfg['build_targets'] if target not in CLANG_TARGETS] + + if unknown_targets: + raise EasyBuildError("Some of the chosen build targets (%s) are not in %s.", + ', '.join(unknown_targets), ', '.join(CLANG_TARGETS)) + + if LooseVersion(self.version) < LooseVersion('3.4') and "R600" in self.cfg['build_targets']: + raise EasyBuildError("Build target R600 not supported in < Clang-3.4") + + if LooseVersion(self.version) > LooseVersion('3.3') and "MBlaze" in self.cfg['build_targets']: + raise EasyBuildError("Build target MBlaze is not supported anymore in > Clang-3.3") + + def check_readiness_step(self): + """Fail early on RHEL 5.x and derivatives because of known bug in libc.""" + super(EB_Clang, self).check_readiness_step() + # RHEL 5.x have a buggy libc. Building stage 2 will fail. + if get_os_name() in ['redhat', 'RHEL', 'centos', 'SL'] and get_os_version().startswith('5.'): + raise EasyBuildError("Can not build Clang on %s v5.x: libc is buggy, building stage 2 will fail. " + "See http://stackoverflow.com/questions/7276828/", get_os_name()) + + def extract_step(self): + """ + Prepare a combined LLVM source tree. The layout is: + llvm/ Unpack llvm-*.tar.gz here + projects/ + compiler-rt/ Unpack compiler-rt-*.tar.gz here + openmp/ Unpack openmp-*.tar.xz here + libcxx/ Unpack libcxx-*.tar.xz here + libcxxabi/ Unpack libcxxapbi-*.tar.xz here + tools/ + clang/ Unpack cfe-*.tar.gz here + tools/extra Unpack clang-*.tar.gz here + polly/ Unpack polly-*.tar.gz here + """ + + # Extract everything into separate directories. + super(EB_Clang, self).extract_step() + + # Find the full path to the directory that was unpacked from llvm-*.tar.gz. + for tmp in self.src: + if tmp['name'].startswith("llvm-"): + self.llvm_src_dir = tmp['finalpath'] + break + + if self.llvm_src_dir is None: + raise EasyBuildError("Could not determine LLVM source root (LLVM source was not unpacked?)") + + src_dirs = {} + + def find_source_dir(globpatterns, targetdir): + """Search for directory with globpattern and rename it to targetdir""" + if not isinstance(globpatterns, list): + globpatterns = [globpatterns] + + glob_src_dirs = [glob_dir for globpattern in globpatterns for glob_dir in glob.glob(globpattern)] + if len(glob_src_dirs) != 1: + raise EasyBuildError("Failed to find exactly one source directory for pattern %s: %s", globpatterns, + glob_src_dirs) + src_dirs[glob_src_dirs[0]] = targetdir + + find_source_dir('compiler-rt-*', os.path.join(self.llvm_src_dir, 'projects', 'compiler-rt')) + + if self.cfg["usepolly"]: + find_source_dir('polly-*', os.path.join(self.llvm_src_dir, 'tools', 'polly')) + + find_source_dir('cfe-*', os.path.join(self.llvm_src_dir, 'tools', 'clang')) + + find_source_dir('clang-*', os.path.join(self.llvm_src_dir, 'tools', 'clang', 'tools', 'extra')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libcxx-*', os.path.join(self.llvm_src_dir, 'projects', 'libcxx')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libcxxabi-*', os.path.join(self.llvm_src_dir, 'projects', 'libcxxabi')) + + if LooseVersion(self.version) >= LooseVersion('3.8'): + find_source_dir('openmp-*', os.path.join(self.llvm_src_dir, 'projects', 'openmp')) + + for src in self.src: + for (dirname, new_path) in src_dirs.items(): + if src['name'].startswith(dirname): + old_path = os.path.join(src['finalpath'], dirname) + try: + shutil.move(old_path, new_path) + except IOError, err: + raise EasyBuildError("Failed to move %s to %s: %s", old_path, new_path, err) + src['finalpath'] = new_path + break + + def configure_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).configure_step() + return + + """Run CMake for stage 1 Clang.""" + self.llvm_obj_dir_stage1 = os.path.join(self.builddir, 'llvm.obj.1') + if self.cfg['bootstrap']: + self.llvm_obj_dir_stage2 = os.path.join(self.builddir, 'llvm.obj.2') + self.llvm_obj_dir_stage3 = os.path.join(self.builddir, 'llvm.obj.3') + + if LooseVersion(self.version) >= LooseVersion('3.3'): + disable_san_tests = False + # all sanitizer tests will fail when there's a limit on the vmem + # this is ugly but I haven't found a cleaner way so far + (vmemlim, ec) = run_cmd("ulimit -v", regexp=False) + if not vmemlim.startswith("unlimited"): + disable_san_tests = True + self.log.warn("There is a virtual memory limit set of %s KB. The tests of the " + "sanitizers will be disabled as they need unlimited virtual " + "memory unless --strict=error is used." % vmemlim.strip()) + + # the same goes for unlimited stacksize + (stacklim, ec) = run_cmd("ulimit -s", regexp=False) + if stacklim.startswith("unlimited"): + disable_san_tests = True + self.log.warn("The stacksize limit is set to unlimited. This causes the ThreadSanitizer " + "to fail. The sanitizers tests will be disabled unless --strict=error is used.") + + if (disable_san_tests or self.cfg['skip_sanitizer_tests']) and build_option('strict') != run.ERROR: + self.log.debug("Disabling the sanitizer tests") + self.disable_sanitizer_tests() + + # Create and enter build directory. + mkdir(self.llvm_obj_dir_stage1) + os.chdir(self.llvm_obj_dir_stage1) + + # GCC and Clang are installed in different prefixes and Clang will not + # find the GCC installation on its own. + # First try with GCCcore, as GCC built on top of GCCcore is just a wrapper for GCCcore and binutils, + # instead of a full-fledge compiler + gcc_prefix = get_software_root('GCCcore') + + # If that doesn't work, try with GCC + if gcc_prefix is None: + gcc_prefix = get_software_root('GCC') + + # If that doesn't work either, print error and exit + if gcc_prefix is None: + raise EasyBuildError("Can't find GCC or GCCcore to use") + + self.cfg.update('configopts', "-DGCC_INSTALL_PREFIX='%s' " % gcc_prefix) + self.log.debug("Using %s as GCC_INSTALL_PREFIX", gcc_prefix) + + self.cfg['configopts'] += "-DCMAKE_BUILD_TYPE=Release " + if self.cfg['assertions']: + self.cfg['configopts'] += "-DLLVM_ENABLE_ASSERTIONS=ON " + else: + self.cfg['configopts'] += "-DLLVM_ENABLE_ASSERTIONS=OFF " + + self.cfg['configopts'] += '-DLLVM_TARGETS_TO_BUILD="%s" ' % ';'.join(self.cfg['build_targets']) + + if self.cfg['parallel']: + self.make_parallel_opts = "-j %s" % self.cfg['parallel'] + + self.log.info("Configuring") + super(EB_Clang, self).configure_step(srcdir=self.llvm_src_dir) + + def disable_sanitizer_tests(self): + """Disable the tests of all the sanitizers by removing the test directories from the build system""" + if LooseVersion(self.version) < LooseVersion('3.6'): + # for Clang 3.5 and lower, the tests are scattered over several CMakeLists. + # We loop over them, and patch out the rule that adds the sanitizers tests to the testsuite + patchfiles = [ + "lib/asan", + "lib/dfsan", + "lib/lsan", + "lib/msan", + "lib/tsan", + "lib/ubsan", + ] + + for patchfile in patchfiles: + patchfile_fp = os.path.join(self.llvm_src_dir, "projects/compiler-rt", patchfile, "CMakeLists.txt") + if os.path.exists(patchfile_fp): + self.log.debug("Patching %s in %s" % (patchfile, self.llvm_src_dir)) + try: + for line in fileinput.input(patchfile_fp, inplace=1, backup='.orig'): + if "add_subdirectory(lit_tests)" not in line: + sys.stdout.write(line) + except (IOError, OSError), err: + raise EasyBuildError("Failed to patch %s: %s", patchfile_fp, err) + else: + self.log.debug("Not patching non-existent %s in %s" % (patchfile, self.llvm_src_dir)) + + # There is a common part seperate for the specific saniters, we disable all + # the common tests + patchfile = "projects/compiler-rt/lib/sanitizer_common/CMakeLists.txt" + try: + for line in fileinput.input("%s/%s" % (self.llvm_src_dir, patchfile), inplace=1, backup='.orig'): + if "add_subdirectory(tests)" not in line: + sys.stdout.write(line) + except IOError, err: + raise EasyBuildError("Failed to patch %s/%s: %s", self.llvm_src_dir, patchfile, err) + else: + # In Clang 3.6, the sanitizer tests are grouped together in one CMakeLists + # We patch out adding the subdirectories with the sanitizer tests + patchfile = "projects/compiler-rt/test/CMakeLists.txt" + patchfile_fp = os.path.join(self.llvm_src_dir, patchfile) + self.log.debug("Patching %s in %s" % (patchfile, self.llvm_src_dir)) + patch_regex = re.compile(r'add_subdirectory\((.*san|sanitizer_common)\)') + try: + for line in fileinput.input(patchfile_fp, inplace=1, backup='.orig'): + if not patch_regex.search(line): + sys.stdout.write(line) + except IOError, err: + raise EasyBuildError("Failed to patch %s: %s", patchfile_fp, err) + + def build_with_prev_stage(self, prev_obj, next_obj): + """Build Clang stage N using Clang stage N-1""" + + # Create and enter build directory. + mkdir(next_obj) + os.chdir(next_obj) + + # Configure. + CC = os.path.join(prev_obj, 'bin', 'clang') + CXX = os.path.join(prev_obj, 'bin', 'clang++') + + options = "-DCMAKE_INSTALL_PREFIX=%s " % self.installdir + options += "-DCMAKE_C_COMPILER='%s' " % CC + options += "-DCMAKE_CXX_COMPILER='%s' " % CXX + options += self.cfg['configopts'] + + self.log.info("Configuring") + run_cmd("cmake %s %s" % (options, self.llvm_src_dir), log_all=True) + + self.log.info("Building") + run_cmd("make %s" % self.make_parallel_opts, log_all=True) + + def run_clang_tests(self, obj_dir): + os.chdir(obj_dir) + + self.log.info("Running tests") + run_cmd("make %s check-all" % self.make_parallel_opts, log_all=True) + + def build_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).build_step() + return + + """Build Clang stage 1, 2, 3""" + + # Stage 1: build using system compiler. + self.log.info("Building stage 1") + os.chdir(self.llvm_obj_dir_stage1) + super(EB_Clang, self).build_step() + + if self.cfg['bootstrap']: + # Stage 1: run tests. + self.run_clang_tests(self.llvm_obj_dir_stage1) + + self.log.info("Building stage 2") + self.build_with_prev_stage(self.llvm_obj_dir_stage1, self.llvm_obj_dir_stage2) + self.run_clang_tests(self.llvm_obj_dir_stage2) + + self.log.info("Building stage 3") + self.build_with_prev_stage(self.llvm_obj_dir_stage2, self.llvm_obj_dir_stage3) + # Don't run stage 3 tests here, do it in the test step. + + def test_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).test_step() + return + + if self.cfg['bootstrap']: + self.run_clang_tests(self.llvm_obj_dir_stage3) + else: + self.run_clang_tests(self.llvm_obj_dir_stage1) + + def install_step(self): + if LooseVersion(self.version) >= LooseVersion('5.0'): + super(EB_Clang, self).install_step() + return + + """Install stage 3 binaries.""" + + if self.cfg['bootstrap']: + os.chdir(self.llvm_obj_dir_stage3) + else: + os.chdir(self.llvm_obj_dir_stage1) + super(EB_Clang, self).install_step() + + # the static analyzer is not installed by default + # we do it by hand + if self.cfg['static_analyzer'] and LooseVersion(self.version) < LooseVersion('3.8'): + try: + tools_src_dir = os.path.join(self.llvm_src_dir, 'tools', 'clang', 'tools') + analyzer_target_dir = os.path.join(self.installdir, 'libexec', 'clang-analyzer') + bindir = os.path.join(self.installdir, 'bin') + for scan_dir in ['scan-build', 'scan-view']: + shutil.copytree(os.path.join(tools_src_dir, scan_dir), os.path.join(analyzer_target_dir, scan_dir)) + os.symlink(os.path.relpath(bindir, os.path.join(analyzer_target_dir, scan_dir)), + os.path.join(analyzer_target_dir, scan_dir, 'bin')) + os.symlink(os.path.relpath(os.path.join(analyzer_target_dir, scan_dir, scan_dir), bindir), + os.path.join(bindir, scan_dir)) + + mandir = os.path.join(self.installdir, 'share', 'man', 'man1') + os.makedirs(mandir) + shutil.copy2(os.path.join(tools_src_dir, 'scan-build', 'scan-build.1'), mandir) + except OSError, err: + raise EasyBuildError("Failed to copy static analyzer dirs to install dir: %s", err) + + def sanity_check_step(self): + """Custom sanity check for Clang.""" + shlib_ext = get_shared_lib_ext() + custom_paths = { + 'files': [ + "bin/clang", "bin/clang++", "bin/llvm-ar", "bin/llvm-nm", "bin/llvm-as", "bin/opt", "bin/llvm-link", + "bin/llvm-config", "bin/llvm-symbolizer", "include/llvm-c/Core.h", "include/clang-c/Index.h", + "lib/libclang.%s" % shlib_ext, "lib/clang/%s/include/stddef.h" % self.version, + ], + 'dirs': ["include/clang", "include/llvm", "lib/clang/%s/lib" % self.version], + } + if self.cfg['static_analyzer']: + custom_paths['files'].extend(["bin/scan-build", "bin/scan-view"]) + + if self.cfg["usepolly"]: + custom_paths['files'].extend(["lib/LLVMPolly.%s" % shlib_ext]) + custom_paths['dirs'].extend(["include/polly"]) + + if LooseVersion(self.version) >= LooseVersion('3.8'): + custom_paths['files'].extend(["lib/libomp.%s" % shlib_ext, "lib/clang/%s/include/omp.h" % self.version]) + + super(EB_Clang, self).sanity_check_step(custom_paths=custom_paths) + + def make_module_extra(self): + """Custom variables for Clang module.""" + txt = super(EB_Clang, self).make_module_extra() + # we set the symbolizer path so that asan/tsan give meanfull output by default + asan_symbolizer_path = os.path.join(self.installdir, 'bin', 'llvm-symbolizer') + txt += self.module_generator.set_environment('ASAN_SYMBOLIZER_PATH', asan_symbolizer_path) + return txt diff --git a/easyblocks/c/clang.py.old b/easyblocks/c/clang.py.old new file mode 100644 index 0000000000000000000000000000000000000000..e0b60edd5711bfaf160e7fbb3ec52902fd149a04 --- /dev/null +++ b/easyblocks/c/clang.py.old @@ -0,0 +1,403 @@ +## +# Copyright 2013 Dmitri Gribenko +# Copyright 2013-2017 Ghent University +# +# 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 <http://www.gnu.org/licenses/>. +## +""" +Support for building and installing Clang, implemented as an easyblock. + +@author: Dmitri Gribenko (National Technical University of Ukraine "KPI") +@author: Ward Poelmans (Ghent University) +""" + +import fileinput +import glob +import os +import re +import shutil +import sys +from distutils.version import LooseVersion + +from easybuild.easyblocks.generic.cmakemake import CMakeMake +from easybuild.framework.easyconfig import CUSTOM +from easybuild.tools import run +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.config import build_option +from easybuild.tools.filetools import mkdir +from easybuild.tools.modules import get_software_root +from easybuild.tools.run import run_cmd +from easybuild.tools.systemtools import get_os_name, get_os_version, get_shared_lib_ext + +# List of all possible build targets for Clang +CLANG_TARGETS = ["all", "AArch64", "ARM", "CppBackend", "Hexagon", "Mips", + "MBlaze", "MSP430", "NVPTX", "PowerPC", "R600", "Sparc", + "SystemZ", "X86", "XCore"] + + +class EB_Clang(CMakeMake): + """Support for bootstrapping Clang.""" + + @staticmethod + def extra_options(): + extra_vars = { + 'assertions': [True, "Enable assertions. Helps to catch bugs in Clang.", CUSTOM], + 'build_targets': [["X86"], "Build targets for LLVM. Possible values: " + ', '.join(CLANG_TARGETS), CUSTOM], + 'bootstrap': [True, "Bootstrap Clang using GCC", CUSTOM], + 'usepolly': [False, "Build Clang with polly", CUSTOM], + 'static_analyzer': [True, "Install the static analyser of Clang", CUSTOM], + # The sanitizer tests often fail on HPC systems due to the 'weird' environment. + 'skip_sanitizer_tests': [False, "Do not run the sanitizer tests", CUSTOM], + } + + return CMakeMake.extra_options(extra_vars) + + def __init__(self, *args, **kwargs): + """Initialize custom class variables for Clang.""" + + super(EB_Clang, self).__init__(*args, **kwargs) + self.llvm_src_dir = None + self.llvm_obj_dir_stage1 = None + self.llvm_obj_dir_stage2 = None + self.llvm_obj_dir_stage3 = None + self.make_parallel_opts = "" + + unknown_targets = [target for target in self.cfg['build_targets'] if target not in CLANG_TARGETS] + + if unknown_targets: + raise EasyBuildError("Some of the chosen build targets (%s) are not in %s.", + ', '.join(unknown_targets), ', '.join(CLANG_TARGETS)) + + if LooseVersion(self.version) < LooseVersion('3.4') and "R600" in self.cfg['build_targets']: + raise EasyBuildError("Build target R600 not supported in < Clang-3.4") + + if LooseVersion(self.version) > LooseVersion('3.3') and "MBlaze" in self.cfg['build_targets']: + raise EasyBuildError("Build target MBlaze is not supported anymore in > Clang-3.3") + + def check_readiness_step(self): + """Fail early on RHEL 5.x and derivatives because of known bug in libc.""" + super(EB_Clang, self).check_readiness_step() + # RHEL 5.x have a buggy libc. Building stage 2 will fail. + if get_os_name() in ['redhat', 'RHEL', 'centos', 'SL'] and get_os_version().startswith('5.'): + raise EasyBuildError("Can not build Clang on %s v5.x: libc is buggy, building stage 2 will fail. " + "See http://stackoverflow.com/questions/7276828/", get_os_name()) + + def extract_step(self): + """ + Prepare a combined LLVM source tree. The layout is: + llvm/ Unpack llvm-*.tar.gz here + projects/ + compiler-rt/ Unpack compiler-rt-*.tar.gz here + openmp/ Unpack openmp-*.tar.xz here + libcxx/ + libcxxabi/ + tools/ + clang/ Unpack clang-*.tar.gz here + clang/tools/extra + polly/ Unpack polly-*.tar.gz here + """ + + # Extract everything into separate directories. + super(EB_Clang, self).extract_step() + + # Find the full path to the directory that was unpacked from llvm-*.tar.gz. + for tmp in self.src: + if tmp['name'].startswith("llvm-"): + self.llvm_src_dir = tmp['finalpath'] + break + + if self.llvm_src_dir is None: + raise EasyBuildError("Could not determine LLVM source root (LLVM source was not unpacked?)") + + src_dirs = {} + + def find_source_dir(globpatterns, targetdir): + """Search for directory with globpattern and rename it to targetdir""" + if not isinstance(globpatterns, list): + globpatterns = [globpatterns] + + glob_src_dirs = [glob_dir for globpattern in globpatterns for glob_dir in glob.glob(globpattern)] + if len(glob_src_dirs) != 1: + raise EasyBuildError("Failed to find exactly one source directory for pattern %s: %s", globpatterns, + glob_src_dirs) + src_dirs[glob_src_dirs[0]] = targetdir + + find_source_dir('compiler-rt-*', os.path.join(self.llvm_src_dir, 'projects', 'compiler-rt')) + + if self.cfg["usepolly"]: + find_source_dir('polly-*', os.path.join(self.llvm_src_dir, 'tools', 'polly')) + + find_source_dir('cfe-*', os.path.join(self.llvm_src_dir, 'tools', 'clang')) + + find_source_dir('clang-*', os.path.join(self.llvm_src_dir, 'tools', 'clang', 'tools', 'extra')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libcxx-*', os.path.join(self.llvm_src_dir, 'projects', 'libcxx')) + + if LooseVersion(self.version) >= LooseVersion('5.0'): + find_source_dir('libcxxabi-*', os.path.join(self.llvm_src_dir, 'projects', 'libcxxabi')) + + if LooseVersion(self.version) >= LooseVersion('3.8'): + find_source_dir('openmp-*', os.path.join(self.llvm_src_dir, 'projects', 'openmp')) + + for src in self.src: + for (dirname, new_path) in src_dirs.items(): + if src['name'].startswith(dirname): + old_path = os.path.join(src['finalpath'], dirname) + try: + shutil.move(old_path, new_path) + except IOError, err: + raise EasyBuildError("Failed to move %s to %s: %s", old_path, new_path, err) + src['finalpath'] = new_path + break + + def configure_step(self): + """Run CMake for stage 1 Clang.""" + + self.llvm_obj_dir_stage1 = os.path.join(self.builddir, 'llvm.obj.1') + if self.cfg['bootstrap']: + self.llvm_obj_dir_stage2 = os.path.join(self.builddir, 'llvm.obj.2') + self.llvm_obj_dir_stage3 = os.path.join(self.builddir, 'llvm.obj.3') + + if LooseVersion(self.version) >= LooseVersion('3.3'): + disable_san_tests = False + # all sanitizer tests will fail when there's a limit on the vmem + # this is ugly but I haven't found a cleaner way so far + (vmemlim, ec) = run_cmd("ulimit -v", regexp=False) + if not vmemlim.startswith("unlimited"): + disable_san_tests = True + self.log.warn("There is a virtual memory limit set of %s KB. The tests of the " + "sanitizers will be disabled as they need unlimited virtual " + "memory unless --strict=error is used." % vmemlim.strip()) + + # the same goes for unlimited stacksize + (stacklim, ec) = run_cmd("ulimit -s", regexp=False) + if stacklim.startswith("unlimited"): + disable_san_tests = True + self.log.warn("The stacksize limit is set to unlimited. This causes the ThreadSanitizer " + "to fail. The sanitizers tests will be disabled unless --strict=error is used.") + + if (disable_san_tests or self.cfg['skip_sanitizer_tests']) and build_option('strict') != run.ERROR: + self.log.debug("Disabling the sanitizer tests") + self.disable_sanitizer_tests() + + # Create and enter build directory. + mkdir(self.llvm_obj_dir_stage1) + os.chdir(self.llvm_obj_dir_stage1) + + # GCC and Clang are installed in different prefixes and Clang will not + # find the GCC installation on its own. + # First try with GCCcore, as GCC built on top of GCCcore is just a wrapper for GCCcore and binutils, + # instead of a full-fledge compiler + gcc_prefix = get_software_root('GCCcore') + + # If that doesn't work, try with GCC + if gcc_prefix is None: + gcc_prefix = get_software_root('GCC') + + # If that doesn't work either, print error and exit + if gcc_prefix is None: + raise EasyBuildError("Can't find GCC or GCCcore to use") + + self.cfg.update('configopts', "-DGCC_INSTALL_PREFIX='%s' " % gcc_prefix) + self.log.debug("Using %s as GCC_INSTALL_PREFIX", gcc_prefix) + + self.cfg['configopts'] += "-DCMAKE_BUILD_TYPE=Release " + if self.cfg['assertions']: + self.cfg['configopts'] += "-DLLVM_ENABLE_ASSERTIONS=ON " + else: + self.cfg['configopts'] += "-DLLVM_ENABLE_ASSERTIONS=OFF " + + self.cfg['configopts'] += '-DLLVM_TARGETS_TO_BUILD="%s" ' % ';'.join(self.cfg['build_targets']) + + if self.cfg['parallel']: + self.make_parallel_opts = "-j %s" % self.cfg['parallel'] + + self.log.info("Configuring") + super(EB_Clang, self).configure_step(srcdir=self.llvm_src_dir) + + def disable_sanitizer_tests(self): + """Disable the tests of all the sanitizers by removing the test directories from the build system""" + if LooseVersion(self.version) < LooseVersion('3.6'): + # for Clang 3.5 and lower, the tests are scattered over several CMakeLists. + # We loop over them, and patch out the rule that adds the sanitizers tests to the testsuite + patchfiles = [ + "lib/asan", + "lib/dfsan", + "lib/lsan", + "lib/msan", + "lib/tsan", + "lib/ubsan", + ] + + for patchfile in patchfiles: + patchfile_fp = os.path.join(self.llvm_src_dir, "projects/compiler-rt", patchfile, "CMakeLists.txt") + if os.path.exists(patchfile_fp): + self.log.debug("Patching %s in %s" % (patchfile, self.llvm_src_dir)) + try: + for line in fileinput.input(patchfile_fp, inplace=1, backup='.orig'): + if "add_subdirectory(lit_tests)" not in line: + sys.stdout.write(line) + except (IOError, OSError), err: + raise EasyBuildError("Failed to patch %s: %s", patchfile_fp, err) + else: + self.log.debug("Not patching non-existent %s in %s" % (patchfile, self.llvm_src_dir)) + + # There is a common part seperate for the specific saniters, we disable all + # the common tests + patchfile = "projects/compiler-rt/lib/sanitizer_common/CMakeLists.txt" + try: + for line in fileinput.input("%s/%s" % (self.llvm_src_dir, patchfile), inplace=1, backup='.orig'): + if "add_subdirectory(tests)" not in line: + sys.stdout.write(line) + except IOError, err: + raise EasyBuildError("Failed to patch %s/%s: %s", self.llvm_src_dir, patchfile, err) + else: + # In Clang 3.6, the sanitizer tests are grouped together in one CMakeLists + # We patch out adding the subdirectories with the sanitizer tests + patchfile = "projects/compiler-rt/test/CMakeLists.txt" + patchfile_fp = os.path.join(self.llvm_src_dir, patchfile) + self.log.debug("Patching %s in %s" % (patchfile, self.llvm_src_dir)) + patch_regex = re.compile(r'add_subdirectory\((.*san|sanitizer_common)\)') + try: + for line in fileinput.input(patchfile_fp, inplace=1, backup='.orig'): + if not patch_regex.search(line): + sys.stdout.write(line) + except IOError, err: + raise EasyBuildError("Failed to patch %s: %s", patchfile_fp, err) + + def build_with_prev_stage(self, prev_obj, next_obj): + """Build Clang stage N using Clang stage N-1""" + + # Create and enter build directory. + mkdir(next_obj) + os.chdir(next_obj) + + # Configure. + CC = os.path.join(prev_obj, 'bin', 'clang') + CXX = os.path.join(prev_obj, 'bin', 'clang++') + + options = "-DCMAKE_INSTALL_PREFIX=%s " % self.installdir + options += "-DCMAKE_C_COMPILER='%s' " % CC + options += "-DCMAKE_CXX_COMPILER='%s' " % CXX + options += self.cfg['configopts'] + + self.log.info("Configuring") + run_cmd("cmake %s %s" % (options, self.llvm_src_dir), log_all=True) + + self.log.info("Building") + run_cmd("make %s" % self.make_parallel_opts, log_all=True) + + def run_clang_tests(self, obj_dir): + os.chdir(obj_dir) + + self.log.info("Running tests") + run_cmd("make %s check-all" % self.make_parallel_opts, log_all=True) + + def build_step(self): + """Build Clang stage 1, 2, 3""" + + # Stage 1: build using system compiler. + self.log.info("Building stage 1") + os.chdir(self.llvm_obj_dir_stage1) + super(EB_Clang, self).build_step() + + if self.cfg['bootstrap']: + # Stage 1: run tests. + self.run_clang_tests(self.llvm_obj_dir_stage1) + + self.log.info("Building stage 2") + self.build_with_prev_stage(self.llvm_obj_dir_stage1, self.llvm_obj_dir_stage2) + self.run_clang_tests(self.llvm_obj_dir_stage2) + + self.log.info("Building stage 3") + self.build_with_prev_stage(self.llvm_obj_dir_stage2, self.llvm_obj_dir_stage3) + # Don't run stage 3 tests here, do it in the test step. + + def test_step(self): + if self.cfg['bootstrap']: + self.run_clang_tests(self.llvm_obj_dir_stage3) + else: + self.run_clang_tests(self.llvm_obj_dir_stage1) + + def install_step(self): + """Install stage 3 binaries.""" + + if self.cfg['bootstrap']: + os.chdir(self.llvm_obj_dir_stage3) + else: + os.chdir(self.llvm_obj_dir_stage1) + super(EB_Clang, self).install_step() + + # the static analyzer is not installed by default + # we do it by hand + if self.cfg['static_analyzer'] and LooseVersion(self.version) < LooseVersion('3.8'): + try: + tools_src_dir = os.path.join(self.llvm_src_dir, 'tools', 'clang', 'tools') + analyzer_target_dir = os.path.join(self.installdir, 'libexec', 'clang-analyzer') + bindir = os.path.join(self.installdir, 'bin') + for scan_dir in ['scan-build', 'scan-view']: + shutil.copytree(os.path.join(tools_src_dir, scan_dir), os.path.join(analyzer_target_dir, scan_dir)) + os.symlink(os.path.relpath(bindir, os.path.join(analyzer_target_dir, scan_dir)), + os.path.join(analyzer_target_dir, scan_dir, 'bin')) + os.symlink(os.path.relpath(os.path.join(analyzer_target_dir, scan_dir, scan_dir), bindir), + os.path.join(bindir, scan_dir)) + + mandir = os.path.join(self.installdir, 'share', 'man', 'man1') + os.makedirs(mandir) + shutil.copy2(os.path.join(tools_src_dir, 'scan-build', 'scan-build.1'), mandir) + except OSError, err: + raise EasyBuildError("Failed to copy static analyzer dirs to install dir: %s", err) + + def sanity_check_step(self): + """Custom sanity check for Clang.""" + shlib_ext = get_shared_lib_ext() + custom_paths = { + 'files': [ + "bin/clang", "bin/clang++", "bin/llvm-ar", "bin/llvm-nm", "bin/llvm-as", "bin/opt", "bin/llvm-link", + "bin/llvm-config", "bin/llvm-symbolizer", "include/llvm-c/Core.h", "include/clang-c/Index.h", + "lib/libclang.%s" % shlib_ext, "lib/clang/%s/include/stddef.h" % self.version, + ], + 'dirs': ["include/clang", "include/llvm", "lib/clang/%s/lib" % self.version], + } + if self.cfg['static_analyzer']: + custom_paths['files'].extend(["bin/scan-build", "bin/scan-view"]) + + if self.cfg["usepolly"]: + custom_paths['files'].extend(["lib/LLVMPolly.%s" % shlib_ext]) + custom_paths['dirs'].extend(["include/polly"]) + + if LooseVersion(self.version) >= LooseVersion('3.8'): + custom_paths['files'].extend(["lib/libomp.%s" % shlib_ext, "lib/clang/%s/include/omp.h" % self.version]) + + super(EB_Clang, self).sanity_check_step(custom_paths=custom_paths) + + def make_module_extra(self): + """Custom variables for Clang module.""" + txt = super(EB_Clang, self).make_module_extra() + # we set the symbolizer path so that asan/tsan give meanfull output by default + asan_symbolizer_path = os.path.join(self.installdir, 'bin', 'llvm-symbolizer') + txt += self.module_generator.set_environment('ASAN_SYMBOLIZER_PATH', asan_symbolizer_path) + return txt diff --git a/easyblocks/d/doris.py b/easyblocks/d/doris.py new file mode 100644 index 0000000000000000000000000000000000000000..306e31e8fd285161c4760543cb09e6c566e5c656 --- /dev/null +++ b/easyblocks/d/doris.py @@ -0,0 +1,131 @@ +## +# Copyright 2009-2017 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). +# +# http://github.com/hpcugent/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 Doris, implemented as an easyblock + +author: Kenneth Hoste (HPC-UGent) +""" +import os + +from easybuild.easyblocks.generic.configuremake import ConfigureMake +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.filetools import change_dir, mkdir +from easybuild.tools.modules import get_software_root +from easybuild.tools.run import run_cmd_qa + + +class EB_Doris(ConfigureMake): + """Support for building/installing Doris.""" + + def configure_step(self): + """Custom configuration procedure for Doris.""" + fftw = get_software_root('FFTW') + if fftw is None: + raise EasyBuildError("Required dependency FFTW is missing") + + # create installation directory (and /bin subdirectory) early, make sure it doesn't get removed later + self.make_installdir() + mkdir(os.path.join(self.installdir, 'bin')) + self.cfg['keeppreviousinstall'] = True + + # configure/build/install should be done from 'doris_core' subdirectory + change_dir(os.path.join(self.cfg['start_dir'], 'doris_core')) + + qa = { + "===> Press enter to continue.": '', + "===> What is your C++ compiler? [g++]": os.getenv('CXX'), + "===> Do you have the FFTW library (y/n)? [n]": 'y', + "===> What is the path to the FFTW library (libfftw3f.a or libfftw3f.so)? []": os.path.join(fftw, 'lib'), + "===> What is the path to the FFTW include file (fftw3.h)? []": os.path.join(fftw, 'include'), + "===> Do you have the VECLIB library (y/n)? [n]": 'n', + #"===> Do you have the LAPACK library (y/n)? [n]": 'y', + #"===> What is the path to the LAPACK library liblapack.a? []": os.path.join(lapack, 'lib'), + "==> Do you have the LAPACK library (y/n)? [n]": 'n', + "===> Are you working on a Little Endian (X86 PC, Intel) machine (y/n)? [y]": 'y', + "===> Installation of Doris in directory: /usr/local/bin (y/n)? [y]": 'n', + "===> Enter installation directory (use absolute path):": os.path.join(self.installdir, 'bin'), + "===> Press enter to continue (CTRL-C to exit).": '', + } + std_qa = { + "===> Do you want to compile a more verbose DEBUG version \(y/n\)\? \[n\](.|\n)*expected results\)": 'n', + } + + run_cmd_qa('./configure', qa, std_qa=std_qa, log_all=True, simple=True) + + def build_step(self): + """Custom build procedure for Doris.""" + common_buildopts = self.cfg['buildopts'] + + # build Doris + change_dir(os.path.join(self.cfg['start_dir'], 'doris_core')) + + super(EB_Doris, self).build_step() + + # build SARtools + change_dir(os.path.join(self.cfg['start_dir'], 'sar_tools')) + + self.cfg['buildopts'] = common_buildopts + self.cfg.update('buildopts', 'CC="%s"' % os.getenv('CXX')) + cflags = os.getenv('CXXFLAGS') + " -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" + self.cfg.update('buildopts', 'CFLAGS="%s"' % cflags) + + super(EB_Doris, self).build_step() + + # build ENVISAT_TOOLS + change_dir(os.path.join(self.cfg['start_dir'], 'envisat_tools')) + + self.cfg['buildopts'] = common_buildopts + self.cfg.update('buildopts', 'CC="%s"' % os.getenv('CC')) + self.cfg.update('buildopts', 'CFLAGS="%s"' % os.getenv('CFLAGS')) + + super(EB_Doris, self).build_step() + + def install_step(self): + """Custom build procedure for Doris.""" + # install Doris + change_dir(os.path.join(self.cfg['start_dir'], 'doris_core')) + super(EB_Doris, self).install_step() + + # install SARtools + self.cfg.update('installopts', 'INSTALL_DIR=%s' % os.path.join(self.installdir, 'bin')) + change_dir(os.path.join(self.cfg['start_dir'], 'sar_tools')) + super(EB_Doris, self).install_step() + + # install ENVISAT_TOOLS + change_dir(os.path.join(self.cfg['start_dir'], 'envisat_tools')) + self.cfg.update('installopts', 'CC="%s"' % os.getenv('CC')) + self.cfg.update('installopts', 'CFLAGS="%s"' % os.getenv('CFLAGS')) + super(EB_Doris, self).install_step() + + def sanity_check_step(self): + """Custom sanity check for Doris.""" + doris_bins = ['cpx2ps', 'doris', 'plotcpm', 'run'] + sartools_bins = ['bkconvert', 'cpxfiddle', 'flapjack', 'floatmult', 'wrap'] + envisat_tools_bins = ['envisat_dump_header', 'envisat_dump_data'] + custom_paths = { + 'files': [os.path.join('bin', x) for x in doris_bins + sartools_bins + envisat_tools_bins], + 'dirs': [], + } + super(EB_Doris, self).sanity_check_step(custom_paths=custom_paths) diff --git a/easyblocks/i/imkl.py b/easyblocks/i/imkl.py deleted file mode 100644 index 0fe0a33d043b107c9b9e7f102f7d65e616fa7446..0000000000000000000000000000000000000000 --- a/easyblocks/i/imkl.py +++ /dev/null @@ -1,396 +0,0 @@ -# # -# Copyright 2009-2016 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://vscentrum.be/nl/en), -# Flemish Research Foundation (FWO) (http://www.fwo.be/en) -# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). -# -# http://github.com/hpcugent/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 Math Kernel Library (MKL), 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: Ward Poelmans (Ghent University) -@author: Lumir Jasiok (IT4Innovations) -""" - -import itertools -import os -import shutil -import tempfile -from distutils.version import LooseVersion - -import easybuild.tools.environment as env -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.filetools import rmtree2 -from easybuild.tools.modules import get_software_root -from easybuild.tools.run import run_cmd -from easybuild.tools.systemtools import get_shared_lib_ext - - -class EB_imkl(IntelBase): - """ - Class that can be used to install mkl - - tested with 10.2.1.017 - -- will fail for all older versions (due to newer silent installer) - """ - - @staticmethod - def extra_options(): - """Add easyconfig parameters custom to imkl (e.g. interfaces).""" - extra_vars = { - 'interfaces': [True, "Indicates whether interfaces should be built", CUSTOM], - } - return IntelBase.extra_options(extra_vars) - - def __init__(self, *args, **kwargs): - super(EB_imkl, self).__init__(*args, **kwargs) - # make sure $MKLROOT isn't set, it's known to cause problems with the installation - self.cfg.update('unwanted_env_vars', ['MKLROOT']) - - def install_step(self): - """ - Actual installation - - create silent cfg file - - execute command - """ - silent_cfg_names_map = None - silent_cfg_extras = None - - if LooseVersion(self.version) < LooseVersion('11.1'): - # since imkl v11.1, silent.cfg has been slightly changed to be 'more standard' - - silent_cfg_names_map = { - 'activation_name': ACTIVATION_NAME_2012, - 'license_file_name': LICENSE_FILE_NAME_2012, - } - - if LooseVersion(self.version) >= LooseVersion('11.1'): - silent_cfg_extras = { - 'COMPONENTS': 'ALL', - } - - super(EB_imkl, self).install_step(silent_cfg_names_map=silent_cfg_names_map, silent_cfg_extras=silent_cfg_extras) - - def make_module_req_guess(self): - """ - A dictionary of possible directories to look for - """ - if LooseVersion(self.version) >= LooseVersion('10.3'): - if self.cfg['m32']: - raise EasyBuildError("32-bit not supported yet for IMKL v%s (>= 10.3)", self.version) - else: - retdict = { - 'PATH': ['bin', 'mkl/bin', 'mkl/bin/intel64', 'composerxe-2011/bin'], - 'LD_LIBRARY_PATH': ['lib/intel64', 'mkl/lib/intel64'], - 'LIBRARY_PATH': ['lib/intel64', 'mkl/lib/intel64'], - 'MANPATH': ['man', 'man/en_US'], - 'CPATH': ['mkl/include', 'mkl/include/fftw'], - 'FPATH': ['mkl/include', 'mkl/include/fftw'], - } - if LooseVersion(self.version) >= LooseVersion('11.0'): - if LooseVersion(self.version) >= LooseVersion('11.3'): - retdict['MIC_LD_LIBRARY_PATH'] = ['lib/intel64_lin_mic', 'mkl/lib/mic']; - elif LooseVersion(self.version) >= LooseVersion('11.1'): - retdict['MIC_LD_LIBRARY_PATH'] = ['lib/mic', 'mkl/lib/mic']; - else: - retdict['MIC_LD_LIBRARY_PATH'] = ['compiler/lib/mic', 'mkl/lib/mic']; - return retdict; - else: - if self.cfg['m32']: - return { - 'PATH': ['bin', 'bin/ia32', 'tbb/bin/ia32'], - 'LD_LIBRARY_PATH': ['lib', 'lib/32'], - 'LIBRARY_PATH': ['lib', 'lib/32'], - 'MANPATH': ['man', 'share/man', 'man/en_US'], - 'CPATH': ['include'], - 'FPATH': ['include'] - } - - else: - return { - 'PATH': ['bin', 'bin/intel64', 'tbb/bin/em64t'], - 'LD_LIBRARY_PATH': ['lib', 'lib/em64t'], - 'LIBRARY_PATH': ['lib', 'lib/em64t'], - 'MANPATH': ['man', 'share/man', 'man/en_US'], - 'CPATH': ['include'], - 'FPATH': ['include'], - } - - def make_module_extra(self): - """Overwritten from Application to add extra txt""" - txt = super(EB_imkl, self).make_module_extra() - txt += self.module_generator.set_environment('MKLROOT', os.path.join(self.installdir, 'mkl')) - return txt - - def post_install_step(self): - """ - Install group libraries and interfaces (if desired). - """ - super(EB_imkl, self).post_install_step() - - shlib_ext = get_shared_lib_ext() - - # reload the dependencies - self.load_dependency_modules() - - if self.cfg['m32']: - extra = { - 'libmkl.%s' % shlib_ext : 'GROUP (-lmkl_intel -lmkl_intel_thread -lmkl_core)', - 'libmkl_em64t.a': 'GROUP (libmkl_intel.a libmkl_intel_thread.a libmkl_core.a)', - 'libmkl_solver.a': 'GROUP (libmkl_solver.a)', - 'libmkl_scalapack.a': 'GROUP (libmkl_scalapack_core.a)', - 'libmkl_lapack.a': 'GROUP (libmkl_intel.a libmkl_intel_thread.a libmkl_core.a)', - 'libmkl_cdft.a': 'GROUP (libmkl_cdft_core.a)' - } - else: - extra = { - 'libmkl.%s' % shlib_ext: 'GROUP (-lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core)', - 'libmkl_em64t.a': 'GROUP (libmkl_intel_lp64.a libmkl_intel_thread.a libmkl_core.a)', - 'libmkl_solver.a': 'GROUP (libmkl_solver_lp64.a)', - 'libmkl_scalapack.a': 'GROUP (libmkl_scalapack_lp64.a)', - 'libmkl_lapack.a': 'GROUP (libmkl_intel_lp64.a libmkl_intel_thread.a libmkl_core.a)', - 'libmkl_cdft.a': 'GROUP (libmkl_cdft_core.a)' - } - - if LooseVersion(self.version) >= LooseVersion('10.3'): - libsubdir = os.path.join('mkl', 'lib', 'intel64') - else: - if self.cfg['m32']: - libsubdir = os.path.join('lib', '32') - else: - libsubdir = os.path.join('lib', 'em64t') - - for fil, txt in extra.items(): - dest = os.path.join(self.installdir, libsubdir, fil) - if not os.path.exists(dest): - try: - f = open(dest, 'w') - f.write(txt) - f.close() - self.log.info("File %s written" % dest) - except IOError, err: - raise EasyBuildError("Can't write file %s: %s", dest, err) - - # build the mkl interfaces, if desired - if self.cfg['interfaces']: - - if LooseVersion(self.version) >= LooseVersion('10.3'): - intsubdir = os.path.join('mkl', 'interfaces') - inttarget = 'libintel64' - else: - intsubdir = 'interfaces' - if self.cfg['m32']: - inttarget = 'lib32' - else: - inttarget = 'libem64t' - - cmd = "make -f makefile %s" % inttarget - - # blas95 and lapack95 need more work, ignore for now - # blas95 and lapack also need include/.mod to be processed - fftw2libs = ['fftw2xc', 'fftw2xf'] - fftw3libs = ['fftw3xc', 'fftw3xf'] - cdftlibs = ['fftw2x_cdft'] - if LooseVersion(self.version) >= LooseVersion('10.3'): - cdftlibs.append('fftw3x_cdft') - - interfacedir = os.path.join(self.installdir, intsubdir) - try: - os.chdir(interfacedir) - self.log.info("Changed to interfaces directory %s" % interfacedir) - except OSError, err: - raise EasyBuildError("Can't change to interfaces directory %s", interfacedir) - - compopt = None - # determine whether we're using a non-Intel GCC-based toolchain - # can't use toolchain.comp_family, because of dummy toolchain used when installing imkl - if get_software_root('icc') is None: - if get_software_root('GCC'): - compopt = 'compiler=gnu' - else: - raise EasyBuildError("Not using either Intel compilers nor GCC, " - "don't know how to build wrapper libs") - else: - compopt = 'compiler=intel' - - for lib in fftw2libs + fftw3libs + cdftlibs: - buildopts = [compopt] - if lib in fftw3libs: - buildopts.append('install_to=$INSTALL_DIR') - elif lib in cdftlibs: - mpi_spec = None - # check whether MPI_FAMILY constant is defined, so mpi_family() can be used - if hasattr(self.toolchain, 'MPI_FAMILY') and self.toolchain.MPI_FAMILY is not None: - mpi_spec_by_fam = { - toolchain.MPICH: 'mpich2', # MPICH is MPICH v3.x, which is MPICH2 compatible - toolchain.MPICH2: 'mpich2', - toolchain.MVAPICH2: 'mpich2', - toolchain.OPENMPI: 'openmpi', - } - mpi_fam = self.toolchain.mpi_family() - mpi_spec = mpi_spec_by_fam.get(mpi_fam) - self.log.debug("Determined MPI specification based on MPI toolchain component: %s" % mpi_spec) - else: - # can't use toolchain.mpi_family, because of dummy toolchain - if get_software_root('MPICH2') or get_software_root('MVAPICH2'): - mpi_spec = 'mpich2' - elif get_software_root('OpenMPI'): - mpi_spec = 'openmpi' - self.log.debug("Determined MPI specification based on loaded MPI module: %s" % mpi_spec) - - if mpi_spec is not None: - buildopts.append('mpi=%s' % mpi_spec) - - precflags = [''] - if lib.startswith('fftw2x') and not self.cfg['m32']: - # build both single and double precision variants - precflags = ['PRECISION=MKL_DOUBLE', 'PRECISION=MKL_SINGLE'] - - intflags = [''] - if lib in cdftlibs and not self.cfg['m32']: - # build both 32-bit and 64-bit interfaces - intflags = ['interface=lp64', 'interface=ilp64'] - - allopts = [list(opts) for opts in itertools.product(intflags, precflags)] - - for flags, extraopts in itertools.product(['', '-fPIC'], allopts): - tup = (lib, flags, buildopts, extraopts) - self.log.debug("Building lib %s with: flags %s, buildopts %s, extraopts %s" % tup) - - tmpbuild = tempfile.mkdtemp(dir=self.builddir) - self.log.debug("Created temporary directory %s" % tmpbuild) - - # always set INSTALL_DIR, SPEC_OPT, COPTS and CFLAGS - # fftw2x(c|f): use $INSTALL_DIR, $CFLAGS and $COPTS - # fftw3x(c|f): use $CFLAGS - # fftw*cdft: use $INSTALL_DIR and $SPEC_OPT - env.setvar('INSTALL_DIR', tmpbuild) - env.setvar('SPEC_OPT', flags) - env.setvar('COPTS', flags) - env.setvar('CFLAGS', flags) - - try: - intdir = os.path.join(interfacedir, lib) - os.chdir(intdir) - self.log.info("Changed to interface %s directory %s" % (lib, intdir)) - except OSError, err: - raise EasyBuildError("Can't change to interface %s directory %s: %s", lib, intdir, err) - - fullcmd = "%s %s" % (cmd, ' '.join(buildopts + extraopts)) - res = run_cmd(fullcmd, log_all=True, simple=True) - if not res: - raise EasyBuildError("Building %s (flags: %s, fullcmd: %s) failed", lib, flags, fullcmd) - - for fn in os.listdir(tmpbuild): - src = os.path.join(tmpbuild, fn) - if flags == '-fPIC': - # add _pic to filename - ff = fn.split('.') - fn = '.'.join(ff[:-1]) + '_pic.' + ff[-1] - dest = os.path.join(self.installdir, libsubdir, fn) - try: - if os.path.isfile(src): - shutil.move(src, dest) - self.log.info("Moved %s to %s" % (src, dest)) - except OSError, err: - raise EasyBuildError("Failed to move %s to %s: %s", src, dest, err) - - rmtree2(tmpbuild) - - def sanity_check_step(self): - """Custom sanity check paths for Intel MKL.""" - shlib_ext = get_shared_lib_ext() - - mklfiles = None - mkldirs = None - ver = LooseVersion(self.version) - libs = ['libmkl_core.%s' % shlib_ext, 'libmkl_gnu_thread.%s' % shlib_ext, - 'libmkl_intel_thread.%s' % shlib_ext, 'libmkl_sequential.%s' % shlib_ext] - extralibs = ['libmkl_blacs_intelmpi_%(suff)s.' + shlib_ext, 'libmkl_scalapack_%(suff)s.' + shlib_ext] - - if self.cfg['interfaces']: - compsuff = '_intel' - if get_software_root('icc') is None: - if get_software_root('GCC'): - compsuff = '_gnu' - else: - raise EasyBuildError("Not using Intel/GCC, don't know compiler suffix for FFTW libraries.") - - precs = ['_double', '_single'] - if ver < LooseVersion('11'): - # no precision suffix in libfftw2 libs before imkl v11 - precs = [''] - fftw_vers = ['2x%s%s' % (x, prec) for x in ['c', 'f'] for prec in precs] + ['3xc', '3xf'] - pics = ['', '_pic'] - libs = ['libfftw%s%s%s.a' % (fftwver, compsuff, pic) for fftwver in fftw_vers for pic in pics] - - fftw_cdft_vers = ['2x_cdft_DOUBLE'] - if not self.cfg['m32']: - fftw_cdft_vers.append('2x_cdft_SINGLE') - if ver >= LooseVersion('10.3'): - fftw_cdft_vers.append('3x_cdft') - if ver >= LooseVersion('11.0.2'): - bits = ['_lp64'] - if not self.cfg['m32']: - bits.append('_ilp64') - else: - # no bits suffix in cdft libs before imkl v11.0.2 - bits = [''] - libs += ['libfftw%s%s%s.a' % x for x in itertools.product(fftw_cdft_vers, bits, pics)] - - if ver >= LooseVersion('10.3'): - if self.cfg['m32']: - raise EasyBuildError("Sanity check for 32-bit not implemented yet for IMKL v%s (>= 10.3)", self.version) - else: - mkldirs = ['bin', 'mkl/bin', 'mkl/lib/intel64', 'mkl/include'] - if ver < LooseVersion('11.3'): - mkldirs.append('mkl/bin/intel64') - libs += [lib % {'suff': suff} for lib in extralibs for suff in ['lp64', 'ilp64']] - mklfiles = ['mkl/lib/intel64/libmkl.%s' % shlib_ext, 'mkl/include/mkl.h'] + \ - ['mkl/lib/intel64/%s' % lib for lib in libs] - if ver >= LooseVersion('10.3.4') and ver < LooseVersion('11.1'): - mkldirs += ['compiler/lib/intel64'] - else: - mkldirs += ['lib/intel64'] - - else: - if self.cfg['m32']: - mklfiles = ['lib/32/libmkl.%s' % shlib_ext, 'include/mkl.h'] + \ - ['lib/32/%s' % lib for lib in libs] - mkldirs = ['lib/32', 'include/32', 'interfaces'] - else: - libs += [lib % {'suff': suff} for lib in extralibs for suff in ['lp64', 'ilp64']] - mklfiles = ['lib/em64t/libmkl.%s' % shlib_ext, 'include/mkl.h'] + \ - ['lib/em64t/%s' % lib for lib in libs] - mkldirs = ['lib/em64t', 'include/em64t', 'interfaces'] - - custom_paths = { - 'files': mklfiles, - 'dirs': mkldirs, - } - - super(EB_imkl, self).sanity_check_step(custom_paths=custom_paths) diff --git a/easyblocks/i/impi.py b/easyblocks/i/impi.py new file mode 100644 index 0000000000000000000000000000000000000000..349b6d3085d9feb2468a41e85ded3062a716e12f --- /dev/null +++ b/easyblocks/i/impi.py @@ -0,0 +1,233 @@ +# # +# Copyright 2009-2017 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) +""" +import fileinput +import os +import sys +from distutils.version import LooseVersion + +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.filetools import apply_regex_substitutions +from easybuild.tools.run import run_cmd +from easybuild.tools.systemtools import get_shared_lib_ext + + +class EB_impi(IntelBase): + """ + Support for installing Intel MPI library + """ + @staticmethod + def extra_options(): + extra_vars = { + '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('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") + try: + f = open(silentcfg, 'w') + f.write(silent) + f.close() + except: + raise EasyBuildError("Writing silent cfg file %s failed.", silent) + self.log.debug("Contents of %s: %s" % (silentcfg, silent)) + + tmpdir = os.path.join(os.getcwd(), self.version, 'mytmpdir') + try: + os.makedirs(tmpdir) + except: + raise EasyBuildError("Directory %s can't be created", tmpdir) + + cmd = "./install.sh --tmp-dir=%s --silent=%s" % (tmpdir, silentcfg) + run_cmd(cmd, log_all=True, simple=True) + + 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('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"^I_MPI_ROOT=.*", r"I_MPI_ROOT=%s; export I_MPI_ROOT" % 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) + + def sanity_check_step(self): + """Custom sanity check paths for IMPI.""" + + suff = "64" + if self.cfg['m32']: + suff = "" + + mpi_mods = ['mpi.mod'] + if LooseVersion(self.version) > LooseVersion('4.0'): + mpi_mods.extend(["mpi_base.mod", "mpi_constants.mod", "mpi_sizeofs.mod"]) + + custom_paths = { + 'files': ["bin%s/mpi%s" % (suff, x) for x in ["icc", "icpc", "ifort"]] + + ["include%s/mpi%s.h" % (suff, x) for x in ["cxx", "f", "", "o", "of"]] + + ["include%s/%s" % (suff, x) for x in ["i_malloc.h"] + mpi_mods] + + ["lib%s/libmpi.%s" % (suff, get_shared_lib_ext()), "lib%s/libmpi.a" % suff], + 'dirs': [], + } + + super(EB_impi, self).sanity_check_step(custom_paths=custom_paths) + + def make_module_req_guess(self): + """ + A dictionary of possible directories to look for + """ + if self.cfg['m32']: + lib_dirs = ['lib', 'lib/ia32', 'ia32/lib'] + include_dirs = ['include'] + return { + 'PATH': ['bin', 'bin/ia32', 'ia32/bin'], + 'LD_LIBRARY_PATH': lib_dirs, + 'LIBRARY_PATH': lib_dirs, + 'CPATH': include_dirs, + 'MIC_LD_LIBRARY_PATH' : ['mic/lib'], + } + else: + lib_dirs = ['lib/em64t', 'lib64'] + include_dirs = ['include64'] + return { + 'PATH': ['bin/intel64', 'bin64'], + 'LD_LIBRARY_PATH': lib_dirs, + 'LIBRARY_PATH': lib_dirs, + 'CPATH': include_dirs, + 'MIC_LD_LIBRARY_PATH' : ['mic/lib'], + } + + def make_module_extra(self): + """Overwritten from Application to add extra txt""" + txt = super(EB_impi, self).make_module_extra() + txt += self.module_generator.set_environment('I_MPI_ROOT', self.installdir) + 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') + + return txt diff --git a/easyblocks/t/trilinos.py b/easyblocks/t/trilinos.py new file mode 100644 index 0000000000000000000000000000000000000000..de40dd0a742bfc6d05aebdb955b0b3392163161f --- /dev/null +++ b/easyblocks/t/trilinos.py @@ -0,0 +1,251 @@ +## +# Copyright 2009-2017 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 Trilinos, implemented as an easyblock + +@author: Kenneth Hoste (Ghent University) +""" +import os +import re + +from distutils.version import LooseVersion + +import easybuild.tools.toolchain as toolchain +from easybuild.easyblocks.generic.cmakemake import CMakeMake +from easybuild.framework.easyconfig import CUSTOM +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.modules import get_software_root + + +class EB_Trilinos(CMakeMake): + """Support for building Trilinos.""" + # see http://trilinos.sandia.gov/Trilinos10CMakeQuickstart.txt + + @staticmethod + def extra_options(): + """Add extra config options specific to Trilinos.""" + extra_vars = { + 'shared_libs': [False, "Build shared libs; if False, build static libs", CUSTOM], + 'openmp': [True, "Enable OpenMP support", CUSTOM], + 'all_exts': [True, "Enable all Trilinos packages", CUSTOM], + 'skip_exts': [[], "List of Trilinos packages to skip", CUSTOM], + 'verbose': [False, "Configure for verbose output", CUSTOM], + } + return CMakeMake.extra_options(extra_vars) + + def configure_step(self): + """Set some extra environment variables before configuring.""" + + # enable verbose output if desired + if self.cfg['verbose']: + for x in ["CONFIGURE", "MAKEFILE"]: + self.cfg.update('configopts', "-DTrilinos_VERBOSE_%s:BOOL=ON" % x) + + # compiler flags + cflags = [os.getenv('CFLAGS')] + cxxflags = [os.getenv('CXXFLAGS')] + fflags = [os.getenv('FFLAGS')] + + ignore_cxx_seek_mpis = [toolchain.INTELMPI, toolchain.MPICH, toolchain.MPICH2, toolchain.MVAPICH2] #@UndefinedVariable + ignore_cxx_seek_flag = "-DMPICH_IGNORE_CXX_SEEK" + if self.toolchain.mpi_family() in ignore_cxx_seek_mpis: + cflags.append(ignore_cxx_seek_flag) + cxxflags.append(ignore_cxx_seek_flag) + fflags.append(ignore_cxx_seek_flag) + + self.cfg.update('configopts', '-DCMAKE_C_FLAGS="%s"' % ' '.join(cflags)) + self.cfg.update('configopts', '-DCMAKE_CXX_FLAGS="%s"' % ' '.join(cxxflags)) + self.cfg.update('configopts', '-DCMAKE_Fortran_FLAGS="%s"' % ' '.join(fflags)) + + # OpenMP + if self.cfg['openmp']: + self.cfg.update('configopts', "-DTrilinos_ENABLE_OpenMP:BOOL=ON") + + # MPI + if self.toolchain.options.get('usempi', None): + self.cfg.update('configopts', "-DTPL_ENABLE_MPI:BOOL=ON") + + # shared libraries + if self.cfg['shared_libs']: + self.cfg.update('configopts', "-DBUILD_SHARED_LIBS:BOOL=ON") + else: + self.cfg.update('configopts', "-DBUILD_SHARED_LIBS:BOOL=OFF") + + # release or debug get_version + if self.toolchain.options['debug']: + self.cfg.update('configopts', "-DCMAKE_BUILD_TYPE:STRING=DEBUG") + else: + self.cfg.update('configopts', "-DCMAKE_BUILD_TYPE:STRING=RELEASE") + + # enable full testing + self.cfg.update('configopts', "-DTrilinos_ENABLE_TESTS:BOOL=ON") + self.cfg.update('configopts', "-DTrilinos_ENABLE_ALL_FORWARD_DEP_PACKAGES:BOOL=ON") + + lib_re = re.compile("^lib(.*).a$") + + # BLAS, LAPACK + for dep in ["BLAS", "LAPACK"]: + self.cfg.update('configopts', '-DTPL_ENABLE_%s:BOOL=ON' % dep) + libdirs = os.getenv('%s_LIB_DIR' % dep) + if self.toolchain.comp_family() == toolchain.GCC: #@UndefinedVariable + libdirs += ";%s/lib64" % get_software_root('GCC') + self.cfg.update('configopts', '-D%s_LIBRARY_DIRS="%s"' % (dep, libdirs)) + libs = os.getenv('%s_MT_STATIC_LIBS' % dep).split(',') + lib_names = ';'.join([lib_re.search(l).group(1) for l in libs]) + if self.toolchain.comp_family() == toolchain.GCC: #@UndefinedVariable + # explicitely specify static lib! + lib_names += ";libgfortran.a" + self.cfg.update('configopts', '-D%s_LIBRARY_NAMES="%s"' % (dep, lib_names)) + + # UMFPACK is part of SuiteSparse + suitesparse = get_software_root('SuiteSparse') + if suitesparse: + self.cfg.update('configopts', "-DTPL_ENABLE_UMFPACK:BOOL=ON") + incdirs, libdirs, libnames = [], [], [] + for lib in ["UMFPACK", "CHOLMOD", "COLAMD", "AMD"]: + incdirs.append(os.path.join(suitesparse, lib, "Include")) + libdirs.append(os.path.join(suitesparse, lib, "Lib")) + libnames.append(lib.lower()) + # add SuiteSparse config lib, it is in recent versions of suitesparse + libdirs.append(os.path.join(suitesparse, 'SuiteSparse_config')) + libnames.append('suitesparseconfig') + self.cfg.update('configopts', '-DUMFPACK_INCLUDE_DIRS:PATH="%s"' % ';'.join(incdirs)) + self.cfg.update('configopts', '-DUMFPACK_LIBRARY_DIRS:PATH="%s"' % ';'.join(libdirs)) + self.cfg.update('configopts', '-DUMFPACK_LIBRARY_NAMES:STRING="%s"' % ';'.join(libnames)) + + # BLACS + if get_software_root('BLACS'): + self.cfg.update('configopts', "-DTPL_ENABLE_BLACS:BOOL=ON") + self.cfg.update('configopts', '-DBLACS_INCLUDE_DIRS:PATH="%s"' % os.getenv('BLACS_INC_DIR')) + self.cfg.update('configopts', '-DBLACS_LIBRARY_DIRS:PATH="%s"' % os.getenv('BLACS_LIB_DIR')) + blacs_lib_names = os.getenv('BLACS_STATIC_LIBS').split(',') + blacs_lib_names = [lib_re.search(x).group(1) for x in blacs_lib_names] + self.cfg.update('configopts', '-DBLACS_LIBRARY_NAMES:STRING="%s"' % (';'.join(blacs_lib_names))) + + # ScaLAPACK + if get_software_root('ScaLAPACK'): + self.cfg.update('configopts', "-DTPL_ENABLE_SCALAPACK:BOOL=ON") + self.cfg.update('configopts', '-DSCALAPACK_INCLUDE_DIRS:PATH="%s"' % os.getenv('SCALAPACK_INC_DIR')) + self.cfg.update('configopts', '-DSCALAPACK_LIBRARY_DIRS:PATH="%s;%s"' % (os.getenv('SCALAPACK_LIB_DIR'), + os.getenv('BLACS_LIB_DIR'))) + # PETSc + petsc = get_software_root('PETSc') + if petsc: + self.cfg.update('configopts', "-DTPL_ENABLE_PETSC:BOOL=ON") + incdirs = [os.path.join(petsc, "include")] + self.cfg.update('configopts', '-DPETSC_INCLUDE_DIRS:PATH="%s"' % ';'.join(incdirs)) + petsc_libdirs = [ + os.path.join(petsc, "lib"), + os.path.join(suitesparse, "UMFPACK", "Lib"), + os.path.join(suitesparse, "CHOLMOD", "Lib"), + os.path.join(suitesparse, "COLAMD", "Lib"), + os.path.join(suitesparse, "AMD", "Lib"), + os.getenv('FFTW_LIB_DIR'), + os.path.join(get_software_root('ParMETIS'), "Lib") + ] + self.cfg.update('configopts', '-DPETSC_LIBRARY_DIRS:PATH="%s"' % ';'.join(petsc_libdirs)) + petsc_libnames = ["petsc", "umfpack", "cholmod", "colamd", "amd", "parmetis", "metis"] + petsc_libnames += [lib_re.search(x).group(1) for x in os.getenv('FFTW_STATIC_LIBS').split(',')] + self.cfg.update('configopts', '-DPETSC_LIBRARY_NAMES:STRING="%s"' % ';'.join(petsc_libnames)) + + # other Third-Party Libraries (TPLs) + deps = self.cfg.dependencies() + builddeps = self.cfg.builddependencies() + ["SuiteSparse"] + deps = [dep['name'] for dep in deps if not dep['name'] in builddeps] + for dep in deps: + deproot = get_software_root(dep) + if deproot: + depmap = { + 'SCOTCH': 'Scotch', + } + dep = depmap.get(dep, dep) + self.cfg.update('configopts', "-DTPL_ENABLE_%s:BOOL=ON" % dep) + incdir = os.path.join(deproot, "include") + self.cfg.update('configopts', '-D%s_INCLUDE_DIRS:PATH="%s"' % (dep, incdir)) + libdir = os.path.join(deproot, "lib") + self.cfg.update('configopts', '-D%s_LIBRARY_DIRS:PATH="%s"' % (dep, libdir)) + + # extensions_step + if self.cfg['all_exts']: + self.cfg.update('configopts', "-DTrilinos_ENABLE_ALL_PACKAGES:BOOL=ON") + + else: + for ext in self.cfg['exts_list']: + self.cfg.update('configopts', "-DTrilinos_ENABLE_%s=ON" % ext) + + # packages to skip + skip_exts = self.cfg['skip_exts'] + if skip_exts: + for ext in skip_exts: + self.cfg.update('configopts', "-DTrilinos_ENABLE_%s:BOOL=OFF" % ext) + + # building in source dir not supported + try: + build_dir = "BUILD" + os.mkdir(build_dir) + os.chdir(build_dir) + except OSError, err: + raise EasyBuildError("Failed to create and move into build directory: %s", err) + + # configure using cmake + super(EB_Trilinos, self).configure_step(srcdir="..") + + def build_step(self): + """Build with make (verbose logging enabled).""" + super(EB_Trilinos, self).build_step(verbose=True) + + def sanity_check_step(self): + """Custom sanity check for Trilinos.""" + + # selection of libraries + libs = ["Amesos", "Anasazi", "AztecOO", "Belos", "Epetra", "Galeri", + "GlobiPack", "Ifpack", "Intrepid", "Isorropia", "Kokkos", + "Komplex", "LOCA", "Mesquite", "ML", "Moertel", "MOOCHO", "NOX", + "Pamgen", "RTOp", "Rythmos", "Sacado", "Shards", "Stratimikos", + "Teuchos", "Tpetra", "Triutils", "Zoltan"] + + libs = [l for l in libs if not l in self.cfg['skip_exts']] + + # Teuchos was refactored in 11.2 + if LooseVersion(self.version) >= LooseVersion('11.2') and 'Teuchos' in libs: + libs.remove('Teuchos') + libs.extend(['teuchoscomm', 'teuchoscore', 'teuchosnumerics', 'teuchosparameterlist', 'teuchosremainder']) + + # Kokkos was refactored in 12.x, check for libkokkoscore.a rather than libkokkos.a + if LooseVersion(self.version) >= LooseVersion('12') and 'Kokkos' in libs: + libs.remove('Kokkos') + libs.append('kokkoscore') + + if LooseVersion(self.version) >= LooseVersion('12.10') and 'Galeri' in libs: + libs.remove('Galeri') + libs.append('galeri-epetra') + libs.append('galeri-xpetra') + + custom_paths = { + 'files': [os.path.join('lib', 'lib%s.a' % x.lower()) for x in libs], + 'dirs': ['bin', 'include'] + } + + super(EB_Trilinos, self).sanity_check_step(custom_paths=custom_paths)