def install_step(self):
        """Install python but only keep the bits we need"""
        super(EB_Tkinter, self).install_step()

        tmpdir = tempfile.mkdtemp(dir=self.builddir)

        self.tkinter_so_basename = self.get_tkinter_so_basename(False)
        if LooseVersion(self.version) >= LooseVersion('3'):
            tkparts = [
                "tkinter",
                os.path.join("lib-dynload", self.tkinter_so_basename)
            ]
        else:
            tkparts = [
                "lib-tk",
                os.path.join("lib-dynload", self.tkinter_so_basename)
            ]

        pylibdir = os.path.join(self.installdir, det_pylibdir())
        copy([os.path.join(os.path.dirname(pylibdir), x) for x in tkparts],
             tmpdir)

        remove_dir(self.installdir)

        move_file(os.path.join(tmpdir, tkparts[0]),
                  os.path.join(pylibdir, tkparts[0]))
        move_file(os.path.join(tmpdir, self.tkinter_so_basename),
                  os.path.join(pylibdir, self.tkinter_so_basename))
Пример #2
0
 def post_install_step(self):
     super(EB_AOMP, self).post_install_step()
     # The install script will create a symbolic link as the install
     # directory, this creates problems for EB as it won't remove the
     # symlink. To remedy this we remove the link here and rename the actual
     # install directory created by the AOMP install script
     if os.path.islink(self.installdir):
         remove_file(self.installdir)
     else:
         err_str = "Expected '{!s}' to be a symbolic link" \
                   " that needed to be removed, but it wasn't!"
         raise EasyBuildError(err_str.format(self.installdir))
     # Move the actual directory containing the install
     install_name = '{!s}_{!s}'.format(os.path.basename(self.installdir),
                                       self.version)
     actual_install = os.path.join(os.path.dirname(self.installdir),
                                   install_name)
     if os.path.exists(actual_install) and os.path.isdir(actual_install):
         move_file(actual_install, self.installdir)
     else:
         err_str = "Tried to move '{!s}' to '{!s}', " \
                   " but it either doesn't exist" \
                   " or isn't a directory!"
         raise EasyBuildError(
             err_str.format(actual_install, self.installdir))
Пример #3
0
    def install_step(self):
        """Custom install procedure for Nim."""

        run_cmd("./koch geninstall")
        run_cmd("sh install.sh %s" % self.installdir)

        # install.sh copies stuff into <prefix>/nim, so move it
        nim_dir = os.path.join(self.installdir, 'nim')
        for entry in os.listdir(nim_dir):
            move_file(os.path.join(nim_dir, entry), os.path.join(self.installdir, entry))

        # also copy nimble/nimgrep/nimsuggest tools
        for tool in ['nimble', 'nimgrep', 'nimsuggest']:
            copy_file(os.path.join('bin', tool), os.path.join(self.installdir, 'bin', tool))
Пример #4
0
    def install_step(self):
        """Custom install procedure for Nim."""

        run_cmd("./koch geninstall")
        run_cmd("sh install.sh %s" % self.installdir)

        # install.sh copies stuff into <prefix>/nim, so move it
        nim_dir = os.path.join(self.installdir, 'nim')
        for entry in os.listdir(nim_dir):
            move_file(os.path.join(nim_dir, entry),
                      os.path.join(self.installdir, entry))

        # also copy nimble/nimgrep/nimsuggest tools
        for tool in ['nimble', 'nimgrep', 'nimsuggest']:
            copy_file(os.path.join('bin', tool),
                      os.path.join(self.installdir, 'bin', tool))
