Пример #1
0
    def _std_args(pkg):
        """Computes the standard cmake arguments for a generic package"""
        try:
            generator = pkg.generator
        except AttributeError:
            generator = 'Unix Makefiles'

        # Make sure a valid generator was chosen
        valid_primary_generators = ['Unix Makefiles', 'Ninja']
        primary_generator = _extract_primary_generator(generator)
        if primary_generator not in valid_primary_generators:
            msg  = "Invalid CMake generator: '{0}'\n".format(generator)
            msg += "CMakePackage currently supports the following "
            msg += "primary generators: '{0}'".\
                   format("', '".join(valid_primary_generators))
            raise InstallError(msg)

        try:
            build_type = pkg.spec.variants['build_type'].value
        except KeyError:
            build_type = 'RelWithDebInfo'

        try:
            ipo = pkg.spec.variants['ipo'].value
        except KeyError:
            ipo = False

        define = CMakePackage.define
        args = [
            '-G', generator,
            define('CMAKE_INSTALL_PREFIX', pkg.prefix),
            define('CMAKE_BUILD_TYPE', build_type),
        ]

        # CMAKE_INTERPROCEDURAL_OPTIMIZATION only exists for CMake >= 3.9
        if pkg.spec.satisfies('^[email protected]:'):
            args.append(define('CMAKE_INTERPROCEDURAL_OPTIMIZATION', ipo))

        if primary_generator == 'Unix Makefiles':
            args.append(define('CMAKE_VERBOSE_MAKEFILE', True))

        if platform.mac_ver()[0]:
            args.extend([
                define('CMAKE_FIND_FRAMEWORK', "LAST"),
                define('CMAKE_FIND_APPBUNDLE', "LAST"),
            ])

        # Set up CMake rpath
        args.extend([
            define('CMAKE_INSTALL_RPATH_USE_LINK_PATH', False),
            define('CMAKE_INSTALL_RPATH',
                   spack.build_environment.get_rpaths(pkg)),
        ])
        # CMake's find_package() looks in CMAKE_PREFIX_PATH first, help CMake
        # to find immediate link dependencies in right places:
        deps = [d.prefix for d in
                pkg.spec.dependencies(deptype=('build', 'link'))]
        deps = filter_system_paths(deps)
        args.append(define('CMAKE_PREFIX_PATH', deps))
        return args
Пример #2
0
    def test_filter_system_paths(self):
        filtered = filter_system_paths([
            '/usr/local/Cellar/gcc/5.3.0/lib',
            '/usr/local/lib',
            '/usr/local/include',
            '/usr/local/lib64',
            '/usr/local/opt/some-package/lib',
            '/usr/opt/lib',
            '/lib',
            '/lib64',
            '/include',
            '/opt/some-package/include',
        ])
        self.assertEqual(filtered,
                         ['/usr/local/Cellar/gcc/5.3.0/lib',
                          '/usr/local/opt/some-package/lib',
                          '/usr/opt/lib',
                          '/opt/some-package/include'])

        filtered = filter_system_bin_paths([
            '/usr/local/Cellar/gcc/5.3.0/bin',
            '/usr/local/bin',
            '/usr/local/opt/some-package/bin',
            '/usr/opt/bin',
            '/bin',
            '/opt/some-package/bin',
        ])
        self.assertEqual(filtered,
                         ['/usr/local/bin',
                          '/bin',
                          '/usr/local/Cellar/gcc/5.3.0/bin',
                          '/usr/local/opt/some-package/bin',
                          '/usr/opt/bin',
                          '/opt/some-package/bin'])
Пример #3
0
def get_cmake_prefix_path(pkg):
    build_deps = set(pkg.spec.dependencies(deptype=('build', 'test')))
    link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
    build_link_deps = build_deps | link_deps
    build_link_deps = _place_externals_last(build_link_deps)
    build_link_prefixes = filter_system_paths(x.prefix
                                              for x in build_link_deps)
    return build_link_prefixes
Пример #4
0
def test_filter_system_paths(miscellaneous_paths):
    """Tests that the filtering of system paths works as expected."""
    filtered = filter_system_paths(miscellaneous_paths)
    expected = [
        '/usr/local/Cellar/gcc/5.3.0/lib',
        '/usr/local/opt/some-package/lib',
        '/usr/opt/lib',
        '/opt/some-package/include',
        '/opt/some-package/local/..',
    ]
    assert filtered == expected
Пример #5
0
def test_filter_system_paths(miscellaneous_paths):
    """Tests that the filtering of system paths works as expected."""
    filtered = filter_system_paths(miscellaneous_paths)
    expected = [
        '/usr/local/Cellar/gcc/5.3.0/lib',
        '/usr/local/opt/some-package/lib',
        '/usr/opt/lib',
        '/opt/some-package/include',
        '/opt/some-package/local/..',
    ]
    assert filtered == expected
