def normalize_suite_dir()

in lib/ramble/spack/build_systems/intel.py [0:0]


    def normalize_suite_dir(self, suite_dir_name, version_globs=['*.*.*']):
        '''Returns the version-specific and absolute path to the directory of
        an Intel product or a suite of product components.

        Parameters:

            suite_dir_name (str):
                Name of the product directory, without numeric version.

                - Examples::

                    composer_xe, parallel_studio_xe, compilers_and_libraries

                The following will work as well, even though they are not
                directly targets for Spack installation::

                    advisor_xe, inspector_xe, vtune_amplifier_xe,
                    performance_snapshots (new name for vtune as of 2018)

                These are single-component products without subordinate
                components and are normally made available to users by a
                toplevel psxevars.sh or equivalent file to source (and thus by
                the modulefiles that Spack produces).

            version_globs (list): Suffix glob patterns (most specific
                first) expected to qualify suite_dir_name to its fully
                version-specific install directory (as opposed to a
                compatibility directory or symlink).
        '''
        # See ./README-intel.rst for background and analysis of dir layouts.

        d = self.prefix

        # Distinguish between product installations that were done external to
        # Spack (integrated via packages.yaml) and Spack-internal ones. The
        # resulting prefixes may differ in directory depth and specificity.
        unversioned_dirname = ''
        if suite_dir_name and suite_dir_name in d:
            # If e.g. MKL was installed outside of Spack, it is likely just one
            # product or product component among possibly many other Intel
            # products and their releases that were installed in sibling or
            # cousin directories.  In such cases, the prefix given to Spack
            # will inevitably be a highly product-specific and preferably fully
            # version-specific directory.  This is what we want and need, and
            # nothing more specific than that, i.e., if needed, convert, e.g.:
            #   .../compilers_and_libraries*/* -> .../compilers_and_libraries*
            d = re.sub('(%s%s.*?)%s.*' %
                       (os.sep, re.escape(suite_dir_name), os.sep), r'\1', d)

            # The Intel installer scripts try hard to place compatibility links
            # named like this in the install dir to convey upgrade benefits to
            # traditional client apps. But such a generic name can be trouble
            # when given to Spack: the link target is bound to change outside
            # of Spack's purview and when it does, the outcome of subsequent
            # builds of dependent packages may be affected. (Though Intel has
            # been remarkably good at backward compatibility.)
            # I'm not sure if Spack's package hashing includes link targets.
            if d.endswith(suite_dir_name):
                # NB: This could get tiresome without a seen++ test.
                # tty.warn('Intel product found in a version-neutral directory'
                #          ' - future builds may not be reproducible.')
                #
                # Simply doing realpath() would not be enough, because:
                #   compilers_and_libraries -> compilers_and_libraries_2018
                # which is mostly a staging directory for symlinks (see next).
                unversioned_dirname = d
        else:
            # By contrast, a Spack-internal MKL installation will inherit its
            # prefix from install.sh of Intel's package distribution, where it
            # means the high-level installation directory that is specific to
            # the *vendor* (think of the default "/opt/intel"). We must now
            # step down into the *product* directory to get the usual
            # hierarchy. But let's not do that in haste ...
            #
            # For a Spack-born install, the fully-qualified release directory
            # desired above may seem less important since product upgrades
            # won't land in the same parent. However, only the fully qualified
            # directory contains the regular files for the compiler commands:
            #
            # $ ls -lF <HASH>/compilers_and_libraries*/linux/bin/intel64/icc
            #
            # <HASH>/compilers_and_libraries_2018.1.163/linux/bin/intel64/icc*
            #   A regular file in the actual release directory. Bingo!
            #
            # <HASH>/compilers_and_libraries_2018/linux/bin/intel64/icc -> ...
            #   A symlink - no good. Note that "compilers_and_libraries_2018/"
            #   is itself a directory (not symlink) but it merely holds a
            #   compatibility dir hierarchy with lots of symlinks into the
            #   release dir.
            #
            # <HASH>/compilers_and_libraries/linux/bin/intel64/icc -> ...
            #   Ditto.
            #
            #  Now, the Spack packages for MKL and MPI packges use version
            #  triplets, but the one for intel-parallel-studio does not.
            #  So, we can't have it quite as easy as:
            # d = Prefix(d.append('compilers_and_libraries_' + self.version))
            #  Alright, let's see what we can find instead:
            unversioned_dirname = os.path.join(d, suite_dir_name)

        if unversioned_dirname:
            for g in version_globs:
                try_glob = unversioned_dirname + g
                debug_print('trying %s' % try_glob)

                matching_dirs = sorted(glob.glob(try_glob))
                # NB: Python glob() returns results in arbitrary order - ugh!
                # NB2: sorted() is a shortcut that is NOT number-aware.

                if matching_dirs:
                    debug_print('found %d:' % len(matching_dirs),
                                matching_dirs)
                    # Take the highest and thus presumably newest match, which
                    # better be the sole one anyway.
                    d = matching_dirs[-1]
                    break

            if not matching_dirs:
                # No match -- return a sensible value anyway.
                d = unversioned_dirname

        debug_print(d)
        return Prefix(d)