Пример #5
0
    def post_install_step(self):
        """Create wrappers for the compilers to make sure compilers picks up GCCcore as GCC toolchain"""

        orig_compiler_tmpl = '%s.orig'

        def create_wrapper(wrapper_comp):
            """Create for a particular compiler, with a particular name"""
            wrapper_f = os.path.join(self.installdir, 'bin', wrapper_comp)
            write_file(
                wrapper_f, WRAPPER_TEMPLATE %
                {'compiler_name': orig_compiler_tmpl % wrapper_comp})
            perms = stat.S_IXUSR | stat.S_IRUSR | stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH
            adjust_permissions(wrapper_f, perms)

        compilers_to_wrap = [
            'clang',
            'clang++',
            'clang-%s' % LooseVersion(self.clangversion).version[0],
            'clang-cpp',
            'flang',
        ]

        # Rename original compilers and prepare wrappers to pick up GCCcore as GCC toolchain for the compilers
        for comp in compilers_to_wrap:
            actual_compiler = os.path.join(self.installdir, 'bin', comp)
            if os.path.isfile(actual_compiler):
                move_file(actual_compiler,
                          orig_compiler_tmpl % actual_compiler)
            else:
                err_str = "Tried to move '%s' to '%s', but it does not exist!"
                raise EasyBuildError(err_str, actual_compiler,
                                     '%s.orig' % actual_compiler)

            if not os.path.exists(actual_compiler):
                create_wrapper(comp)
                self.log.info("Wrapper for %s successfully created", comp)
            else:
                err_str = "Creating wrapper for '%s' not possible, since original compiler was not renamed!"
                raise EasyBuildError(err_str, actual_compiler)

        super(EB_AOCC, self).post_install_step()
Пример #6
0
    def install_step(self):
        """Install python but only keep the bits we need"""
        super(EB_Tkinter, self).install_step()

        tmpdir = tempfile.mkdtemp(dir=self.builddir)

        pylibdir = os.path.join(self.installdir,
                                os.path.dirname(det_pylibdir()))
        shlib_ext = get_shared_lib_ext()
        tkinter_so = os.path.join(pylibdir, 'lib-dynload',
                                  '_tkinter*.' + shlib_ext)
        tkinter_so_hits = glob.glob(tkinter_so)
        if len(tkinter_so_hits) != 1:
            raise EasyBuildError(
                "Expected to find exactly one _tkinter*.so: %s",
                tkinter_so_hits)
        self.tkinter_so_basename = os.path.basename(tkinter_so_hits[0])
        if LooseVersion(self.version) >= LooseVersion('3'):
            tkparts = [
                "tkinter",
                os.path.join("lib-dynload", self.tkinter_so_basename)
            ]
        else:
            tkparts = [
                "lib-tk",
                os.path.join("lib-dynload", self.tkinter_so_basename)
            ]

        copy([os.path.join(pylibdir, x) for x in tkparts], tmpdir)

        remove_dir(self.installdir)

        move_file(os.path.join(tmpdir, tkparts[0]),
                  os.path.join(pylibdir, tkparts[0]))
        tkinter_so = os.path.basename(tkparts[1])
        move_file(os.path.join(tmpdir, tkinter_so),
                  os.path.join(pylibdir, tkinter_so))