Пример #6
0
def get_rpaths(pkg):
    """Get a list of all the rpaths for a package."""
    rpaths = [pkg.prefix.lib, pkg.prefix.lib64]
    deps = get_rpath_deps(pkg)
    rpaths.extend(d.prefix.lib for d in deps if os.path.isdir(d.prefix.lib))
    rpaths.extend(d.prefix.lib64 for d in deps
                  if os.path.isdir(d.prefix.lib64))
    # Second module is our compiler mod name. We use that to get rpaths from
    # module show output.
    if pkg.compiler.modules and len(pkg.compiler.modules) > 1:
        rpaths.append(path_from_modules([pkg.compiler.modules[1]]))
    return list(dedupe(filter_system_paths(rpaths)))
Пример #7
0
    def _std_args(pkg):
        """Computes the standard cmake arguments for a generic package"""
        try:
            generator = pkg.generator
        except AttributeError:
            generator = 'Unix Makefiles'

        # Make sure a valid generator was chosen
        valid_primary_generators = ['Unix Makefiles', 'Ninja']
        primary_generator = _extract_primary_generator(generator)
        if primary_generator not in valid_primary_generators:
            msg = "Invalid CMake generator: '{0}'\n".format(generator)
            msg += "CMakePackage currently supports the following "
            msg += "primary generators: '{0}'".\
                   format("', '".join(valid_primary_generators))
            raise InstallError(msg)

        try:
            build_type = pkg.spec.variants['build_type'].value
        except KeyError:
            build_type = 'RelWithDebInfo'

        args = [
            '-G',
            generator,
            '-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix),
            '-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type),
        ]

        if primary_generator == 'Unix Makefiles':
            args.append('-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON')

        if platform.mac_ver()[0]:
            args.extend([
                '-DCMAKE_FIND_FRAMEWORK:STRING=LAST',
                '-DCMAKE_FIND_APPBUNDLE:STRING=LAST'
            ])

        # Set up CMake rpath
        args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE')
        rpaths = ';'.join(spack.build_environment.get_rpaths(pkg))
        args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths))
        # CMake's find_package() looks in CMAKE_PREFIX_PATH first, help CMake
        # to find immediate link dependencies in right places:
        deps = [
            d.prefix for d in pkg.spec.dependencies(deptype=('build', 'link'))
        ]
        deps = filter_system_paths(deps)
        args.append('-DCMAKE_PREFIX_PATH:STRING={0}'.format(';'.join(deps)))
        return args
Пример #8
0
    def setup_run_environment(self, env):
        if '+java' in self.spec:
            class_paths = find(self.prefix, '*.jar')
            classpath = os.pathsep.join(class_paths)
            env.prepend_path('CLASSPATH', classpath)

        # `spack test run gdal+python` requires these for the Python bindings
        # to find the correct libraries
        libs = []
        for dep in self.spec.dependencies(deptype='link'):
            query = self.spec[dep.name]
            libs.extend(filter_system_paths(query.libs.directories))
        if sys.platform == 'darwin':
            env.prepend_path('DYLD_FALLBACK_LIBRARY_PATH', ':'.join(libs))
        else:
            env.prepend_path('LD_LIBRARY_PATH', ':'.join(libs))
Пример #9
0
def _parse_non_system_link_dirs(string):
    """Parses link paths out of compiler debug output.

    Args:
        string (str): compiler debug output as a string

    Returns:
        (list of str): implicit link paths parsed from the compiler output
    """
    link_dirs = _parse_link_paths(string)

    # Return set of directories containing needed compiler libs, minus
    # system paths. Note that 'filter_system_paths' only checks for an
    # exact match, while 'in_system_subdirectory' checks if a path contains
    # a system directory as a subdirectory
    link_dirs = filter_system_paths(link_dirs)
    return list(p for p in link_dirs if not in_system_subdirectory(p))
Пример #10
0
    def _std_args(pkg):
        """Computes the standard cmake arguments for a generic package"""
        try:
            generator = pkg.generator
        except AttributeError:
            generator = 'Unix Makefiles'

        # Make sure a valid generator was chosen
        valid_generators = ['Unix Makefiles', 'Ninja']
        if generator not in valid_generators:
            msg  = "Invalid CMake generator: '{0}'\n".format(generator)
            msg += "CMakePackage currently supports the following "
            msg += "generators: '{0}'".format("', '".join(valid_generators))
            raise InstallError(msg)

        try:
            build_type = pkg.spec.variants['build_type'].value
        except KeyError:
            build_type = 'RelWithDebInfo'

        args = [
            '-G', generator,
            '-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix),
            '-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type),
            '-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'
        ]

        if platform.mac_ver()[0]:
            args.extend([
                '-DCMAKE_FIND_FRAMEWORK:STRING=LAST',
                '-DCMAKE_FIND_APPBUNDLE:STRING=LAST'
            ])

        # Set up CMake rpath
        args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE')
        rpaths = ';'.join(spack.build_environment.get_rpaths(pkg))
        args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths))
        # CMake's find_package() looks in CMAKE_PREFIX_PATH first, help CMake
        # to find immediate link dependencies in right places:
        deps = [d.prefix for d in
                pkg.spec.dependencies(deptype=('build', 'link'))]
        deps = filter_system_paths(deps)
        args.append('-DCMAKE_PREFIX_PATH:STRING={0}'.format(';'.join(deps)))
        return args
