Spack environment updates take precedence (#9107)

Spack originally handled environment modifications in the following
order:

 1. clear environment variables
    (unless Spack was invoked with --dirty)
 2. apply spack-specific environment variable updates,
    including variables set by Spack core like CC/PKG_CONFIG_PATH
	and those set by installed dependencies (e.g. in
	setup_dependent_environment)
 3. load all external/compiler modules

1 and 2 were done together. This splits 1 into its own function and
imposes the following order for environment modifications:

 1. clear environment variables
 2. load all external/compiler modules
 3. apply spack-specific environment variable updates

As a result, prepend-path actions taken by Spack (or installed Spack
dependencies) take precedence over prepend-path actions from compiler
and external modules. Additionally, when Spack (or a package
dependency) sets/unsets an environment variable, that will override
the actions of external/compiler modules.
This commit is contained in:
becker33 2018-09-05 17:28:39 -07:00 committed by scheibelp
parent a779e87442
commit f6fff8f343
3 changed files with 64 additions and 28 deletions

View File

@ -146,6 +146,33 @@ def __call__(self, *args, **kwargs):
return super(MakeExecutable, self).__call__(*args, **kwargs)
def clean_environment():
# Stuff in here sanitizes the build environment to eliminate
# anything the user has set that may interfere. We apply it immediately
# unlike the other functions so it doesn't overwrite what the modules load.
env = EnvironmentModifications()
# 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)
env.apply_modifications()
def set_compiler_environment_variables(pkg, env):
assert pkg.spec.concrete
compiler = pkg.compiler
@ -278,27 +305,6 @@ def set_build_environment_variables(pkg, env, dirty):
# 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
@ -629,6 +635,9 @@ def setup_package(pkg, dirty):
spack_env = EnvironmentModifications()
run_env = EnvironmentModifications()
if not dirty:
clean_environment()
set_compiler_environment_variables(pkg, spack_env)
set_build_environment_variables(pkg, spack_env, dirty)
pkg.architecture.platform.setup_platform_environment(pkg, spack_env)
@ -656,14 +665,12 @@ def setup_package(pkg, dirty):
set_module_variables_for_package(pkg, pkg.module)
pkg.setup_environment(spack_env, run_env)
# Make sure nothing's strange about the Spack environment.
validate(spack_env, tty.warn)
spack_env.apply_modifications()
# Loading modules, in particular if they are meant to be used outside
# of Spack, can change environment variables that are relevant to the
# build of packages. To avoid a polluted environment, preserve the
# value of a few, selected, environment variables
# With the current ordering of environment modifications, this is strictly
# unnecessary. Modules affecting these variables will be overwritten anyway
with preserve_environment('CC', 'CXX', 'FC', 'F77'):
# All module loads that otherwise would belong in previous
# functions have to occur after the spack_env object has its
@ -681,6 +688,10 @@ def setup_package(pkg, dirty):
load_external_modules(pkg)
# Make sure nothing's strange about the Spack environment.
validate(spack_env, tty.warn)
spack_env.apply_modifications()
def fork(pkg, function, dirty, fake):
"""Fork a child process to do part of a spack build.

View File

@ -1478,7 +1478,7 @@ def to_node_dict(self, hash_function=None):
if self.external:
d['external'] = {
'path': self.external_path,
'module': bool(self.external_module)
'module': self.external_module
}
# TODO: restore build dependencies here once we have less picky
@ -1916,7 +1916,7 @@ def concretize(self, tests=False):
dedupe(p + patches))
for s in self.traverse():
if s.external_module:
if s.external_module and not s.external_path:
compiler = spack.compilers.compiler_for_spec(
s.compiler, s.architecture)
for mod in compiler.modules:

View File

@ -131,7 +131,6 @@ def _set_wrong_cc(x):
@pytest.mark.usefixtures('config', 'mock_packages')
def test_compiler_config_modifications(monkeypatch):
s = spack.spec.Spec('cmake')
s.concretize()
pkg = s.package
@ -209,3 +208,29 @@ def test_compiler_config_modifications(monkeypatch):
os.environ.pop('PATH_LIST', None)
os.environ.pop('EMPTY_PATH_LIST', None)
os.environ.pop('NEW_PATH_LIST', None)
@pytest.mark.regression('9107')
def test_spack_paths_before_module_paths(config, mock_packages, monkeypatch):
s = spack.spec.Spec('cmake')
s.concretize()
pkg = s.package
module_path = '/path/to/module'
def _set_wrong_cc(x):
os.environ['PATH'] = module_path + ':' + os.environ['PATH']
monkeypatch.setattr(
spack.build_environment, 'load_module', _set_wrong_cc
)
monkeypatch.setattr(
pkg.compiler, 'modules', ['some_module']
)
spack.build_environment.setup_package(pkg, False)
spack_path = os.path.join(spack.paths.prefix, 'lib/spack/env')
paths = os.environ['PATH'].split(':')
assert paths.index(spack_path) < paths.index(module_path)