Merge pull request #6 in SCALE/spack from bugfix/SPACK-20-bin-directories-in-path to develop
# By Todd Gamblin # Via Todd Gamblin * commit '554ae9b3552a40ed253250bdebf548e4d8b01976': bugfix for SPACK-20: add dependency bin directories to PATH
This commit is contained in:
commit
b2efea01d5
24
lib/spack/env/cc
vendored
24
lib/spack/env/cc
vendored
@ -62,15 +62,17 @@ options, other_args = parser.parse_known_args()
|
|||||||
rpaths, other_args = parse_rpaths(other_args)
|
rpaths, other_args = parse_rpaths(other_args)
|
||||||
|
|
||||||
# Add dependencies' include and lib paths to our compiler flags.
|
# Add dependencies' include and lib paths to our compiler flags.
|
||||||
def append_if_dir(path_list, *dirs):
|
def add_if_dir(path_list, directory, index=None):
|
||||||
full_path = os.path.join(*dirs)
|
if os.path.isdir(directory):
|
||||||
if os.path.isdir(full_path):
|
if index is None:
|
||||||
path_list.append(full_path)
|
path_list.append(directory)
|
||||||
|
else:
|
||||||
|
path_list.insert(index, directory)
|
||||||
|
|
||||||
for dep_dir in spack_deps:
|
for dep_dir in spack_deps:
|
||||||
append_if_dir(options.include_path, dep_dir, "include")
|
add_if_dir(options.include_path, os.path.join(dep_dir, "include"))
|
||||||
append_if_dir(options.lib_path, dep_dir, "lib")
|
add_if_dir(options.lib_path, os.path.join(dep_dir, "lib"))
|
||||||
append_if_dir(options.lib_path, dep_dir, "lib64")
|
add_if_dir(options.lib_path, os.path.join(dep_dir, "lib64"))
|
||||||
|
|
||||||
# Add our modified arguments to it.
|
# Add our modified arguments to it.
|
||||||
arguments = ['-I%s' % path for path in options.include_path]
|
arguments = ['-I%s' % path for path in options.include_path]
|
||||||
@ -95,11 +97,9 @@ for var in ["LD_LIBRARY_PATH", "LD_RUN_PATH", "DYLD_LIBRARY_PATH"]:
|
|||||||
os.environ.pop(var)
|
os.environ.pop(var)
|
||||||
|
|
||||||
# Ensure that the delegated command doesn't just call this script again.
|
# Ensure that the delegated command doesn't just call this script again.
|
||||||
clean_path = get_path("PATH")
|
remove_paths = ['.'] + spack_env_path
|
||||||
for item in ['.'] + spack_env_path:
|
path = [p for p in get_path("PATH") if p not in remove_paths]
|
||||||
if item in clean_path:
|
os.environ["PATH"] = ":".join(path)
|
||||||
clean_path.remove(item)
|
|
||||||
os.environ["PATH"] = ":".join(clean_path)
|
|
||||||
|
|
||||||
full_command = [command] + arguments
|
full_command = [command] + arguments
|
||||||
|
|
||||||
|
160
lib/spack/spack/build_environment.py
Normal file
160
lib/spack/spack/build_environment.py
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
"""
|
||||||
|
This module contains all routines related to setting up the package
|
||||||
|
build environment. All of this is set up by package.py just before
|
||||||
|
install() is called.
|
||||||
|
|
||||||
|
There are two parts to the bulid environment:
|
||||||
|
|
||||||
|
1. Python build environment (i.e. install() method)
|
||||||
|
|
||||||
|
This is how things are set up when install() is called. Spack
|
||||||
|
takes advantage of each package being in its own module by adding a
|
||||||
|
bunch of command-like functions (like configure(), make(), etc.) in
|
||||||
|
the package's module scope. Ths allows package writers to call
|
||||||
|
them all directly in Package.install() without writing 'self.'
|
||||||
|
everywhere. No, this isn't Pythonic. Yes, it makes the code more
|
||||||
|
readable and more like the shell script from whcih someone is
|
||||||
|
likely porting.
|
||||||
|
|
||||||
|
2. Build execution environment
|
||||||
|
|
||||||
|
This is the set of environment variables, like PATH, CC, CXX,
|
||||||
|
etc. that control the build. There are also a number of
|
||||||
|
environment variables used to pass information (like RPATHs and
|
||||||
|
other information about dependencies) to Spack's compiler wrappers.
|
||||||
|
All of these env vars are also set up here.
|
||||||
|
|
||||||
|
Skimming this module is a nice way to get acquainted with the types of
|
||||||
|
calls you can make from within the install() function.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import multiprocessing
|
||||||
|
import platform
|
||||||
|
from llnl.util.filesystem import *
|
||||||
|
|
||||||
|
import spack
|
||||||
|
from spack.util.executable import Executable, which
|
||||||
|
from spack.util.environment import *
|
||||||
|
|
||||||
|
#
|
||||||
|
# This can be set by the user to globally disable parallel builds.
|
||||||
|
#
|
||||||
|
SPACK_NO_PARALLEL_MAKE = 'SPACK_NO_PARALLEL_MAKE'
|
||||||
|
|
||||||
|
#
|
||||||
|
# These environment variables are set by
|
||||||
|
# set_build_environment_variables and used to pass parameters to
|
||||||
|
# Spack's compiler wrappers.
|
||||||
|
#
|
||||||
|
SPACK_LIB = 'SPACK_LIB'
|
||||||
|
SPACK_ENV_PATH = 'SPACK_ENV_PATH'
|
||||||
|
SPACK_DEPENDENCIES = 'SPACK_DEPENDENCIES'
|
||||||
|
SPACK_PREFIX = 'SPACK_PREFIX'
|
||||||
|
SPACK_BUILD_ROOT = 'SPACK_BUILD_ROOT'
|
||||||
|
|
||||||
|
|
||||||
|
class MakeExecutable(Executable):
|
||||||
|
"""Special callable executable object for make so the user can
|
||||||
|
specify parallel or not on a per-invocation basis. Using
|
||||||
|
'parallel' as a kwarg will override whatever the package's
|
||||||
|
global setting is, so you can either default to true or false
|
||||||
|
and override particular calls.
|
||||||
|
|
||||||
|
Note that if the SPACK_NO_PARALLEL_MAKE env var is set it overrides
|
||||||
|
everything.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, parallel):
|
||||||
|
super(MakeExecutable, self).__init__(name)
|
||||||
|
self.parallel = parallel
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
parallel = kwargs.get('parallel', self.parallel)
|
||||||
|
disable_parallel = env_flag(SPACK_NO_PARALLEL_MAKE)
|
||||||
|
|
||||||
|
if parallel and not disable_parallel:
|
||||||
|
jobs = "-j%d" % multiprocessing.cpu_count()
|
||||||
|
args = (jobs,) + args
|
||||||
|
|
||||||
|
super(MakeExecutable, self).__call__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def set_build_environment_variables(pkg):
|
||||||
|
"""This ensures a clean install environment when we build packages.
|
||||||
|
"""
|
||||||
|
# This tells the compiler script where to find the Spack installation.
|
||||||
|
os.environ[SPACK_LIB] = spack.lib_path
|
||||||
|
|
||||||
|
# Add spack build environment path with compiler wrappers first in
|
||||||
|
# the path. We handle case sensitivity conflicts like "CC" and
|
||||||
|
# "cc" by putting one in the <build_env_path>/case-insensitive
|
||||||
|
# directory. Add that to the path too.
|
||||||
|
env_paths = [spack.build_env_path,
|
||||||
|
join_path(spack.build_env_path, 'case-insensitive')]
|
||||||
|
path_put_first("PATH", env_paths)
|
||||||
|
path_set(SPACK_ENV_PATH, env_paths)
|
||||||
|
|
||||||
|
# Prefixes of all of the package's dependencies go in
|
||||||
|
# SPACK_DEPENDENCIES
|
||||||
|
dep_prefixes = [d.package.prefix for d in pkg.spec.dependencies.values()]
|
||||||
|
path_set(SPACK_DEPENDENCIES, dep_prefixes)
|
||||||
|
|
||||||
|
# Install prefix
|
||||||
|
os.environ[SPACK_PREFIX] = pkg.prefix
|
||||||
|
|
||||||
|
# Build root for logging.
|
||||||
|
os.environ[SPACK_BUILD_ROOT] = pkg.stage.expanded_archive_path
|
||||||
|
|
||||||
|
# Remove these vars from the environment during build becaus they
|
||||||
|
# can affect how some packages find libraries. We want to make
|
||||||
|
# sure that builds never pull in unintended external dependencies.
|
||||||
|
pop_keys(os.environ, "LD_LIBRARY_PATH", "LD_RUN_PATH", "DYLD_LIBRARY_PATH")
|
||||||
|
|
||||||
|
# Add bin directories from dependencies to the PATH for the build.
|
||||||
|
bin_dirs = ['%s/bin' % prefix for prefix in dep_prefixes]
|
||||||
|
path_put_first('PATH', [bin for bin in bin_dirs if os.path.isdir(bin)])
|
||||||
|
|
||||||
|
|
||||||
|
def set_module_variables_for_package(pkg):
|
||||||
|
"""Populate the module scope of install() with some useful functions.
|
||||||
|
This makes things easier for package writers.
|
||||||
|
"""
|
||||||
|
m = pkg.module
|
||||||
|
|
||||||
|
m.make = MakeExecutable('make', pkg.parallel)
|
||||||
|
m.gmake = MakeExecutable('gmake', pkg.parallel)
|
||||||
|
|
||||||
|
# number of jobs spack prefers to build with.
|
||||||
|
m.make_jobs = multiprocessing.cpu_count()
|
||||||
|
|
||||||
|
# Find the configure script in the archive path
|
||||||
|
# Don't use which for this; we want to find it in the current dir.
|
||||||
|
m.configure = Executable('./configure')
|
||||||
|
|
||||||
|
# TODO: shouldn't really use "which" here. Consider adding notion
|
||||||
|
# TODO: of build dependencies, as opposed to link dependencies.
|
||||||
|
# TODO: Currently, everything is a link dependency, but tools like
|
||||||
|
# TODO: this shouldn't be.
|
||||||
|
m.cmake = which("cmake")
|
||||||
|
|
||||||
|
# standard CMake arguments
|
||||||
|
m.std_cmake_args = ['-DCMAKE_INSTALL_PREFIX=%s' % pkg.prefix,
|
||||||
|
'-DCMAKE_BUILD_TYPE=None']
|
||||||
|
if platform.mac_ver()[0]:
|
||||||
|
m.std_cmake_args.append('-DCMAKE_FIND_FRAMEWORK=LAST')
|
||||||
|
|
||||||
|
# Emulate some shell commands for convenience
|
||||||
|
m.cd = os.chdir
|
||||||
|
m.mkdir = os.mkdir
|
||||||
|
m.makedirs = os.makedirs
|
||||||
|
m.remove = os.remove
|
||||||
|
m.removedirs = os.removedirs
|
||||||
|
|
||||||
|
m.mkdirp = mkdirp
|
||||||
|
m.install = install
|
||||||
|
m.rmtree = shutil.rmtree
|
||||||
|
m.move = shutil.move
|
||||||
|
|
||||||
|
# Useful directories within the prefix are encapsulated in
|
||||||
|
# a Prefix object.
|
||||||
|
m.prefix = pkg.prefix
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
# spack directory hierarchy
|
# spack directory hierarchy
|
||||||
lib_path = join_path(prefix, "lib", "spack")
|
lib_path = join_path(prefix, "lib", "spack")
|
||||||
env_path = join_path(lib_path, "env")
|
build_env_path = join_path(lib_path, "env")
|
||||||
module_path = join_path(lib_path, "spack")
|
module_path = join_path(lib_path, "spack")
|
||||||
compilers_path = join_path(module_path, "compilers")
|
compilers_path = join_path(module_path, "compilers")
|
||||||
test_path = join_path(module_path, "test")
|
test_path = join_path(module_path, "test")
|
||||||
@ -130,10 +130,3 @@
|
|||||||
#
|
#
|
||||||
mirrors = []
|
mirrors = []
|
||||||
|
|
||||||
# Important environment variables
|
|
||||||
SPACK_NO_PARALLEL_MAKE = 'SPACK_NO_PARALLEL_MAKE'
|
|
||||||
SPACK_LIB = 'SPACK_LIB'
|
|
||||||
SPACK_ENV_PATH = 'SPACK_ENV_PATH'
|
|
||||||
SPACK_DEPENDENCIES = 'SPACK_DEPENDENCIES'
|
|
||||||
SPACK_PREFIX = 'SPACK_PREFIX'
|
|
||||||
SPACK_BUILD_ROOT = 'SPACK_BUILD_ROOT'
|
|
||||||
|
@ -38,25 +38,22 @@
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import platform as py_platform
|
import platform as py_platform
|
||||||
import shutil
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.tty.color import cwrite
|
|
||||||
from llnl.util.filesystem import *
|
from llnl.util.filesystem import *
|
||||||
from llnl.util.lang import *
|
from llnl.util.lang import *
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.error
|
import spack.error
|
||||||
|
import spack.build_environment as build_env
|
||||||
import spack.url as url
|
import spack.url as url
|
||||||
import spack.util.crypto as crypto
|
import spack.util.crypto as crypto
|
||||||
from spack.version import *
|
from spack.version import *
|
||||||
from spack.stage import Stage
|
from spack.stage import Stage
|
||||||
from spack.util.web import get_pages
|
from spack.util.web import get_pages
|
||||||
from spack.util.environment import *
|
|
||||||
from spack.util.executable import Executable, which
|
|
||||||
from spack.util.compression import allowed_archive
|
from spack.util.compression import allowed_archive
|
||||||
|
|
||||||
"""Allowed URL schemes for spack packages."""
|
"""Allowed URL schemes for spack packages."""
|
||||||
@ -413,46 +410,6 @@ def stage(self):
|
|||||||
return self._stage
|
return self._stage
|
||||||
|
|
||||||
|
|
||||||
def add_commands_to_module(self):
|
|
||||||
"""Populate the module scope of install() with some useful functions.
|
|
||||||
This makes things easier for package writers.
|
|
||||||
"""
|
|
||||||
m = self.module
|
|
||||||
|
|
||||||
m.make = MakeExecutable('make', self.parallel)
|
|
||||||
m.gmake = MakeExecutable('gmake', self.parallel)
|
|
||||||
|
|
||||||
# number of jobs spack prefers to build with.
|
|
||||||
m.make_jobs = multiprocessing.cpu_count()
|
|
||||||
|
|
||||||
# Find the configure script in the archive path
|
|
||||||
# Don't use which for this; we want to find it in the current dir.
|
|
||||||
m.configure = Executable('./configure')
|
|
||||||
m.cmake = which("cmake")
|
|
||||||
|
|
||||||
# standard CMake arguments
|
|
||||||
m.std_cmake_args = ['-DCMAKE_INSTALL_PREFIX=%s' % self.prefix,
|
|
||||||
'-DCMAKE_BUILD_TYPE=None']
|
|
||||||
if py_platform.mac_ver()[0]:
|
|
||||||
m.std_cmake_args.append('-DCMAKE_FIND_FRAMEWORK=LAST')
|
|
||||||
|
|
||||||
# Emulate some shell commands for convenience
|
|
||||||
m.cd = os.chdir
|
|
||||||
m.mkdir = os.mkdir
|
|
||||||
m.makedirs = os.makedirs
|
|
||||||
m.remove = os.remove
|
|
||||||
m.removedirs = os.removedirs
|
|
||||||
|
|
||||||
m.mkdirp = mkdirp
|
|
||||||
m.install = install
|
|
||||||
m.rmtree = shutil.rmtree
|
|
||||||
m.move = shutil.move
|
|
||||||
|
|
||||||
# Useful directories within the prefix are encapsulated in
|
|
||||||
# a Prefix object.
|
|
||||||
m.prefix = self.prefix
|
|
||||||
|
|
||||||
|
|
||||||
def preorder_traversal(self, visited=None, **kwargs):
|
def preorder_traversal(self, visited=None, **kwargs):
|
||||||
"""This does a preorder traversal of the package's dependence DAG."""
|
"""This does a preorder traversal of the package's dependence DAG."""
|
||||||
virtual = kwargs.get("virtual", False)
|
virtual = kwargs.get("virtual", False)
|
||||||
@ -682,19 +639,16 @@ def do_install(self):
|
|||||||
self.do_install_dependencies()
|
self.do_install_dependencies()
|
||||||
|
|
||||||
self.do_patch()
|
self.do_patch()
|
||||||
self.setup_install_environment()
|
|
||||||
|
|
||||||
# Add convenience commands to the package's module scope to
|
|
||||||
# make building easier.
|
|
||||||
self.add_commands_to_module()
|
|
||||||
|
|
||||||
tty.msg("Building %s." % self.name)
|
|
||||||
|
|
||||||
# create the install directory (allow the layout to handle this in
|
# create the install directory (allow the layout to handle this in
|
||||||
# case it needs to add extra files)
|
# case it needs to add extra files)
|
||||||
spack.install_layout.make_path_for_spec(self.spec)
|
spack.install_layout.make_path_for_spec(self.spec)
|
||||||
|
|
||||||
|
tty.msg("Building %s." % self.name)
|
||||||
try:
|
try:
|
||||||
|
build_env.set_build_environment_variables(self)
|
||||||
|
build_env.set_module_variables_for_package(self)
|
||||||
|
|
||||||
self.install(self.spec, self.prefix)
|
self.install(self.spec, self.prefix)
|
||||||
if not os.path.isdir(self.prefix):
|
if not os.path.isdir(self.prefix):
|
||||||
tty.die("Install failed for %s. No install dir created." % self.name)
|
tty.die("Install failed for %s. No install dir created." % self.name)
|
||||||
@ -713,36 +667,6 @@ def do_install(self):
|
|||||||
self.stage.destroy()
|
self.stage.destroy()
|
||||||
|
|
||||||
|
|
||||||
def setup_install_environment(self):
|
|
||||||
"""This ensures a clean install environment when we build packages."""
|
|
||||||
pop_keys(os.environ, "LD_LIBRARY_PATH", "LD_RUN_PATH", "DYLD_LIBRARY_PATH")
|
|
||||||
|
|
||||||
# Add spack environment at front of path and pass the
|
|
||||||
# lib location along so the compiler script can find spack
|
|
||||||
os.environ[spack.SPACK_LIB] = spack.lib_path
|
|
||||||
|
|
||||||
# Fix for case-insensitive file systems. Conflicting links are
|
|
||||||
# in directories called "case*" within the env directory.
|
|
||||||
env_paths = [spack.env_path]
|
|
||||||
for file in os.listdir(spack.env_path):
|
|
||||||
path = join_path(spack.env_path, file)
|
|
||||||
if file.startswith("case") and os.path.isdir(path):
|
|
||||||
env_paths.append(path)
|
|
||||||
path_put_first("PATH", env_paths)
|
|
||||||
path_set(spack.SPACK_ENV_PATH, env_paths)
|
|
||||||
|
|
||||||
# Pass along prefixes of dependencies here
|
|
||||||
path_set(
|
|
||||||
spack.SPACK_DEPENDENCIES,
|
|
||||||
[dep.package.prefix for dep in self.spec.dependencies.values()])
|
|
||||||
|
|
||||||
# Install location
|
|
||||||
os.environ[spack.SPACK_PREFIX] = self.prefix
|
|
||||||
|
|
||||||
# Build root for logging.
|
|
||||||
os.environ[spack.SPACK_BUILD_ROOT] = self.stage.expanded_archive_path
|
|
||||||
|
|
||||||
|
|
||||||
def do_install_dependencies(self):
|
def do_install_dependencies(self):
|
||||||
# Pass along paths of dependencies here
|
# Pass along paths of dependencies here
|
||||||
for dep in self.spec.dependencies.values():
|
for dep in self.spec.dependencies.values():
|
||||||
@ -786,7 +710,8 @@ def do_clean(self):
|
|||||||
def clean(self):
|
def clean(self):
|
||||||
"""By default just runs make clean. Override if this isn't good."""
|
"""By default just runs make clean. Override if this isn't good."""
|
||||||
try:
|
try:
|
||||||
make = MakeExecutable('make', self.parallel)
|
# TODO: should we really call make clean, ro just blow away the directory?
|
||||||
|
make = build_env.MakeExecutable('make', self.parallel)
|
||||||
make('clean')
|
make('clean')
|
||||||
tty.msg("Successfully cleaned %s" % self.name)
|
tty.msg("Successfully cleaned %s" % self.name)
|
||||||
except subprocess.CalledProcessError, e:
|
except subprocess.CalledProcessError, e:
|
||||||
@ -871,30 +796,6 @@ def find_versions_of_archive(archive_url, **kwargs):
|
|||||||
return versions
|
return versions
|
||||||
|
|
||||||
|
|
||||||
class MakeExecutable(Executable):
|
|
||||||
"""Special Executable for make so the user can specify parallel or
|
|
||||||
not on a per-invocation basis. Using 'parallel' as a kwarg will
|
|
||||||
override whatever the package's global setting is, so you can
|
|
||||||
either default to true or false and override particular calls.
|
|
||||||
|
|
||||||
Note that if the SPACK_NO_PARALLEL_MAKE env var is set it overrides
|
|
||||||
everything.
|
|
||||||
"""
|
|
||||||
def __init__(self, name, parallel):
|
|
||||||
super(MakeExecutable, self).__init__(name)
|
|
||||||
self.parallel = parallel
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
parallel = kwargs.get('parallel', self.parallel)
|
|
||||||
disable_parallel = env_flag(spack.SPACK_NO_PARALLEL_MAKE)
|
|
||||||
|
|
||||||
if parallel and not disable_parallel:
|
|
||||||
jobs = "-j%d" % multiprocessing.cpu_count()
|
|
||||||
args = (jobs,) + args
|
|
||||||
|
|
||||||
super(MakeExecutable, self).__call__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_package_url(url_string):
|
def validate_package_url(url_string):
|
||||||
"""Determine whether spack can handle a particular URL or not."""
|
"""Determine whether spack can handle a particular URL or not."""
|
||||||
url = urlparse(url_string)
|
url = urlparse(url_string)
|
||||||
@ -911,6 +812,7 @@ def print_pkg(message):
|
|||||||
if mac_ver and Version(mac_ver) >= Version('10.7'):
|
if mac_ver and Version(mac_ver) >= Version('10.7'):
|
||||||
print u"\U0001F4E6" + tty.indent,
|
print u"\U0001F4E6" + tty.indent,
|
||||||
else:
|
else:
|
||||||
|
from llnl.util.tty.color import cwrite
|
||||||
cwrite('@*g{[+]} ')
|
cwrite('@*g{[+]} ')
|
||||||
print message
|
print message
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user