Пример #11
0
    def test_filter_system_paths(self):
        filtered = filter_system_paths([
            '/usr/local/Cellar/gcc/5.3.0/lib',
            '/usr/local/lib',
            '/usr/local',
            '/usr/local/include',
            '/usr/local/lib64',
            '/usr/local/opt/some-package/lib',
            '/usr/opt/lib',
            '/lib',
            '/',
            '/usr',
            '/lib64',
            '/include',
            '/opt/some-package/include',
        ])
        self.assertEqual(filtered,
                         ['/usr/local/Cellar/gcc/5.3.0/lib',
                          '/usr/local/opt/some-package/lib',
                          '/usr/opt/lib',
                          '/opt/some-package/include'])

        filtered = filter_system_bin_paths([
            '/usr/local/Cellar/gcc/5.3.0/bin',
            '/usr/local/bin',
            '/usr/local/opt/some-package/bin',
            '/usr/opt/bin',
            '/bin',
            '/opt/some-package/bin',
        ])
        self.assertEqual(filtered,
                         ['/usr/local/bin',
                          '/bin',
                          '/usr/local/Cellar/gcc/5.3.0/bin',
                          '/usr/local/opt/some-package/bin',
                          '/usr/opt/bin',
                          '/opt/some-package/bin'])
Пример #12
0
def test_filter_system_paths():
    expected = [p for p in test_paths if p.startswith('/nonsense_path')]
    filtered = envutil.filter_system_paths(test_paths)
    assert(expected == filtered)
