##
# Copyright 2009-2020 Ghent University
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for building and installing Siesta, implemented as an easyblock
@author: Miguel Dias Costa (National University of Singapore)
@author: Ake Sandgren (Umea University)
"""
import os
import stat

import easybuild.tools.toolchain as toolchain
from distutils.version import LooseVersion
from easybuild.easyblocks.generic.configuremake import ConfigureMake
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.filetools import adjust_permissions, apply_regex_substitutions
from easybuild.tools.filetools import change_dir, copy_dir, copy_file, mkdir, write_file
from easybuild.tools.filetools import expand_glob_paths
from easybuild.tools.modules import get_software_root, get_software_version
from easybuild.tools.run import run_cmd
from easybuild.tools.systemtools import get_shared_lib_ext


PKGCONF_TEXT = """prefix={prefix}
libdir=${{prefix}}/lib
incdir=${{prefix}}/include

Name: Siesta
Description: libsiesta lets you easily link SiestaAsASubroutine functionality.
Version: {version}
Libs: -L${{libdir}} -lsiesta
Requires.private: {libnames}
Cflags: -I${{incdir}}/Siesta/modules
"""
# Possibly needed: libs.private (eg -lnetcdf) and cflags (includes) and fcflags (modules)
# Elpa:
# Cflags: -I${includedir}/elpa-2020.05.001 
# fcflags= -I${includedir}/elpa-2020.05.001/modules


class EB_Siesta(ConfigureMake):
    """
    Support for building/installing Siesta.
    - avoid parallel build for older versions
    """

    @staticmethod
    def extra_options(extra_vars=None):
        """Define extra options for Siesta"""
        extra = {
            'with_libsiesta': [None, "Install the static libsiesta.a (v>4.1)", CUSTOM],
            'with_transiesta': [None, "Install transiesta (v<4.1)", CUSTOM],
            'with_utils': [True, "Install all utils", CUSTOM],
            'with_utils_names': [
                None, "Install list of utils by dir name under Utils/. (overrides with_utils)", CUSTOM
            ],
        }
        return ConfigureMake.extra_options(extra_vars=extra)

    def configure_step(self):
        """
        Custom configure and build procedure for Siesta.
        - There are two main builds to do, siesta and transiesta
        - In addition there are multiple support tools to build
        """

        start_dir = self.cfg['start_dir']
        self.obj_dir = os.path.join(start_dir, 'Obj')
        arch_make = os.path.join(self.obj_dir, 'arch.make')
        self.bindir = os.path.join(start_dir, 'bin')

        self.pkg_conf_requires = []
        self.pkg_conf_libs = []

        loose_ver = LooseVersion(self.version)

        # Option defaults depending on version
        if self.cfg['with_transiesta'] is None:
            self.cfg['with_transiesta'] = loose_ver <= LooseVersion('4.1-b4')

        if self.cfg['with_libsiesta'] is None:
            self.cfg['with_libsiesta'] = loose_ver >= LooseVersion('4.2')

        # Features depending on version and options
        self.jpar = ""
        if loose_ver >= LooseVersion('4.1'):
            self.jpar = "-j {}".format(self.cfg['parallel'])

        if self.cfg['with_transiesta'] and loose_ver >= LooseVersion('4.1-rc2'):
            # Error out if the user has specified options wrong
            raise EasyBuildError(
                "You cannot use `with_transiesta` for newer versions of Siesta."
                " Transiesta is always built-in to Siesta."
            )
        elif self.cfg['with_transiesta'] and loose_ver >= LooseVersion('4.1-b3'):
            # Although for compatibility with older easyconfigs,
            # we may need to silently alter the user's whishes
            self.cfg['with_transiesta'] = False
    
        if self.cfg['with_libsiesta'] and loose_ver <= LooseVersion('4.1'):
            raise EasyBuildError(
                "libsiesta is an addition in an upcoming version after 4.1."
            )

        # enable OpenMP support if desired
        env_var_suff = ''
        if self.toolchain.options.get('openmp', None):
            env_var_suff = '_MT'

        # Other libraries
        scalapack = os.environ['LIBSCALAPACK' + env_var_suff]
        blacs = os.environ['LIBSCALAPACK' + env_var_suff]
        lapack = os.environ['LIBLAPACK' + env_var_suff]
        blas = os.environ['LIBBLAS' + env_var_suff]
        if get_software_root('imkl') or get_software_root('FFTW'):
            fftw = os.environ['LIBFFT' + env_var_suff]
        else:
            fftw = None

        regex_newlines = []
        regex_subs = [
            ('dc_lapack.a', ''),
            (r'^NETCDF_INTERFACE\s*=.*$', ''),
            ('libsiestaBLAS.a', ''),
            ('libsiestaLAPACK.a', ''),
            # Needed here to allow 4.1-b1 to be built with openmp
            (r"^(LDFLAGS\s*=).*$", r"\1 %s %s" % (os.environ['FCFLAGS'], os.environ['LDFLAGS'])),
        ]
        # Be really sure we are using -fPIC in case of libsiesta.a:
        if self.cfg['with_libsiesta']:
            regex_subs.append((r"^(FPPFLAGS\s*:?=.*)$", r"\1 -fPIC"))
            regex_newlines.append((r"^(FPPFLAGS\s*:?=.*)$", r"\1\nCFLAGS+= -fPIC"))

        netcdff_loc = get_software_root('netCDF-Fortran')
        if netcdff_loc:
            # Needed for gfortran at least
            regex_newlines.append((r"^(ARFLAGS_EXTRA\s*=.*)$", r"\1\nNETCDF_INCFLAGS = -I%s/include" % netcdff_loc))

        if fftw:
            fft_inc, fft_lib = os.environ['FFT_INC_DIR'], os.environ['FFT_LIB_DIR']
            fppflags = r"\1\nFFTW_INCFLAGS = -I%s\nFFTW_LIBS = -L%s %s" % (fft_inc, fft_lib, fftw)
            regex_newlines.append((r'(FPPFLAGS\s*:?=.*)$', fppflags))

        # Make a temp installdir during the build of the various parts
        mkdir(self.bindir)

        # change to actual build dir
        change_dir(self.obj_dir)

        # Populate start_dir with makefiles
        run_cmd(os.path.join(start_dir, 'Src', 'obj_setup.sh'), log_all=True, simple=True, log_output=True)

        if loose_ver < LooseVersion('4.1-b2'):
            # MPI?
            if self.toolchain.options.get('usempi', None):
                self.cfg.update('configopts', '--enable-mpi')

            # BLAS and LAPACK
            self.cfg.update('configopts', '--with-blas="%s"' % blas)
            self.cfg.update('configopts', '--with-lapack="%s"' % lapack)

            # ScaLAPACK (and BLACS)
            self.cfg.update('configopts', '--with-scalapack="%s"' % scalapack)
            self.cfg.update('configopts', '--with-blacs="%s"' % blacs)

            # NetCDF-Fortran
            if netcdff_loc:
                self.cfg.update('configopts', '--with-netcdf=-lnetcdff')

            # Configure is run in self.obj_dir, configure script is in ../Src
            super(EB_Siesta, self).configure_step(cmd_prefix='../Src/')

            regex_subs_Makefile = [
                (r'CFLAGS\)-c', r'CFLAGS) -c'),
            ]
            apply_regex_substitutions('Makefile', regex_subs_Makefile)

        else:  # there's no configure on newer versions

            if self.toolchain.comp_family() in [toolchain.INTELCOMP]:
                copy_file(os.path.join(self.obj_dir, 'intel.make'), arch_make)
            elif self.toolchain.comp_family() in [toolchain.GCC]:
                copy_file(os.path.join(self.obj_dir, 'gfortran.make'), arch_make)
            else:
                raise EasyBuildError("There is currently no support for compiler: %s", self.toolchain.comp_family())

            regex_subs.append((r"^(FPPFLAGS\s*:?=.*)$", r"\1 -DF2003"))

            if self.toolchain.options.get('usempi', None):
                regex_subs.extend([
                    (r"^(CC\s*=\s*).*$", r"\1%s" % os.environ['MPICC']),
                    (r"^(FC\s*=\s*).*$", r"\1%s" % os.environ['MPIF90']),
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -DMPI"),
                ])
                regex_newlines.append((r"^(FPPFLAGS\s*:?=.*)$", r"\1\nMPI_INTERFACE = libmpi_f90.a\nMPI_INCLUDE = ."))
                complibs = scalapack
            else:
                complibs = lapack

            regex_subs.extend([
                (r"^(LIBS\s*=).*$", r"\1 %s" % complibs),
                # Needed for a couple of the utils
                (r"^(FFLAGS\s*=\s*).*$", r"\1 -fPIC %s" % os.environ['FCFLAGS']),
            ])
            regex_newlines.append((r"^(COMP_LIBS\s*=.*)$", r"\1\nWXML = libwxml.a"))

            if netcdff_loc:
                regex_subs.extend([
                    (r"^(LIBS\s*=.*)$", r"\1 $(NETCDF_LIBS)"),
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -DCDF -DNCDF -DNCDF_4 -DNCDF_PARALLEL $(NETCDF_INCLUDE)"),
                    (r"^(COMP_LIBS\s*=.*)$", r"\1 libncdf.a libfdict.a"),
                ])
                netcdf_lib_and_inc = "NETCDF_LIBS = -lnetcdff\nNETCDF_INCLUDE = -I%s/include" % netcdff_loc
                netcdf_lib_and_inc += "\nINCFLAGS = $(NETCDF_INCLUDE)"
                regex_newlines.append((r"^(COMP_LIBS\s*=.*)$", r"\1\n%s" % netcdf_lib_and_inc))
                self.pkg_conf_requires += ["netcdf-fortran"]

            xmlf90 = get_software_root('xmlf90')
            if xmlf90:
                regex_subs.append((r"^(XMLF90_ROOT\s*=).*$", r"\1%s" % xmlf90))
                self.pkg_conf_requires += ["xmlf90"]

            libpsml = get_software_root('libPSML')
            if libpsml:
                regex_subs.append((r"^(PSML_ROOT\s*=).*$.*", r"\1%s" % libpsml))
                self.pkg_conf_requires += ["libpsml"]

            libgridxc = get_software_root('libGridXC')
            if libgridxc:
                regex_subs.append((r"^(GRIDXC_ROOT\s*=).*$", r"\1%s" % libgridxc))
                self.pkg_conf_requires += ["libgridxc"]

            libxc = get_software_root('libxc')
            if libxc:
                regex_subs.append((r"^#(LIBXC_ROOT\s*=).*$", r"\1 %s" % libxc))
                self.pkg_conf_requires += ["libxc"]

            elpa = get_software_root('ELPA')
            if elpa:
                elpa_ver = get_software_version('ELPA')
                regex_subs.extend([
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -DSIESTA__ELPA"),
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -I%s/include/elpa-%s/modules" % (elpa, elpa_ver)),
                    (r"^(LIBS\s*=.*)$", r"\1 -L%s/lib -lelpa" % elpa),
                ])
                self.pkg_conf_requires += ["elpa-%s" % elpa_ver]

            elsi = get_software_root('ELSI')
            if elsi:
                if not os.path.isfile(os.path.join(elsi, 'lib', 'libelsi.%s' % get_shared_lib_ext())):
                    raise EasyBuildError("This easyblock requires ELSI shared libraries instead of static")

                regex_subs.extend([
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -DSIESTA__ELSI"),
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -I%s/include" % elsi),
                    (r"^(LIBS\s*=.*)$", r"\1 $(FFTW_LIBS) -L%s/lib -lelsi" % elsi),
                ])
                self.pkg_conf_requires += ["elsi"]

            metis = get_software_root('METIS')
            if metis:
                regex_subs.extend([
                    (r"^(FPPFLAGS\s*:?=.*)$", r"\1 -DSIESTA__METIS"),
                    (r"^(LIBS\s*=.*)$", r"\1 -L%s/lib -lmetis" % metis),
                ])
                self.pkg_conf_requires += ["metis"]

        apply_regex_substitutions(arch_make, regex_subs)

        # individually apply substitutions that add lines
        for regex_nl in regex_newlines:
            apply_regex_substitutions(arch_make, [regex_nl])

        allutils = self.cfg['with_utils']
        someutils = self.cfg['with_utils_names']
        self.expected_utils = []
        if allutils or someutils:
            # Make the utils
            change_dir(os.path.join(start_dir, 'Util'))

            # clean_all.sh might be missing executable bit...
            adjust_permissions('./clean_all.sh', stat.S_IXUSR, recursive=False, relative=True)
            run_cmd('./clean_all.sh', log_all=True, simple=True, log_output=True)

            if loose_ver >= LooseVersion('4.1'):
                regex_subs_TS = [
                    (r"^default:.*$", r""),
                    (r"^EXE\s*=.*$", r""),
                    (r"^(include\s*..ARCH_MAKE.*)$", r"EXE=tshs2tshs\ndefault: $(EXE)\n\1"),
                    (r"^(INCFLAGS.*)$", r"\1 -I%s" % self.obj_dir),
                ]

                makefile = os.path.join(start_dir, 'Util', 'TS', 'tshs2tshs', 'Makefile')
                apply_regex_substitutions(makefile, regex_subs_TS)

            # SUFFIX rules in wrong place
            regex_subs_suffix = [
                (r'^(\.SUFFIXES:.*)$', r''),
                (r'^(include\s*\$\(ARCH_MAKE\).*)$', r'\1\n.SUFFIXES:\n.SUFFIXES: .c .f .F .o .a .f90 .F90'),
            ]
            makefile = os.path.join(start_dir, 'Util', 'Sockets', 'Makefile')
            apply_regex_substitutions(makefile, regex_subs_suffix)
            makefile = os.path.join(start_dir, 'Util', 'SiestaSubroutine', 'SimpleTest', 'Src', 'Makefile')
            apply_regex_substitutions(makefile, regex_subs_suffix)

            regex_subs_UtilLDFLAGS = [
                (r'(\$\(FC\)\s*-o\s)', r'$(FC) %s %s -o ' % (os.environ['FCFLAGS'], os.environ['LDFLAGS'])),
            ]
            makefile = os.path.join(start_dir, 'Util', 'Optimizer', 'Makefile')
            apply_regex_substitutions(makefile, regex_subs_UtilLDFLAGS)
            makefile = os.path.join(start_dir, 'Util', 'JobList', 'Src', 'Makefile')
            apply_regex_substitutions(makefile, regex_subs_UtilLDFLAGS)

            # remove clean at the end of default target (!!)
            if loose_ver < LooseVersion('4.0.2') or loose_ver == LooseVersion('4.1-b3'):
                makefile = os.path.join(start_dir, 'Util', 'SiestaSubroutine', 'SimpleTest', 'Src', 'Makefile')
                apply_regex_substitutions(makefile, [(r"simple_mpi_parallel clean", r"simple_mpi_parallel")])
                makefile = os.path.join(start_dir, 'Util', 'SiestaSubroutine', 'ProtoNEB', 'Src', 'Makefile')
                apply_regex_substitutions(makefile, [(r"protoNEB clean", r"protoNEB")])

            # Now move all the built utils to the temp installdir
            expected_utils = [
                'CMLComp/ccViz',
                'Contrib/APostnikov/eig2bxsf', 'Contrib/APostnikov/fmpdos',
                'Contrib/APostnikov/md2axsf', 'Contrib/APostnikov/rho2xsf',
                'Contrib/APostnikov/vib2xsf', 'Contrib/APostnikov/xv2xsf',
                'COOP/fat', 'COOP/mprop',
                'Denchar/Src/denchar',
                'DensityMatrix/cdf2dm', 'DensityMatrix/dm2cdf',
                'Eig2DOS/Eig2DOS',
                'Gen-basis/gen-basis', 'Gen-basis/ioncat',
                'Gen-basis/ionplot.sh',
                'Grid/cdf2grid', 'Grid/cdf2xsf', 'Grid/cdf_laplacian',
                'Grid/g2c_ng', 'Grid/grid2cdf', 'Grid/grid2cube',
                'Grid/grid2val', 'Grid/grid_rotate',
                'Helpers/get_chem_labels',
                'HSX/hs2hsx', 'HSX/hsx2hs',
                'JobList/Src/countJobs', 'JobList/Src/getResults',
                'JobList/Src/horizontal', 'JobList/Src/runJobs',
                'Macroave/Src/macroave',
                'ON/lwf2cdf',
                'Optimizer/simplex', 'Optimizer/swarm',
                'pdosxml/pdosxml',
                'Projections/orbmol_proj',
                'SiestaSubroutine/FmixMD/Src/driver',
                'SiestaSubroutine/FmixMD/Src/para',
                'SiestaSubroutine/FmixMD/Src/simple',
                'STM/ol-stm/Src/stm', 'STM/simple-stm/plstm',
                'Vibra/Src/fcbuild', 'Vibra/Src/vibra',
                'WFS/readwf', 'WFS/readwfx', 'WFS/wfs2wfsx',
                'WFS/wfsnc2wfsx', 'WFS/wfsx2wfs',
            ]

            # skip broken utils in 4.1-MaX-1.0 release, hopefully will be fixed later
            if self.version != '4.1-MaX-1.0':
                expected_utils.extend([
                    'VCA/fractional', 'VCA/mixps',
                ])

            expected_utils.extend([
                'Bands/eigfat2plot',
            ])

            if self.version != '4.1-MaX-1.0':
                expected_utils.extend([
                    'SiestaSubroutine/ProtoNEB/Src/protoNEB',
                    'SiestaSubroutine/SimpleTest/Src/simple_pipes_parallel',
                    'SiestaSubroutine/SimpleTest/Src/simple_pipes_serial',
                    'SiestaSubroutine/SimpleTest/Src/simple_sockets_parallel',
                    'SiestaSubroutine/SimpleTest/Src/simple_sockets_serial',
                ])
            expected_utils.extend([
                'Sockets/f2fmaster', 'Sockets/f2fslave',
            ])
            if self.toolchain.options.get('usempi', None):
                if self.version != '4.1-MaX-1.0':
                    expected_utils.extend([
                        'SiestaSubroutine/SimpleTest/Src/simple_mpi_parallel',
                        'SiestaSubroutine/SimpleTest/Src/simple_mpi_serial',
                    ])

            if loose_ver < LooseVersion('4.1'):
                expected_utils.append('WFS/info_wfsx')
                expected_utils.extend([
                    'COOP/dm_creator',
                    'TBTrans_rep/tbtrans',
                ])

            if loose_ver < LooseVersion('4.0.2'):
                expected_utils.extend([
                    'Bands/new.gnubands',
                ])
            else:
                expected_utils.extend([
                    'Bands/gnubands',
                ])
                # Need to revisit this when 4.1 is officialy released.
                # This is based on b1-b3 releases
                if loose_ver < LooseVersion('4.1'):
                    expected_utils.extend([
                        'Contour/grid1d', 'Contour/grid2d',
                        'Optical/optical', 'Optical/optical_input',
                        'sies2arc/sies2arc',
                    ])

            if loose_ver >= LooseVersion('4.1'):
                expected_utils.extend([
                    'DensityMatrix/dmbs2dm', 'DensityMatrix/dmUnblock',
                    'Grimme/fdf2grimme',
                    'SpPivot/pvtsp',
                    'TS/tselecs.sh',
                    'TS/ts2ts/ts2ts',
                    'TS/tbtrans', 'TS/phtrans'
                ])
                if self.version != '4.1-MaX-1.0':
                    expected_utils.extend([
                        'TS/tshs2tshs/tshs2tshs',
                    ])
            # Filter to selected utils
            if someutils:
                someutils_lower = set(util.lower() for util in someutils)
                expected_utils = filter(
                    lambda util: util.split("/")[0].lower() in someutils_lower,
                    expected_utils
                )
            self.expected_utils = expected_utils

    def build_step(self):
        """All the build steps of Siesta"""
        allutils = self.cfg['with_utils']
        someutils = self.cfg['with_utils_names']
        start_dir = self.cfg['start_dir']
        loose_ver = LooseVersion(self.version)

        # Main executable
        change_dir(self.obj_dir)
        run_cmd('make %s' % self.jpar, log_all=True, simple=True, log_output=True)
        copy_file(os.path.join(self.obj_dir, 'siesta'), self.bindir)

        # Utilities
        change_dir(os.path.join(start_dir, 'Util'))
        if allutils or someutils:
            # build_all.sh might be missing executable bit...
            adjust_permissions('./build_all.sh', stat.S_IXUSR, recursive=False, relative=True)
            run_cmd('./build_all.sh %s' % self.jpar, log_all=True, simple=True, log_output=True)

            # Rerun the tbtrans dir to get phtrans
            if loose_ver >= LooseVersion('4.1'):
                copy_file('TS/TBtrans/tbtrans', 'TS/tbtrans')
                change_dir(os.path.join(start_dir, 'Util', 'TS', 'TBtrans'))
                run_cmd('make clean', log_all=True, simple=True, log_output=True)
                run_cmd('make phtrans %s' % self.jpar, log_all=True, simple=True, log_output=True)
                change_dir(os.path.join(start_dir, 'Util'))
                copy_file('TS/TBtrans/phtrans', 'TS/phtrans')

            # Copy over utils to the temporary dir
            for util in self.expected_utils:
                copy_file(os.path.join(start_dir, 'Util', util), self.bindir)

        # Transiesta executable (older siestas)
        if self.cfg['with_transiesta']:
            change_dir(self.obj_dir)

            ts_clean_target = 'clean'
            if loose_ver >= LooseVersion('4.1-b4'):
                ts_clean_target += '-transiesta'

            run_cmd('make %s' % ts_clean_target, log_all=True, simple=True, log_output=True)
            run_cmd('make %s transiesta' % self.jpar, log_all=True, simple=True, log_output=True)

            copy_file(os.path.join(self.obj_dir, 'transiesta'), self.bindir)
        
    def test_step(self):
        """Custom test step for Siesta."""
        change_dir(os.path.join(self.cfg['start_dir'], 'Obj', 'Tests'))
        super(EB_Siesta, self).test_step()

    def install_step(self):
        """Custom install procedure for Siesta: copy binaries."""
        bindir = os.path.join(self.installdir, 'bin')
        copy_dir(os.path.join(self.cfg['start_dir'], 'bin'), bindir)
        if self.cfg['with_libsiesta']:
            libd = os.path.join(self.installdir, 'lib')
            pkgconfd = os.path.join(libd, 'pkgconfig')
            incdir = os.path.join(self.installdir, "include", "Siesta")
            moddir = os.path.join(incdir, 'modules')

            # Library
            copy_file(
                os.path.join(self.obj_dir, 'libsiesta.a'),
                os.path.join(libd, 'libsiesta.a')
            )
            # Modules
            mkdir(moddir, parents=True)
            modules = expand_glob_paths([os.path.join(self.obj_dir, '*.mod')])
            for module in modules:
                copy_file(module, os.path.join(moddir, os.path.basename(module)))
            # Pkgconf file
            mkdir(pkgconfd)
            write_file(
                os.path.join(pkgconfd, "Siesta.pc"),
                PKGCONF_TEXT.format(
                    prefix=self.installdir,
                    version=self.version,
                    libnames=" ".join(self.pkg_conf_requires),
                )
            )

    def sanity_check_step(self):
        """Custom sanity check for Siesta."""

        bins = ['bin/siesta']

        if self.cfg['with_transiesta']:
            bins.append('bin/transiesta')

        someutils = self.cfg['with_utils_names']
        allutils = (self.cfg['with_utils'] and someutils is None)
        if allutils or "Denchar" in someutils:
            bins.append('bin/denchar')
        if allutils or "TS" in someutils:
            bins += ["bin/tbtrans", "bin/phtrans"]

        if self.cfg['with_libsiesta']:
            bins.append('lib/libsiesta.a')

        custom_paths = {
            'files': bins,
            'dirs': [],
        }
        custom_commands = []
        if self.toolchain.options.get('usempi', None):
            # make sure Siesta was indeed built with support for running in parallel
            # The "cd to builddir" is required to not contaminate the install dir with cruft from running siesta
            mpi_test_cmd = "cd %s && " % self.builddir
            mpi_test_cmd = mpi_test_cmd + "echo 'SystemName test' | mpirun -np 2 siesta 2>/dev/null | grep PARALLEL"
            custom_commands.append(mpi_test_cmd)

        super(EB_Siesta, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)