Пример #7
0
    def install_step(self):
        """Custom install step for netpbm."""
        # Preinstallation to a tmp directory. Can't install directly to installdir because the make command fails if the
        # directory already exists
        cmd = "make package pkgdir=%s/pkg" % self.builddir
        (out, _) = run_cmd(cmd, log_all=True, simple=False)

        # Move things to installdir
        copy(["%s/pkg/%s" % (self.builddir, x) for x in os.listdir("%s/pkg/" % self.builddir)], self.installdir)

        # Need to do manually the last bits of the installation
        configs = [
            ("%s/config_template" % self.installdir, "%s/bin/netpbm-config" % self.installdir),
            ("%s/pkgconfig_template" % self.installdir, "%s/lib/pkgconfig/netpbm.pc" % self.installdir)
        ]

        mkdir("%s/lib/pkgconfig" % self.installdir)
        for template, config_file in configs:
            move_file(template, config_file)
            for line in fileinput.input(config_file, inplace=1, backup='.orig'):
                if re.match(r"^@", line):
                    continue
                else:
                    line = re.sub(r'@VERSION@', 'Netpbm %s' % self.version, line)
                    line = re.sub(r'@DATADIR@', '%s/lib' % self.installdir, line)
                    line = re.sub(r'@LINKDIR@', '%s/lib' % self.installdir, line)
                    line = re.sub(r'@INCLUDEDIR@', '%s/include' % self.installdir, line)
                    line = re.sub(r'@BINDIR@', '%s/bin' % self.installdir, line)

                sys.stdout.write(line)

        adjust_permissions("%s/bin/netpbm-config" % self.installdir, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
        move_file("%s/link/libnetpbm.a" % self.installdir, "%s/lib/libnetpbm.a" % self.installdir)
        symlink("%s/lib/libnetpbm.so.11" % self.installdir, "%s/lib/libnetpbm.so" % self.installdir)
        for f in os.listdir("%s/misc/" % self.installdir):
            move_file("%s/misc/%s" % (self.installdir, f), "%s/lib/%s" % (self.installdir, f))
        rmtree2("%s/misc/" % self.installdir)
        rmtree2("%s/link/" % self.installdir)

        headers = os.listdir("%s/include/netpbm" % self.installdir)
        for header in headers:
            symlink("%s/include/netpbm/%s" % (self.installdir, header), "%s/include/%s" % (self.installdir, header))

        return out
Пример #8
0
    def post_install_step(self, *args, **kwargs):
        """
        Post-processing after installation: add symlinks for cc, c++, f77, f95
        """
        super(EB_GCC, self).post_install_step(*args, **kwargs)

        # Add symlinks for cc/c++/f77/f95.
        bindir = os.path.join(self.installdir, 'bin')
        for key in COMP_CMD_SYMLINKS:
            src = COMP_CMD_SYMLINKS[key]
            target = os.path.join(bindir, key)
            if os.path.exists(target):
                self.log.info(
                    "'%s' already exists in %s, not replacing it with symlink to '%s'",
                    key, bindir, src)
            elif os.path.exists(os.path.join(bindir, src)):
                symlink(src, target, use_abspath_source=False)
            else:
                raise EasyBuildError(
                    "Can't link '%s' to non-existing location %s", target,
                    os.path.join(bindir, src))

        # Rename include-fixed directory which includes system header files that were processed by fixincludes,
        # since these may cause problems when upgrading to newer OS version.
        # (see https://github.com/easybuilders/easybuild-easyconfigs/issues/10666)
        glob_pattern = os.path.join(self.installdir, 'lib*', 'gcc',
                                    '*-linux-gnu', self.version,
                                    'include-fixed')
        paths = glob.glob(glob_pattern)
        if paths:
            # weed out paths that point to the same location,
            # for example when 'lib64' is a symlink to 'lib'
            include_fixed_paths = []
            for path in paths:
                if not any(
                        os.path.samefile(path, x)
                        for x in include_fixed_paths):
                    include_fixed_paths.append(path)

            if len(include_fixed_paths) == 1:
                include_fixed_path = include_fixed_paths[0]

                msg = "Found include-fixed subdirectory at %s, "
                msg += "renaming it to avoid using system header files patched by fixincludes..."
                self.log.info(msg, include_fixed_path)

                # limits.h and syslimits.h need to be copied to include/ first,
                # these are strictly required (by /usr/include/limits.h for example)
                include_path = os.path.join(
                    os.path.dirname(include_fixed_path), 'include')
                retained_header_files = ['limits.h', 'syslimits.h']
                for fn in retained_header_files:
                    from_path = os.path.join(include_fixed_path, fn)
                    to_path = os.path.join(include_path, fn)
                    if os.path.exists(from_path):
                        if os.path.exists(to_path):
                            raise EasyBuildError(
                                "%s already exists, not overwriting it with %s!",
                                to_path, from_path)
                        else:
                            copy_file(from_path, to_path)
                            self.log.info("%s copied to %s before renaming %s",
                                          from_path, to_path,
                                          include_fixed_path)
                    else:
                        self.log.warning(
                            "Can't copy non-existing file %s to %s, since it doesn't exist!",
                            from_path, to_path)

                readme = os.path.join(include_fixed_path, 'README.easybuild')
                readme_txt = '\n'.join([
                    "This directory was renamed by EasyBuild to avoid that the header files in it are picked up,",
                    "since they may cause problems when the OS is upgraded to a new (minor) version.",
                    '',
                    "These files were copied to %s first: %s" %
                    (include_path, ', '.join(retained_header_files)),
                    '',
                    "See https://github.com/easybuilders/easybuild-easyconfigs/issues/10666 for more information.",
                    '',
                ])
                write_file(readme, readme_txt)

                include_fixed_renamed = include_fixed_path + '.renamed-by-easybuild'
                move_file(include_fixed_path, include_fixed_renamed)
                self.log.info(
                    "%s renamed to %s to avoid using the header files in it",
                    include_fixed_path, include_fixed_renamed)
            else:
                raise EasyBuildError(
                    "Exactly one 'include-fixed' directory expected, found %d: %s",
                    len(include_fixed_paths), include_fixed_paths)
        else:
            self.log.info("No include-fixed subdirectory found at %s",
                          glob_pattern)
Пример #9
0
    def configure_step(self):
        """Set up environment for building/installing CFDEMcoupling."""

        # rename top-level directory to CFDEMcoupling-<version>
        top_dirs = os.listdir(self.builddir)

        for (pkgname, target_dir) in [('CFDEMcoupling',
                                       self.cfdem_project_dir),
                                      ('LIGGGHTS', self.liggghts_dir)]:
            pkg_topdirs = [d for d in top_dirs if d.startswith(pkgname)]
            if len(pkg_topdirs) == 1:
                orig_dir = os.path.join(self.builddir, pkg_topdirs[0])
                move_file(orig_dir, target_dir)
            else:
                error_msg = "Failed to find subdirectory for %s in %s %s (missing sources for %s?)",
                raise EasyBuildError(error_msg, pkgname, self.builddir,
                                     top_dirs, pkgname)

        env.setvar('CFDEM_VERSION', self.version)
        env.setvar('CFDEM_PROJECT_DIR', self.cfdem_project_dir)

        # define $CFDEM_PROJECT_USER_DIR to an empty existing directory
        project_user_dir = os.path.join(self.builddir, 'project_user_dir')
        env.setvar('CFDEM_PROJECT_USER_DIR', project_user_dir)
        mkdir(project_user_dir, parents=True)

        cfdem_bashrc = os.path.join(self.cfdem_project_dir, 'src',
                                    'lagrangian', 'cfdemParticle', 'etc',
                                    'bashrc')
        env.setvar('CFDEM_bashrc', cfdem_bashrc)

        env.setvar('CFDEM_LIGGGHTS_SRC_DIR',
                   os.path.join(self.liggghts_dir, 'src'))
        env.setvar('CFDEM_LIGGGHTS_MAKEFILE_NAME', 'auto')

        lpp_dirs = glob.glob(os.path.join(self.builddir, 'LPP-*'))
        if len(lpp_dirs) == 1:
            env.setvar('CFDEM_LPP_DIR', lpp_dirs[0])
        else:
            raise EasyBuildError("Failed to isolate LPP-* directory in %s",
                                 self.builddir)

        # build in parallel
        env.setvar("WM_NCOMPPROCS", str(self.cfg['parallel']))

        vtk_root = get_software_root('VTK')
        if vtk_root:
            vtk_ver_maj_min = '.'.join(
                get_software_version('VTK').split('.')[:2])
            vtk_inc = os.path.join(vtk_root, 'include',
                                   'vtk-%s' % vtk_ver_maj_min)
            if os.path.exists(vtk_inc):
                env.setvar('VTK_INC_USR', '-I%s' % vtk_inc)
            else:
                raise EasyBuildError("Expected directory %s does not exist!",
                                     vtk_inc)

            vtk_lib = os.path.join(vtk_root, 'lib')
            if os.path.exists(vtk_lib):
                env.setvar('VTK_LIB_USR', '-L%s' % vtk_lib)
            else:
                raise EasyBuildError("Expected directory %s does not exist!",
                                     vtk_lib)
        else:
            raise EasyBuildError("VTK not included as dependency")

        # can't seem to use defined 'cfdemSysTest' alias, so call cfdemSystemTest.sh script directly...
        cmd = "source $CFDEM_bashrc && $CFDEM_SRC_DIR/lagrangian/cfdemParticle/etc/cfdemSystemTest.sh"
        run_cmd(cmd, log_all=True, simple=True, log_ok=True)
Пример #10
0
    def build_mkl_fftw_interfaces(self, libdir):
        """Build the Intel MKL FFTW interfaces."""

        mkdir(libdir)

        loosever = LooseVersion(self.version)

        if loosever >= LooseVersion('10.3'):
            intsubdir = os.path.join(self.mkl_basedir, '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']

        interfacedir = os.path.join(self.installdir, intsubdir)
        change_dir(interfacedir)
        self.log.info("Changed to interfaces directory %s", interfacedir)

        compopt = None
        # determine whether we're using a non-Intel GCC-based or PGI/NVHPC-based toolchain
        # can't use toolchain.comp_family, because of system toolchain used when installing imkl
        if get_software_root('icc') or get_software_root('intel-compilers'):
            compopt = 'compiler=intel'
        elif get_software_root('PGI'):
            compopt = 'compiler=pgi'
        elif get_software_root('NVHPC'):
            compopt = 'compiler=nvhpc'
        # GCC should be the last as the above compilers also have an underlying GCC
        elif get_software_root('GCC'):
            compopt = 'compiler=gnu'
        else:
            raise EasyBuildError("Not using Intel/GCC/PGI/NVHPC compilers, "
                                 "don't know how to build wrapper libs")

        # patch makefiles for cdft wrappers when PGI or NVHPC is used as compiler
        if get_software_root('NVHPC'):
            regex_subs = [
                # nvhpc should be considered as a valid compiler
                ("intel gnu", "intel gnu nvhpc"),
                # transform 'gnu' case to 'nvhpc' case
                (r"ifeq \(\$\(compiler\),gnu\)", "ifeq ($(compiler),nvhpc)"),
                ('=gcc', '=nvc'),
            ]
        if get_software_root('PGI'):
            regex_subs = [
                # pgi should be considered as a valid compiler
                ("intel gnu", "intel gnu pgi"),
                # transform 'gnu' case to 'pgi' case
                (r"ifeq \(\$\(compiler\),gnu\)", "ifeq ($(compiler),pgi)"),
                ('=gcc', '=pgcc'),
            ]
        if get_software_root('PGI') or get_software_root('NVHPC'):
            regex_subs += [
                # correct flag to use C99 standard
                ('-std=c99', '-c99'),
                # -Wall and -Werror are not valid options for pgcc, no close equivalent
                ('-Wall', ''),
                ('-Werror', ''),
            ]
            for lib in self.cdftlibs:
                apply_regex_substitutions(
                    os.path.join(interfacedir, lib, 'makefile'), regex_subs)

        if get_software_root('NVHPC'):
            regex_nvc_subs = [
                ('pgcc', 'nvc'),
                ('pgf95', 'nvfortran'),
                ('pgi', 'nvhpc'),
            ]
            for liball in glob.glob(os.path.join(interfacedir, '*',
                                                 'makefile')):
                apply_regex_substitutions(liball, regex_nvc_subs)

        for lib in fftw2libs + fftw3libs + self.cdftlibs:
            buildopts = [compopt]
            if lib in fftw3libs:
                buildopts.append('install_to=$INSTALL_DIR')
            elif lib in self.cdftlibs:
                if self.mpi_spec is not None:
                    buildopts.append('mpi=%s' % self.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 self.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)

                intdir = os.path.join(interfacedir, lib)
                change_dir(intdir)
                self.log.info("Changed to interface %s directory %s", lib,
                              intdir)

                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(libdir, fn)
                    if os.path.isfile(src):
                        move_file(src, dest)
                        self.log.info("Moved %s to %s", src, dest)

                remove_dir(tmpbuild)
Пример #11
0
    def install_step(self):
        """Custom install step, to add extra symlinks"""
        install_tbb_lib_path = os.path.join(self.installdir, 'tbb', 'lib')

        if self.toolchain.is_system_toolchain():
            silent_cfg_names_map = None
            silent_cfg_extras = None

            if LooseVersion(self.version) < LooseVersion('4.2'):
                silent_cfg_names_map = {
                    'activation_name': ACTIVATION_NAME_2012,
                    'license_file_name': LICENSE_FILE_NAME_2012,
                }

            elif LooseVersion(self.version) < LooseVersion('4.4'):
                silent_cfg_names_map = {
                    'install_mode_name': INSTALL_MODE_NAME_2015,
                    'install_mode': INSTALL_MODE_2015,
                }

            # In case of TBB 4.4.x and newer we have to specify ARCH_SELECTED in silent.cfg
            if LooseVersion(self.version) >= LooseVersion('4.4'):
                silent_cfg_extras = {'ARCH_SELECTED': self.arch.upper()}

            IntelBase.install_step(self,
                                   silent_cfg_names_map=silent_cfg_names_map,
                                   silent_cfg_extras=silent_cfg_extras)

            # determine libdir
            os.chdir(self.installdir)
            libpath = os.path.join('tbb', 'libs', 'intel64')
            if LooseVersion(self.version) < LooseVersion('4.1.0'):
                libglob = 'tbb/lib/intel64/cc*libc*_kernel*'
                libs = sorted(glob.glob(libglob), key=LooseVersion)
                if libs:
                    # take the last one, should be ordered by cc version
                    # we're only interested in the last bit
                    libdir = os.path.basename(libs[-1])
                else:
                    raise EasyBuildError("No libs found using %s in %s",
                                         libglob, self.installdir)
            else:
                libdir = get_tbb_gccprefix(libpath)

            libpath = os.path.join(libpath, libdir)
            # applications go looking into tbb/lib so we move what's in there to tbb/libs
            shutil.move(install_tbb_lib_path,
                        os.path.join(self.installdir, 'tbb', 'libs'))
            # And add a symlink of the library folder to tbb/lib
            symlink(os.path.join(self.installdir, libpath),
                    install_tbb_lib_path)
        else:
            # no custom install step when building from source (building is done in install directory)
            cand_lib_paths = glob.glob(
                os.path.join(self.installdir, 'build', '*_release'))
            if len(cand_lib_paths) == 1:
                libpath = os.path.join('build',
                                       os.path.basename(cand_lib_paths[0]))
            else:
                raise EasyBuildError(
                    "Failed to isolate location of libraries: %s",
                    cand_lib_paths)

        self.log.debug("libpath: %s" % libpath)
        # applications usually look into /lib, so we move the folder there and symlink the original one to it
        # This is also important so that /lib and /lib64 are actually on the same level
        root_lib_path = os.path.join(self.installdir, 'lib')
        move_file(libpath, root_lib_path)
        symlink(os.path.relpath(root_lib_path, os.path.join(libpath)),
                libpath,
                use_abspath_source=False)

        # Install CMake config files if possible
        if self._has_cmake() and LooseVersion(
                self.version) >= LooseVersion('2020.0'):
            cmake_install_dir = os.path.join(root_lib_path, 'cmake', 'TBB')
            cmd = [
                'cmake',
                '-DINSTALL_DIR=' + cmake_install_dir,
                '-DSYSTEM_NAME=Linux',
                '-P tbb_config_installer.cmake',
            ]
            run_cmd(' '.join(cmd), path=os.path.join(self.builddir, 'cmake'))