Пример #13
0
def set_build_environment_variables(pkg, env, dirty):
    """Ensure a clean install environment when we build packages.

    This involves unsetting pesky environment variables that may
    affect the build. It also involves setting environment variables
    used by Spack's compiler wrappers.

    Args:
        pkg: The package we are building
        env: The build environment
        dirty (bool): Skip unsetting the user's environment settings
    """
    # Gather information about various types of dependencies
    build_deps = set(pkg.spec.dependencies(deptype=('build', 'test')))
    link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
    build_link_deps = build_deps | link_deps
    rpath_deps = get_rpath_deps(pkg)

    link_dirs = []
    include_dirs = []
    rpath_dirs = []

    # The top-level package is always RPATHed. It hasn't been installed yet
    # so the RPATHs are added unconditionally (e.g. even though lib64/ may
    # not be created for the install).
    for libdir in ['lib', 'lib64']:
        lib_path = os.path.join(pkg.prefix, libdir)
        rpath_dirs.append(lib_path)

    # Set up link, include, RPATH directories that are passed to the
    # compiler wrapper
    for dep in link_deps:
        if is_system_path(dep.prefix):
            continue
        query = pkg.spec[dep.name]
        dep_link_dirs = list()
        try:
            dep_link_dirs.extend(query.libs.directories)
        except NoLibrariesError:
            tty.debug("No libraries found for {0}".format(dep.name))

        for default_lib_dir in ['lib', 'lib64']:
            default_lib_prefix = os.path.join(dep.prefix, default_lib_dir)
            if os.path.isdir(default_lib_prefix):
                dep_link_dirs.append(default_lib_prefix)

        link_dirs.extend(dep_link_dirs)
        if dep in rpath_deps:
            rpath_dirs.extend(dep_link_dirs)

        try:
            include_dirs.extend(query.headers.directories)
        except NoHeadersError:
            tty.debug("No headers found for {0}".format(dep.name))

    link_dirs = list(dedupe(filter_system_paths(link_dirs)))
    include_dirs = list(dedupe(filter_system_paths(include_dirs)))
    rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))

    env.set(SPACK_LINK_DIRS, ':'.join(link_dirs))
    env.set(SPACK_INCLUDE_DIRS, ':'.join(include_dirs))
    env.set(SPACK_RPATH_DIRS, ':'.join(rpath_dirs))

    build_prefixes = [dep.prefix for dep in build_deps]
    build_link_prefixes = [dep.prefix for dep in build_link_deps]

    # add run-time dependencies of direct build-time dependencies:
    for build_dep in build_deps:
        for run_dep in build_dep.traverse(deptype='run'):
            build_prefixes.append(run_dep.prefix)

    # Filter out system paths: ['/', '/usr', '/usr/local']
    # These paths can be introduced into the build when an external package
    # is added as a dependency. The problem with these paths is that they often
    # contain hundreds of other packages installed in the same directory.
    # If these paths come first, they can overshadow Spack installations.
    build_prefixes = filter_system_paths(build_prefixes)
    build_link_prefixes = filter_system_paths(build_link_prefixes)

    # Add dependencies to CMAKE_PREFIX_PATH
    env.set_path('CMAKE_PREFIX_PATH', build_link_prefixes)

    # Set environment variables if specified for
    # the given compiler
    compiler = pkg.compiler
    env.extend(spack.schema.environment.parse(compiler.environment))

    if compiler.extra_rpaths:
        extra_rpaths = ':'.join(compiler.extra_rpaths)
        env.set('SPACK_COMPILER_EXTRA_RPATHS', extra_rpaths)

    # Add bin directories from dependencies to the PATH for the build.
    for prefix in build_prefixes:
        for dirname in ['bin', 'bin64']:
            bin_dir = os.path.join(prefix, dirname)
            if os.path.isdir(bin_dir):
                env.prepend_path('PATH', bin_dir)

    # Add spack build environment path with compiler wrappers first in
    # the path. We add the compiler wrapper path, which includes default
    # wrappers (cc, c++, f77, f90), AND a subdirectory containing
    # compiler-specific symlinks.  The latter ensures that builds that
    # are sensitive to the *name* of the compiler see the right name when
    # we're building with the wrappers.
    #
    # Conflicts on case-insensitive systems (like "CC" and "cc") are
    # handled by putting one in the <build_env_path>/case-insensitive
    # directory.  Add that to the path too.
    env_paths = []
    compiler_specific = os.path.join(
        spack.paths.build_env_path,
        os.path.dirname(pkg.compiler.link_paths['cc']))
    for item in [spack.paths.build_env_path, compiler_specific]:
        env_paths.append(item)
        ci = os.path.join(item, 'case-insensitive')
        if os.path.isdir(ci):
            env_paths.append(ci)

    for item in env_paths:
        env.prepend_path('PATH', item)
    env.set_path(SPACK_ENV_PATH, env_paths)

    # Working directory for the spack command itself, for debug logs.
    if spack.config.get('config:debug'):
        env.set(SPACK_DEBUG, 'TRUE')
    env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec)
    env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('{name}-{hash:7}'))
    env.set(SPACK_DEBUG_LOG_DIR, spack.main.spack_working_dir)

    # Find ccache binary and hand it to build environment
    if spack.config.get('config:ccache'):
        ccache = Executable('ccache')
        if not ccache:
            raise RuntimeError("No ccache binary found in PATH")
        env.set(SPACK_CCACHE_BINARY, ccache)

    # Add any pkgconfig directories to PKG_CONFIG_PATH
    for prefix in build_link_prefixes:
        for directory in ('lib', 'lib64', 'share'):
            pcdir = os.path.join(prefix, directory, 'pkgconfig')
            if os.path.isdir(pcdir):
                env.prepend_path('PKG_CONFIG_PATH', pcdir)

    return env
Пример #14
0
def set_build_environment_variables(pkg, env, dirty):
    """Ensure a clean install environment when we build packages.

    This involves unsetting pesky environment variables that may
    affect the build. It also involves setting environment variables
    used by Spack's compiler wrappers.

    Args:
        pkg: The package we are building
        env: The build environment
        dirty (bool): Skip unsetting the user's environment settings
    """
    # Gather information about various types of dependencies
    build_deps = set(pkg.spec.dependencies(deptype=('build', 'test')))
    link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
    build_link_deps = build_deps | link_deps
    rpath_deps = get_rpath_deps(pkg)
    # This includes all build dependencies and any other dependencies that
    # should be added to PATH (e.g. supporting executables run by build
    # dependencies)
    build_and_supporting_deps = set()
    for build_dep in build_deps:
        build_and_supporting_deps.update(build_dep.traverse(deptype='run'))

    # Establish an arbitrary but fixed ordering of specs so that resulting
    # environment variable values are stable
    def _order(specs):
        return sorted(specs, key=lambda x: x.name)

    # External packages may be installed in a prefix which contains many other
    # package installs. To avoid having those installations override
    # Spack-installed packages, they are placed at the end of search paths.
    # System prefixes are removed entirely later on since they are already
    # searched.
    build_deps = _place_externals_last(_order(build_deps))
    link_deps = _place_externals_last(_order(link_deps))
    build_link_deps = _place_externals_last(_order(build_link_deps))
    rpath_deps = _place_externals_last(_order(rpath_deps))
    build_and_supporting_deps = _place_externals_last(
        _order(build_and_supporting_deps))

    link_dirs = []
    include_dirs = []
    rpath_dirs = []

    # The top-level package is always RPATHed. It hasn't been installed yet
    # so the RPATHs are added unconditionally (e.g. even though lib64/ may
    # not be created for the install).
    for libdir in ['lib', 'lib64']:
        lib_path = os.path.join(pkg.prefix, libdir)
        rpath_dirs.append(lib_path)

    # Set up link, include, RPATH directories that are passed to the
    # compiler wrapper
    for dep in link_deps:
        if is_system_path(dep.prefix):
            continue
        query = pkg.spec[dep.name]
        dep_link_dirs = list()
        try:
            dep_link_dirs.extend(query.libs.directories)
        except NoLibrariesError:
            tty.debug("No libraries found for {0}".format(dep.name))

        for default_lib_dir in ['lib', 'lib64']:
            default_lib_prefix = os.path.join(dep.prefix, default_lib_dir)
            if os.path.isdir(default_lib_prefix):
                dep_link_dirs.append(default_lib_prefix)

        link_dirs.extend(dep_link_dirs)
        if dep in rpath_deps:
            rpath_dirs.extend(dep_link_dirs)

        try:
            include_dirs.extend(query.headers.directories)
        except NoHeadersError:
            tty.debug("No headers found for {0}".format(dep.name))

    link_dirs = list(dedupe(filter_system_paths(link_dirs)))
    include_dirs = list(dedupe(filter_system_paths(include_dirs)))
    rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))

    env.set(SPACK_LINK_DIRS, ':'.join(link_dirs))
    env.set(SPACK_INCLUDE_DIRS, ':'.join(include_dirs))
    env.set(SPACK_RPATH_DIRS, ':'.join(rpath_dirs))

    build_and_supporting_prefixes = filter_system_paths(
        x.prefix for x in build_and_supporting_deps)
    build_link_prefixes = filter_system_paths(x.prefix
                                              for x in build_link_deps)

    # Add dependencies to CMAKE_PREFIX_PATH
    env.set_path('CMAKE_PREFIX_PATH', build_link_prefixes)

    # Set environment variables if specified for
    # the given compiler
    compiler = pkg.compiler
    env.extend(spack.schema.environment.parse(compiler.environment))

    if compiler.extra_rpaths:
        extra_rpaths = ':'.join(compiler.extra_rpaths)
        env.set('SPACK_COMPILER_EXTRA_RPATHS', extra_rpaths)

    # Add bin directories from dependencies to the PATH for the build.
    # These directories are added to the beginning of the search path, and in
    # the order given by 'build_and_supporting_prefixes' (the iteration order
    # is reversed because each entry is prepended)
    for prefix in reversed(build_and_supporting_prefixes):
        for dirname in ['bin', 'bin64']:
            bin_dir = os.path.join(prefix, dirname)
            if os.path.isdir(bin_dir):
                env.prepend_path('PATH', bin_dir)

    # Add spack build environment path with compiler wrappers first in
    # the path. We add the compiler wrapper path, which includes default
    # wrappers (cc, c++, f77, f90), AND a subdirectory containing
    # compiler-specific symlinks.  The latter ensures that builds that
    # are sensitive to the *name* of the compiler see the right name when
    # we're building with the wrappers.
    #
    # Conflicts on case-insensitive systems (like "CC" and "cc") are
    # handled by putting one in the <build_env_path>/case-insensitive
    # directory.  Add that to the path too.
    env_paths = []
    compiler_specific = os.path.join(
        spack.paths.build_env_path,
        os.path.dirname(pkg.compiler.link_paths['cc']))
    for item in [spack.paths.build_env_path, compiler_specific]:
        env_paths.append(item)
        ci = os.path.join(item, 'case-insensitive')
        if os.path.isdir(ci):
            env_paths.append(ci)

    for item in env_paths:
        env.prepend_path('PATH', item)
    env.set_path(SPACK_ENV_PATH, env_paths)

    # Working directory for the spack command itself, for debug logs.
    if spack.config.get('config:debug'):
        env.set(SPACK_DEBUG, 'TRUE')
    env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec)
    env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('{name}-{hash:7}'))
    env.set(SPACK_DEBUG_LOG_DIR, spack.main.spack_working_dir)

    # Find ccache binary and hand it to build environment
    if spack.config.get('config:ccache'):
        ccache = Executable('ccache')
        if not ccache:
            raise RuntimeError("No ccache binary found in PATH")
        env.set(SPACK_CCACHE_BINARY, ccache)

    # Add any pkgconfig directories to PKG_CONFIG_PATH
    for prefix in reversed(build_link_prefixes):
        for directory in ('lib', 'lib64', 'share'):
            pcdir = os.path.join(prefix, directory, 'pkgconfig')
            if os.path.isdir(pcdir):
                env.prepend_path('PKG_CONFIG_PATH', pcdir)

    return env
Пример #15
0
def set_build_environment_variables(pkg, env, dirty):
    """Ensure a clean install environment when we build packages.

    This involves unsetting pesky environment variables that may
    affect the build. It also involves setting environment variables
    used by Spack's compiler wrappers.

    Args:
        pkg: The package we are building
        env: The build environment
        dirty (bool): Skip unsetting the user's environment settings
    """
    # Gather information about various types of dependencies
    build_deps      = set(pkg.spec.dependencies(deptype=('build', 'test')))
    link_deps       = set(pkg.spec.traverse(root=False, deptype=('link')))
    build_link_deps = build_deps | link_deps
    rpath_deps      = get_rpath_deps(pkg)

    build_prefixes      = [dep.prefix for dep in build_deps]
    link_prefixes       = [dep.prefix for dep in link_deps]
    build_link_prefixes = [dep.prefix for dep in build_link_deps]
    rpath_prefixes      = [dep.prefix for dep in rpath_deps]

    # add run-time dependencies of direct build-time dependencies:
    for build_dep in build_deps:
        for run_dep in build_dep.traverse(deptype='run'):
            build_prefixes.append(run_dep.prefix)

    # Filter out system paths: ['/', '/usr', '/usr/local']
    # These paths can be introduced into the build when an external package
    # is added as a dependency. The problem with these paths is that they often
    # contain hundreds of other packages installed in the same directory.
    # If these paths come first, they can overshadow Spack installations.
    build_prefixes      = filter_system_paths(build_prefixes)
    link_prefixes       = filter_system_paths(link_prefixes)
    build_link_prefixes = filter_system_paths(build_link_prefixes)
    rpath_prefixes      = filter_system_paths(rpath_prefixes)

    # Prefixes of all of the package's dependencies go in SPACK_DEPENDENCIES
    env.set_path(SPACK_DEPENDENCIES, build_link_prefixes)

    # These variables control compiler wrapper behavior
    env.set_path(SPACK_RPATH_DEPS, rpath_prefixes)
    env.set_path(SPACK_LINK_DEPS, link_prefixes)

    # Add dependencies to CMAKE_PREFIX_PATH
    env.set_path('CMAKE_PREFIX_PATH', build_link_prefixes)

    # Install prefix
    env.set(SPACK_PREFIX, pkg.prefix)

    # Install root prefix
    env.set(SPACK_INSTALL, spack.store.root)

    # Set environment variables if specified for
    # the given compiler
    compiler = pkg.compiler
    environment = compiler.environment

    for command, variable in iteritems(environment):
        if command == 'set':
            for name, value in iteritems(variable):
                env.set(name, value)
        elif command == 'unset':
            for name, _ in iteritems(variable):
                env.unset(name)
        elif command == 'prepend-path':
            for name, value in iteritems(variable):
                env.prepend_path(name, value)
        elif command == 'append-path':
            for name, value in iteritems(variable):
                env.append_path(name, value)

    if compiler.extra_rpaths:
        extra_rpaths = ':'.join(compiler.extra_rpaths)
        env.set('SPACK_COMPILER_EXTRA_RPATHS', extra_rpaths)

    # Add bin directories from dependencies to the PATH for the build.
    for prefix in build_prefixes:
        for dirname in ['bin', 'bin64']:
            bin_dir = os.path.join(prefix, dirname)
            if os.path.isdir(bin_dir):
                env.prepend_path('PATH', bin_dir)

    # Add spack build environment path with compiler wrappers first in
    # the path. We add the compiler wrapper path, which includes default
    # wrappers (cc, c++, f77, f90), AND a subdirectory containing
    # compiler-specific symlinks.  The latter ensures that builds that
    # are sensitive to the *name* of the compiler see the right name when
    # we're building with the wrappers.
    #
    # Conflicts on case-insensitive systems (like "CC" and "cc") are
    # handled by putting one in the <build_env_path>/case-insensitive
    # directory.  Add that to the path too.
    env_paths = []
    compiler_specific = os.path.join(
        spack.paths.build_env_path, pkg.compiler.name)
    for item in [spack.paths.build_env_path, compiler_specific]:
        env_paths.append(item)
        ci = os.path.join(item, 'case-insensitive')
        if os.path.isdir(ci):
            env_paths.append(ci)

    for item in reversed(env_paths):
        env.prepend_path('PATH', item)
    env.set_path(SPACK_ENV_PATH, env_paths)

    # Working directory for the spack command itself, for debug logs.
    if spack.config.get('config:debug'):
        env.set(SPACK_DEBUG, 'TRUE')
    env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec)
    env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('${PACKAGE}-${HASH:7}'))
    env.set(SPACK_DEBUG_LOG_DIR, spack.main.spack_working_dir)

    # Find ccache binary and hand it to build environment
    if spack.config.get('config:ccache'):
        ccache = Executable('ccache')
        if not ccache:
            raise RuntimeError("No ccache binary found in PATH")
        env.set(SPACK_CCACHE_BINARY, ccache)

    # Add any pkgconfig directories to PKG_CONFIG_PATH
    for prefix in build_link_prefixes:
        for directory in ('lib', 'lib64', 'share'):
            pcdir = os.path.join(prefix, directory, 'pkgconfig')
            if os.path.isdir(pcdir):
                env.prepend_path('PKG_CONFIG_PATH', pcdir)

    return env
Пример #16
0
def test_filter_system_paths():
    nonsense_prefix = 'C:\\nonsense_path' if is_windows else '/nonsense_path'
    expected = [p for p in test_paths if p.startswith(nonsense_prefix)]
    filtered = envutil.filter_system_paths(test_paths)
    assert (expected == filtered)
Пример #17
0
def set_build_environment_variables(pkg, env, dirty):
    """Ensure a clean install environment when we build packages.

    This involves unsetting pesky environment variables that may
    affect the build. It also involves setting environment variables
    used by Spack's compiler wrappers.

    Args:
        pkg: The package we are building
        env: The build environment
        dirty (bool): Skip unsetting the user's environment settings
    """
    # Gather information about various types of dependencies
    build_deps = set(pkg.spec.dependencies(deptype=('build', 'test')))
    link_deps = set(pkg.spec.traverse(root=False, deptype=('link')))
    build_link_deps = build_deps | link_deps
    rpath_deps = get_rpath_deps(pkg)

    build_prefixes = [dep.prefix for dep in build_deps]
    link_prefixes = [dep.prefix for dep in link_deps]
    build_link_prefixes = [dep.prefix for dep in build_link_deps]
    rpath_prefixes = [dep.prefix for dep in rpath_deps]

    # add run-time dependencies of direct build-time dependencies:
    for build_dep in build_deps:
        for run_dep in build_dep.traverse(deptype='run'):
            build_prefixes.append(run_dep.prefix)

    # Filter out system paths: ['/', '/usr', '/usr/local']
    # These paths can be introduced into the build when an external package
    # is added as a dependency. The problem with these paths is that they often
    # contain hundreds of other packages installed in the same directory.
    # If these paths come first, they can overshadow Spack installations.
    build_prefixes = filter_system_paths(build_prefixes)
    link_prefixes = filter_system_paths(link_prefixes)
    build_link_prefixes = filter_system_paths(build_link_prefixes)
    rpath_prefixes = filter_system_paths(rpath_prefixes)

    # Prefixes of all of the package's dependencies go in SPACK_DEPENDENCIES
    env.set_path(SPACK_DEPENDENCIES, build_link_prefixes)

    # These variables control compiler wrapper behavior
    env.set_path(SPACK_RPATH_DEPS, rpath_prefixes)
    env.set_path(SPACK_LINK_DEPS, link_prefixes)

    # Add dependencies to CMAKE_PREFIX_PATH
    env.set_path('CMAKE_PREFIX_PATH', build_link_prefixes)

    # Install prefix
    env.set(SPACK_PREFIX, pkg.prefix)

    # Install root prefix
    env.set(SPACK_INSTALL, spack.store.root)

    # Stuff in here sanitizes the build environment to eliminate
    # anything the user has set that may interfere.
    if not dirty:
        # Remove these vars from the environment during build because they
        # can affect how some packages find libraries.  We want to make
        # sure that builds never pull in unintended external dependencies.
        env.unset('LD_LIBRARY_PATH')
        env.unset('LIBRARY_PATH')
        env.unset('CPATH')
        env.unset('LD_RUN_PATH')
        env.unset('DYLD_LIBRARY_PATH')

        # Remove any macports installs from the PATH.  The macports ld can
        # cause conflicts with the built-in linker on el capitan.  Solves
        # assembler issues, e.g.:
        #    suffix or operands invalid for `movq'"
        path = get_path('PATH')
        for p in path:
            if '/macports/' in p:
                env.remove_path('PATH', p)

    # Set environment variables if specified for
    # the given compiler
    compiler = pkg.compiler
    environment = compiler.environment
    if 'set' in environment:
        env_to_set = environment['set']
        for key, value in iteritems(env_to_set):
            env.set('SPACK_ENV_SET_%s' % key, value)
            env.set('%s' % key, value)
        # Let shell know which variables to set
        env_variables = ":".join(env_to_set.keys())
        env.set('SPACK_ENV_TO_SET', env_variables)

    if compiler.extra_rpaths:
        extra_rpaths = ':'.join(compiler.extra_rpaths)
        env.set('SPACK_COMPILER_EXTRA_RPATHS', extra_rpaths)

    # Add bin directories from dependencies to the PATH for the build.
    for prefix in build_prefixes:
        for dirname in ['bin', 'bin64']:
            bin_dir = os.path.join(prefix, dirname)
            if os.path.isdir(bin_dir):
                env.prepend_path('PATH', bin_dir)

    # Add spack build environment path with compiler wrappers first in
    # the path. We add the compiler wrapper path, which includes default
    # wrappers (cc, c++, f77, f90), AND a subdirectory containing
    # compiler-specific symlinks.  The latter ensures that builds that
    # are sensitive to the *name* of the compiler see the right name when
    # we're building with the wrappers.
    #
    # Conflicts on case-insensitive systems (like "CC" and "cc") are
    # handled by putting one in the <build_env_path>/case-insensitive
    # directory.  Add that to the path too.
    env_paths = []
    compiler_specific = os.path.join(spack.paths.build_env_path,
                                     pkg.compiler.name)
    for item in [spack.paths.build_env_path, compiler_specific]:
        env_paths.append(item)
        ci = os.path.join(item, 'case-insensitive')
        if os.path.isdir(ci):
            env_paths.append(ci)

    for item in reversed(env_paths):
        env.prepend_path('PATH', item)
    env.set_path(SPACK_ENV_PATH, env_paths)

    # Working directory for the spack command itself, for debug logs.
    if spack.config.get('config:debug'):
        env.set(SPACK_DEBUG, 'TRUE')
    env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec)
    env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('${PACKAGE}-${HASH:7}'))
    env.set(SPACK_DEBUG_LOG_DIR, spack.main.spack_working_dir)

    # Find ccache binary and hand it to build environment
    if spack.config.get('config:ccache'):
        ccache = Executable('ccache')
        if not ccache:
            raise RuntimeError("No ccache binary found in PATH")
        env.set(SPACK_CCACHE_BINARY, ccache)

    # Add any pkgconfig directories to PKG_CONFIG_PATH
    for prefix in build_link_prefixes:
        for directory in ('lib', 'lib64', 'share'):
            pcdir = os.path.join(prefix, directory, 'pkgconfig')
            if os.path.isdir(pcdir):
                env.prepend_path('PKG_CONFIG_PATH', pcdir)

    return env
Пример #18
0
def _parse_implicit_rpaths(string):
    """Parse implicit link paths from compiler debug output.

    This gives the compiler runtime library paths that we need to add to
    the RPATH of generated binaries and libraries.  It allows us to
    ensure, e.g., that codes load the right libstdc++ for their compiler.
    """
    lib_search_paths = False
    raw_link_dirs = []
    tty.debug('parsing implicit link info')
    for line in string.splitlines():
        if lib_search_paths:
            if line.startswith('\t'):
                raw_link_dirs.append(line[1:])
                continue
            else:
                lib_search_paths = False
        elif line.startswith('Library search paths:'):
            lib_search_paths = True

        if not _LINKER_LINE.match(line):
            continue
        if _LINKER_LINE_IGNORE.match(line):
            continue
        tty.debug('linker line: %s' % line)

        next_arg = False
        for arg in line.split():
            if arg in ('-L', '-Y'):
                next_arg = True
                continue

            if next_arg:
                raw_link_dirs.append(arg)
                next_arg = False
                continue

            link_dir_arg = _LINK_DIR_ARG.match(arg)
            if link_dir_arg:
                link_dir = link_dir_arg.group('dir')
                tty.debug('linkdir: %s' % link_dir)
                raw_link_dirs.append(link_dir)

            link_dir_arg = _LIBPATH_ARG.match(arg)
            if link_dir_arg:
                link_dir = link_dir_arg.group('dir')
                tty.debug('libpath: %s', link_dir)
                raw_link_dirs.append(link_dir)
    tty.debug('found raw link dirs: %s' % ', '.join(raw_link_dirs))

    implicit_link_dirs = list()
    visited = set()
    for link_dir in raw_link_dirs:
        normalized_path = os.path.abspath(link_dir)
        if normalized_path not in visited:
            implicit_link_dirs.append(normalized_path)
            visited.add(normalized_path)
    implicit_link_dirs = filter_system_paths(implicit_link_dirs)

    # Additional filtering: we also want to exclude paths that are
    # subdirectories of /usr/lib/ and /lib/
    implicit_link_dirs = list(
        path for path in implicit_link_dirs
        if not any(is_subdirectory(path, d) for d in ['/lib/', '/usr/lib/']))

    tty.debug('found link dirs: %s' % ', '.join(implicit_link_dirs))
    return implicit_link_dirs