refactor: clean up and fix the cc test

- Add tests to ensure that RPATHs are not added in cc mode, which can
  cause some builds to fail.

- Change cc.py to use pytest style

- Instead of writing out all the flags, break the flags down into
  variables so that it's easy to read what each test is supposed to
  check. This should make cc.py more maintainable in the future.
This commit is contained in:
Todd Gamblin
2018-08-06 01:40:54 -07:00
parent c8fb9b5479
commit 0e81f6cba5
2 changed files with 460 additions and 371 deletions

View File

@@ -27,16 +27,16 @@
arguments correctly. arguments correctly.
""" """
import os import os
import unittest import pytest
import tempfile
import shutil
from spack.paths import build_env_path from spack.paths import build_env_path
from llnl.util.filesystem import mkdirp from spack.util.environment import system_dirs, set_env
from spack.util.executable import Executable from spack.util.executable import Executable
#
# Complicated compiler test command # Complicated compiler test command
test_command = [ #
test_args = [
'-I/test/include', '-L/test/lib', '-L/other/lib', '-I/other/include', '-I/test/include', '-L/test/lib', '-L/other/lib', '-I/other/include',
'arg1', 'arg1',
'-Wl,--start-group', '-Wl,--start-group',
@@ -45,422 +45,482 @@
'-llib1', '-llib2', '-llib1', '-llib2',
'arg4', 'arg4',
'-Wl,--end-group', '-Wl,--end-group',
'-Xlinker', '-rpath', '-Xlinker', '/third/rpath', '-Xlinker', '-Xlinker', '-rpath', '-Xlinker', '/third/rpath',
'-rpath', '-Xlinker', '/fourth/rpath', '-Xlinker', '-rpath', '-Xlinker', '/fourth/rpath',
'-llib3', '-llib4', '-llib3', '-llib4',
'arg5', 'arg6'] 'arg5', 'arg6']
#
# Pieces of the test command above, as they should be parsed out.
#
# `_wl_rpaths` are for the compiler (with -Wl,), and `_rpaths` are raw
# -rpath arguments for the linker.
#
test_include_paths = [
'-I/test/include', '-I/other/include']
class CompilerWrapperTest(unittest.TestCase): test_library_paths = [
'-L/test/lib', '-L/other/lib']
def setUp(self): test_wl_rpaths = [
self.cc = Executable(os.path.join(build_env_path, "cc")) '-Wl,-rpath,/first/rpath', '-Wl,-rpath,/second/rpath',
self.ld = Executable(os.path.join(build_env_path, "ld")) '-Wl,-rpath,/third/rpath', '-Wl,-rpath,/fourth/rpath']
self.cpp = Executable(os.path.join(build_env_path, "cpp"))
self.cxx = Executable(os.path.join(build_env_path, "c++"))
self.fc = Executable(os.path.join(build_env_path, "fc"))
self.realcc = "/bin/mycc" test_rpaths = [
self.prefix = "/spack-test-prefix" '-rpath', '/first/rpath', '-rpath', '/second/rpath',
'-rpath', '/third/rpath', '-rpath', '/fourth/rpath']
os.environ['SPACK_CC'] = self.realcc test_args_without_paths = [
os.environ['SPACK_CXX'] = self.realcc 'arg1',
os.environ['SPACK_FC'] = self.realcc '-Wl,--start-group',
'arg2', 'arg3', '-llib1', '-llib2', 'arg4',
'-Wl,--end-group',
'-llib3', '-llib4', 'arg5', 'arg6']
os.environ['SPACK_PREFIX'] = self.prefix #: The prefix of the package being mock installed
os.environ['SPACK_ENV_PATH'] = "test" pkg_prefix = '/spack-test-prefix'
os.environ['SPACK_DEBUG_LOG_DIR'] = "."
os.environ['SPACK_DEBUG_LOG_ID'] = "foo-hashabc"
os.environ['SPACK_COMPILER_SPEC'] = "gcc@4.4.7"
os.environ['SPACK_SHORT_SPEC'] = (
"foo@1.2 arch=linux-rhel6-x86_64 /hashabc")
os.environ['SPACK_CC_RPATH_ARG'] = "-Wl,-rpath," #
os.environ['SPACK_CXX_RPATH_ARG'] = "-Wl,-rpath," # Expected RPATHs for the package itself. The package is expected to
os.environ['SPACK_F77_RPATH_ARG'] = "-Wl,-rpath," # have only one of /lib or /lib64, but we add both b/c we can't know
os.environ['SPACK_FC_RPATH_ARG'] = "-Wl,-rpath," # before installing.
#
pkg_wl_rpaths = [
'-Wl,-rpath,' + pkg_prefix + '/lib',
'-Wl,-rpath,' + pkg_prefix + '/lib64']
# Make some fake dependencies pkg_rpaths = [
self.tmp_deps = tempfile.mkdtemp() '-rpath', '/spack-test-prefix/lib',
self.dep1 = os.path.join(self.tmp_deps, 'dep1') '-rpath', '/spack-test-prefix/lib64']
self.dep2 = os.path.join(self.tmp_deps, 'dep2')
self.dep3 = os.path.join(self.tmp_deps, 'dep3')
self.dep4 = os.path.join(self.tmp_deps, 'dep4')
mkdirp(os.path.join(self.dep1, 'include')) # Compilers to use during tests
mkdirp(os.path.join(self.dep1, 'lib')) cc = Executable(os.path.join(build_env_path, "cc"))
ld = Executable(os.path.join(build_env_path, "ld"))
cpp = Executable(os.path.join(build_env_path, "cpp"))
cxx = Executable(os.path.join(build_env_path, "c++"))
fc = Executable(os.path.join(build_env_path, "fc"))
mkdirp(os.path.join(self.dep2, 'lib64')) #: the "real" compiler the wrapper is expected to invoke
real_cc = '/bin/mycc'
mkdirp(os.path.join(self.dep3, 'include')) # mock flags to use in the wrapper environment
mkdirp(os.path.join(self.dep3, 'lib64')) spack_cppflags = ['-g', '-O1', '-DVAR=VALUE']
spack_cflags = ['-Wall']
spack_cxxflags = ['-Werror']
spack_fflags = ['-w']
spack_ldflags = ['-L', 'foo']
spack_ldlibs = ['-lfoo']
mkdirp(os.path.join(self.dep4, 'include'))
if 'SPACK_DEPENDENCIES' in os.environ: @pytest.fixture(scope='session')
del os.environ['SPACK_DEPENDENCIES'] def wrapper_environment():
with set_env(
SPACK_CC=real_cc,
SPACK_CXX=real_cc,
SPACK_FC=real_cc,
SPACK_PREFIX=pkg_prefix,
SPACK_ENV_PATH='test',
SPACK_DEBUG_LOG_DIR='.',
SPACK_DEBUG_LOG_ID='foo-hashabc',
SPACK_COMPILER_SPEC='gcc@4.4.7',
SPACK_SHORT_SPEC='foo@1.2 arch=linux-rhel6-x86_64 /hashabc',
SPACK_SYSTEM_DIRS=' '.join(system_dirs),
SPACK_CC_RPATH_ARG='-Wl,-rpath,',
SPACK_CXX_RPATH_ARG='-Wl,-rpath,',
SPACK_F77_RPATH_ARG='-Wl,-rpath,',
SPACK_FC_RPATH_ARG='-Wl,-rpath,',
SPACK_DEPENDENCIES=None):
yield
def tearDown(self):
shutil.rmtree(self.tmp_deps, True)
def check_cc(self, command, args, expected): @pytest.fixture()
os.environ['SPACK_TEST_COMMAND'] = command def wrapper_flags():
self.assertEqual(self.cc(*args, output=str).strip(), expected) with set_env(
SPACK_CPPFLAGS=' '.join(spack_cppflags),
SPACK_CFLAGS=' '.join(spack_cflags),
SPACK_CXXFLAGS=' '.join(spack_cxxflags),
SPACK_FFLAGS=' '.join(spack_fflags),
SPACK_LDFLAGS=' '.join(spack_ldflags),
SPACK_LDLIBS=' '.join(spack_ldlibs)):
yield
def check_cxx(self, command, args, expected):
os.environ['SPACK_TEST_COMMAND'] = command
self.assertEqual(self.cxx(*args, output=str).strip(), expected)
def check_fc(self, command, args, expected): @pytest.fixture(scope='session')
os.environ['SPACK_TEST_COMMAND'] = command def dep1(tmpdir_factory):
self.assertEqual(self.fc(*args, output=str).strip(), expected) path = tmpdir_factory.mktemp('cc-dep1')
path.mkdir('include')
path.mkdir('lib')
yield str(path)
def check_ld(self, command, args, expected):
os.environ['SPACK_TEST_COMMAND'] = command
self.assertEqual(self.ld(*args, output=str).strip(), expected)
def check_cpp(self, command, args, expected): @pytest.fixture(scope='session')
os.environ['SPACK_TEST_COMMAND'] = command def dep2(tmpdir_factory):
self.assertEqual(self.cpp(*args, output=str).strip(), expected) path = tmpdir_factory.mktemp('cc-dep2')
path.mkdir('lib64')
yield str(path)
def test_vcheck_mode(self):
self.check_cc('dump-mode', ['-I/include', '--version'], "vcheck")
self.check_cc('dump-mode', ['-I/include', '-V'], "vcheck")
self.check_cc('dump-mode', ['-I/include', '-v'], "vcheck")
self.check_cc('dump-mode', ['-I/include', '-dumpversion'], "vcheck")
self.check_cc('dump-mode', ['-I/include', '--version', '-c'], "vcheck")
self.check_cc('dump-mode', ['-I/include',
'-V', '-o', 'output'], "vcheck")
def test_cpp_mode(self): @pytest.fixture(scope='session')
self.check_cc('dump-mode', ['-E'], "cpp") def dep3(tmpdir_factory):
self.check_cpp('dump-mode', [], "cpp") path = tmpdir_factory.mktemp('cc-dep3')
path.mkdir('include')
path.mkdir('lib64')
yield str(path)
def test_as_mode(self):
self.check_cc('dump-mode', ['-S'], "as")
def test_ccld_mode(self): @pytest.fixture(scope='session')
self.check_cc('dump-mode', [], "ccld") def dep4(tmpdir_factory):
self.check_cc('dump-mode', ['foo.c', '-o', 'foo'], "ccld") path = tmpdir_factory.mktemp('cc-dep4')
self.check_cc('dump-mode', ['foo.c', '-o', path.mkdir('include')
'foo', '-Wl,-rpath,foo'], "ccld") yield str(path)
self.check_cc(
pytestmark = pytest.mark.usefixtures('wrapper_environment')
def check_cc(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert cc(*args, output=str).strip().split() == expected
def check_cxx(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert cxx(*args, output=str).strip().split() == expected
def check_fc(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert fc(*args, output=str).strip().split() == expected
def check_ld(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert ld(*args, output=str).strip().split() == expected
def check_cpp(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert cpp(*args, output=str).strip().split() == expected
def test_vcheck_mode():
check_cc(
'dump-mode', ['-I/include', '--version'], ['vcheck'])
check_cc(
'dump-mode', ['-I/include', '-V'], ['vcheck'])
check_cc(
'dump-mode', ['-I/include', '-v'], ['vcheck'])
check_cc(
'dump-mode', ['-I/include', '-dumpversion'], ['vcheck'])
check_cc(
'dump-mode', ['-I/include', '--version', '-c'], ['vcheck'])
check_cc(
'dump-mode', ['-I/include', '-V', '-o', 'output'], ['vcheck'])
def test_cpp_mode():
check_cc('dump-mode', ['-E'], ['cpp'])
check_cpp('dump-mode', [], ['cpp'])
def test_as_mode():
check_cc('dump-mode', ['-S'], ['as'])
def test_ccld_mode():
check_cc(
'dump-mode', [], ['ccld'])
check_cc(
'dump-mode', ['foo.c', '-o', 'foo'], ['ccld'])
check_cc(
'dump-mode', ['foo.c', '-o', 'foo', '-Wl,-rpath,foo'], ['ccld'])
check_cc(
'dump-mode', 'dump-mode',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['ccld'])
"ccld")
def test_ld_mode(self):
self.check_ld('dump-mode', [], "ld") def test_ld_mode():
self.check_ld( check_ld('dump-mode', [], ['ld'])
check_ld(
'dump-mode', 'dump-mode',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['ld'])
"ld")
def test_flags(self):
os.environ['SPACK_LDFLAGS'] = '-L foo'
os.environ['SPACK_LDLIBS'] = '-lfoo'
os.environ['SPACK_CPPFLAGS'] = '-g -O1'
os.environ['SPACK_CFLAGS'] = '-Wall'
os.environ['SPACK_CXXFLAGS'] = '-Werror'
os.environ['SPACK_FFLAGS'] = '-w'
# Test ldflags added properly in ld mode def test_ld_flags(wrapper_flags):
self.check_ld('dump-args', test_command, check_ld(
'ld -L foo ' + 'dump-args', test_args,
'-I/test/include -I/other/include arg1 ' + ['ld'] +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + spack_ldflags +
'-Wl,--end-group ' + test_include_paths +
'-llib3 -llib4 arg5 arg6 ' + test_library_paths +
'-L/test/lib -L/other/lib ' + test_rpaths +
'-lfoo ' + pkg_rpaths +
'-rpath /first/rpath -rpath /second/rpath ' + test_args_without_paths +
'-rpath /third/rpath -rpath /fourth/rpath ' + spack_ldlibs)
'-rpath /spack-test-prefix/lib ' +
'-rpath /spack-test-prefix/lib64')
# Test cppflags added properly in cpp mode
self.check_cpp('dump-args', test_command,
"cpp " +
'-g -O1 ' +
'-I/test/include -I/other/include arg1 ' +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' +
'-Wl,--end-group ' +
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib')
# Test ldflags, cppflags, and language specific flags are added in def test_cpp_flags(wrapper_flags):
# proper order check_cpp(
self.check_cc('dump-args', test_command, 'dump-args', test_args,
self.realcc + ' ' + ['cpp'] +
'-g -O1 -Wall -L foo ' + spack_cppflags +
'-I/test/include -I/other/include arg1 ' + test_include_paths +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + test_library_paths +
'-Wl,--end-group ' + test_args_without_paths)
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib ' +
'-lfoo ' +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' +
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' +
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64')
self.check_cxx('dump-args', test_command,
self.realcc + ' ' +
'-g -O1 -Werror -L foo ' +
'-I/test/include -I/other/include arg1 ' +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' +
'-Wl,--end-group ' +
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib ' +
'-lfoo ' +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' +
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' +
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64')
self.check_fc('dump-args', test_command, def test_cc_flags(wrapper_flags):
self.realcc + ' ' + check_cc(
'-w -g -O1 -L foo ' + 'dump-args', test_args,
'-I/test/include -I/other/include arg1 ' + [real_cc] +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + spack_cppflags +
'-Wl,--end-group ' + spack_cflags +
'-llib3 -llib4 arg5 arg6 ' + spack_ldflags +
'-L/test/lib -L/other/lib ' + test_include_paths +
'-lfoo ' + test_library_paths +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + test_wl_rpaths +
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' + pkg_wl_rpaths +
'-Wl,-rpath,/spack-test-prefix/lib ' + test_args_without_paths +
'-Wl,-rpath,/spack-test-prefix/lib64') spack_ldlibs)
del os.environ['SPACK_CFLAGS']
del os.environ['SPACK_CXXFLAGS']
del os.environ['SPACK_FFLAGS']
del os.environ['SPACK_CPPFLAGS']
del os.environ['SPACK_LDFLAGS']
del os.environ['SPACK_LDLIBS']
def test_dep_rpath(self): def test_cxx_flags(wrapper_flags):
check_cxx(
'dump-args', test_args,
[real_cc] +
spack_cppflags +
spack_cxxflags +
spack_ldflags +
test_include_paths +
test_library_paths +
test_wl_rpaths +
pkg_wl_rpaths +
test_args_without_paths +
spack_ldlibs)
def test_fc_flags(wrapper_flags):
check_fc(
'dump-args', test_args,
[real_cc] +
spack_cppflags +
spack_fflags +
spack_ldflags +
test_include_paths +
test_library_paths +
test_wl_rpaths +
pkg_wl_rpaths +
test_args_without_paths +
spack_ldlibs)
def test_dep_rpath():
"""Ensure RPATHs for root package are added.""" """Ensure RPATHs for root package are added."""
self.check_cc('dump-args', test_command, check_cc(
self.realcc + ' ' + 'dump-args', test_args,
'-I/test/include -I/other/include arg1 ' + [real_cc] +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + test_include_paths +
'-Wl,--end-group ' + test_library_paths +
'-llib3 -llib4 arg5 arg6 ' + test_wl_rpaths +
'-L/test/lib -L/other/lib ' + pkg_wl_rpaths +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + test_args_without_paths)
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' +
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64')
def test_dep_include(self):
def test_dep_include(dep4):
"""Ensure a single dependency include directory is added.""" """Ensure a single dependency include directory is added."""
os.environ['SPACK_DEPENDENCIES'] = self.dep4 with set_env(SPACK_DEPENDENCIES=dep4,
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_RPATH_DEPS=dep4,
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_LINK_DEPS=dep4):
self.check_cc('dump-args', test_command, check_cc(
self.realcc + ' ' + 'dump-args', test_args,
'-I/test/include -I/other/include ' + [real_cc] +
'-I' + self.dep4 + '/include arg1 ' + test_include_paths +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + ['-I' + dep4 + '/include'] +
'-Wl,--end-group ' + test_library_paths +
'-llib3 -llib4 arg5 arg6 ' + test_wl_rpaths +
'-L/test/lib -L/other/lib ' + pkg_wl_rpaths +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + test_args_without_paths)
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' +
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64')
def test_dep_lib(self):
def test_dep_lib(dep2):
"""Ensure a single dependency RPATH is added.""" """Ensure a single dependency RPATH is added."""
os.environ['SPACK_DEPENDENCIES'] = self.dep2 with set_env(SPACK_DEPENDENCIES=dep2,
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_RPATH_DEPS=dep2,
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_LINK_DEPS=dep2):
self.check_cc('dump-args', test_command, check_cc(
self.realcc + ' ' + 'dump-args', test_args,
'-I/test/include -I/other/include arg1 ' + [real_cc] +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + test_include_paths +
'-Wl,--end-group ' + test_library_paths +
'-llib3 -llib4 arg5 arg6 ' + ['-L' + dep2 + '/lib64'] +
'-L/test/lib -L/other/lib ' + test_wl_rpaths +
'-L' + self.dep2 + '/lib64 ' + pkg_wl_rpaths +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + ['-Wl,-rpath,' + dep2 + '/lib64'] +
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' + test_args_without_paths)
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64 ' +
'-Wl,-rpath,' + self.dep2 + '/lib64')
def test_dep_lib_no_rpath(self):
def test_dep_lib_no_rpath(dep2):
"""Ensure a single dependency link flag is added with no dep RPATH.""" """Ensure a single dependency link flag is added with no dep RPATH."""
os.environ['SPACK_DEPENDENCIES'] = self.dep2 with set_env(SPACK_DEPENDENCIES=dep2,
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_LINK_DEPS=dep2):
self.check_cc('dump-args', test_command, check_cc(
self.realcc + ' ' + 'dump-args', test_args,
'-I/test/include -I/other/include arg1 ' + [real_cc] +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + test_include_paths +
'-Wl,--end-group ' + test_library_paths +
'-llib3 -llib4 arg5 arg6 ' + ['-L' + dep2 + '/lib64'] +
'-L/test/lib -L/other/lib ' + test_wl_rpaths +
'-L' + self.dep2 + '/lib64 ' + pkg_wl_rpaths +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + test_args_without_paths)
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' +
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64')
def test_dep_lib_no_lib(self):
def test_dep_lib_no_lib(dep2):
"""Ensure a single dependency RPATH is added with no -L.""" """Ensure a single dependency RPATH is added with no -L."""
os.environ['SPACK_DEPENDENCIES'] = self.dep2 with set_env(SPACK_DEPENDENCIES=dep2,
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_RPATH_DEPS=dep2):
self.check_cc('dump-args', test_command, check_cc(
self.realcc + ' ' + 'dump-args', test_args,
'-I/test/include -I/other/include arg1 ' + [real_cc] +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + test_include_paths +
'-Wl,--end-group ' + test_library_paths +
'-llib3 -llib4 arg5 arg6 ' + test_wl_rpaths +
'-L/test/lib -L/other/lib ' + pkg_wl_rpaths +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + ['-Wl,-rpath,' + dep2 + '/lib64'] +
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' + test_args_without_paths)
'-Wl,-rpath,/spack-test-prefix/lib ' +
'-Wl,-rpath,/spack-test-prefix/lib64 ' +
'-Wl,-rpath,' + self.dep2 + '/lib64')
def test_all_deps(self):
"""Ensure includes and RPATHs for all deps are added. """
os.environ['SPACK_DEPENDENCIES'] = ':'.join([
self.dep1, self.dep2, self.dep3, self.dep4])
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
# This is probably more constrained than it needs to be; it def test_ccld_deps(dep1, dep2, dep3, dep4):
# checks order within prepended args and doesn't strictly have """Ensure all flags are added in ccld mode."""
# to. We could loosen that if it becomes necessary deps = ':'.join((dep1, dep2, dep3, dep4))
self.check_cc('dump-args', test_command, with set_env(SPACK_DEPENDENCIES=deps,
self.realcc + ' ' + SPACK_RPATH_DEPS=deps,
'-I/test/include -I/other/include ' + SPACK_LINK_DEPS=deps):
'-I' + self.dep1 + '/include ' + check_cc(
'-I' + self.dep3 + '/include ' + 'dump-args', test_args,
'-I' + self.dep4 + '/include ' + [real_cc] +
'arg1 ' + test_include_paths +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + ['-I' + dep1 + '/include',
'-Wl,--end-group ' + '-I' + dep3 + '/include',
'-llib3 -llib4 arg5 arg6 ' + '-I' + dep4 + '/include'] +
'-L/test/lib -L/other/lib ' + test_library_paths +
'-L' + self.dep1 + '/lib ' + ['-L' + dep1 + '/lib',
'-L' + self.dep2 + '/lib64 ' + '-L' + dep2 + '/lib64',
'-L' + self.dep3 + '/lib64 ' + '-L' + dep3 + '/lib64'] +
'-Wl,-rpath,/first/rpath -Wl,-rpath,/second/rpath ' + test_wl_rpaths +
'-Wl,-rpath,/third/rpath -Wl,-rpath,/fourth/rpath ' + pkg_wl_rpaths +
'-Wl,-rpath,/spack-test-prefix/lib ' + ['-Wl,-rpath,' + dep1 + '/lib',
'-Wl,-rpath,/spack-test-prefix/lib64 ' + '-Wl,-rpath,' + dep2 + '/lib64',
'-Wl,-rpath,' + self.dep1 + '/lib ' + '-Wl,-rpath,' + dep3 + '/lib64'] +
'-Wl,-rpath,' + self.dep2 + '/lib64 ' + test_args_without_paths)
'-Wl,-rpath,' + self.dep3 + '/lib64')
def test_ld_deps(self):
def test_cc_deps(dep1, dep2, dep3, dep4):
"""Ensure -L and RPATHs are not added in cc mode."""
deps = ':'.join((dep1, dep2, dep3, dep4))
with set_env(SPACK_DEPENDENCIES=deps,
SPACK_RPATH_DEPS=deps,
SPACK_LINK_DEPS=deps):
check_cc(
'dump-args', ['-c'] + test_args,
[real_cc] +
test_include_paths +
['-I' + dep1 + '/include',
'-I' + dep3 + '/include',
'-I' + dep4 + '/include'] +
test_library_paths +
['-c'] +
test_args_without_paths)
def test_ld_deps(dep1, dep2, dep3, dep4):
"""Ensure no (extra) -I args or -Wl, are passed in ld mode.""" """Ensure no (extra) -I args or -Wl, are passed in ld mode."""
os.environ['SPACK_DEPENDENCIES'] = ':'.join([ deps = ':'.join((dep1, dep2, dep3, dep4))
self.dep1, self.dep2, self.dep3, self.dep4]) with set_env(SPACK_DEPENDENCIES=deps,
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_RPATH_DEPS=deps,
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_LINK_DEPS=deps):
check_ld(
'dump-args', test_args,
['ld'] +
test_include_paths +
test_library_paths +
['-L' + dep1 + '/lib',
'-L' + dep2 + '/lib64',
'-L' + dep3 + '/lib64'] +
test_rpaths +
pkg_rpaths +
['-rpath', dep1 + '/lib',
'-rpath', dep2 + '/lib64',
'-rpath', dep3 + '/lib64'] +
test_args_without_paths)
self.check_ld('dump-args', test_command,
'ld ' +
'-I/test/include -I/other/include ' +
'arg1 ' +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' +
'-Wl,--end-group ' +
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib ' +
'-L' + self.dep1 + '/lib ' +
'-L' + self.dep2 + '/lib64 ' +
'-L' + self.dep3 + '/lib64 ' +
'-rpath /first/rpath -rpath /second/rpath ' +
'-rpath /third/rpath -rpath /fourth/rpath ' +
'-rpath /spack-test-prefix/lib ' +
'-rpath /spack-test-prefix/lib64 ' +
'-rpath ' + self.dep1 + '/lib ' +
'-rpath ' + self.dep2 + '/lib64 ' +
'-rpath ' + self.dep3 + '/lib64')
def test_ld_deps_no_rpath(self): def test_ld_deps_no_rpath(dep1, dep2, dep3, dep4):
"""Ensure SPACK_RPATH_DEPS controls RPATHs for ld."""
os.environ['SPACK_DEPENDENCIES'] = ':'.join([
self.dep1, self.dep2, self.dep3, self.dep4])
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
self.check_ld('dump-args', test_command,
'ld ' +
'-I/test/include -I/other/include ' +
'arg1 ' +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' +
'-Wl,--end-group ' +
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib ' +
'-L' + self.dep1 + '/lib ' +
'-L' + self.dep2 + '/lib64 ' +
'-L' + self.dep3 + '/lib64 ' +
'-rpath /first/rpath -rpath /second/rpath ' +
'-rpath /third/rpath -rpath /fourth/rpath ' +
'-rpath /spack-test-prefix/lib ' +
'-rpath /spack-test-prefix/lib64')
def test_ld_deps_no_link(self):
"""Ensure SPACK_LINK_DEPS controls -L for ld.""" """Ensure SPACK_LINK_DEPS controls -L for ld."""
os.environ['SPACK_DEPENDENCIES'] = ':'.join([ deps = ':'.join((dep1, dep2, dep3, dep4))
self.dep1, self.dep2, self.dep3, self.dep4]) with set_env(SPACK_DEPENDENCIES=deps,
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_LINK_DEPS=deps):
check_ld(
'dump-args', test_args,
['ld'] +
test_include_paths +
test_library_paths +
['-L' + dep1 + '/lib',
'-L' + dep2 + '/lib64',
'-L' + dep3 + '/lib64'] +
test_rpaths +
pkg_rpaths +
test_args_without_paths)
self.check_ld('dump-args', test_command,
'ld ' +
'-I/test/include -I/other/include ' +
'arg1 ' +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' +
'-Wl,--end-group ' +
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib ' +
'-rpath /first/rpath -rpath /second/rpath ' +
'-rpath /third/rpath -rpath /fourth/rpath ' +
'-rpath /spack-test-prefix/lib ' +
'-rpath /spack-test-prefix/lib64 ' +
'-rpath ' + self.dep1 + '/lib ' +
'-rpath ' + self.dep2 + '/lib64 ' +
'-rpath ' + self.dep3 + '/lib64')
def test_ld_deps_reentrant(self): def test_ld_deps_no_link(dep1, dep2, dep3, dep4):
"""Make sure ld -r is handled correctly on OS's where it doesn't """Ensure SPACK_RPATH_DEPS controls -rpath for ld."""
support rpaths.""" deps = ':'.join((dep1, dep2, dep3, dep4))
os.environ['SPACK_DEPENDENCIES'] = ':'.join([self.dep1]) with set_env(SPACK_DEPENDENCIES=deps,
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] SPACK_RPATH_DEPS=deps):
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES'] check_ld(
'dump-args', test_args,
['ld'] +
test_include_paths +
test_library_paths +
test_rpaths +
pkg_rpaths +
['-rpath', dep1 + '/lib',
'-rpath', dep2 + '/lib64',
'-rpath', dep3 + '/lib64'] +
test_args_without_paths)
def test_ld_deps_partial(dep1):
"""Make sure ld -r (partial link) is handled correctly on OS's where it
doesn't accept rpaths.
"""
with set_env(SPACK_DEPENDENCIES=dep1,
SPACK_RPATH_DEPS=dep1,
SPACK_LINK_DEPS=dep1):
# TODO: do we need to add RPATHs on other platforms like Linux?
# TODO: Can't we treat them the same?
os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=linux-x86_64" os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=linux-x86_64"
reentrant_test_command = ['-r'] + test_command check_ld(
self.check_ld('dump-args', reentrant_test_command, 'dump-args', ['-r'] + test_args,
'ld ' + ['ld'] +
'-I/test/include -I/other/include ' + test_include_paths +
'-r arg1 ' + test_library_paths +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + ['-L' + dep1 + '/lib'] +
'-Wl,--end-group ' + test_rpaths +
'-llib3 -llib4 arg5 arg6 ' + pkg_rpaths +
'-L/test/lib -L/other/lib ' + ['-rpath', dep1 + '/lib'] +
'-L' + self.dep1 + '/lib ' + ['-r'] +
'-rpath /first/rpath -rpath /second/rpath ' + test_args_without_paths)
'-rpath /third/rpath -rpath /fourth/rpath ' +
'-rpath /spack-test-prefix/lib ' +
'-rpath /spack-test-prefix/lib64 ' +
'-rpath ' + self.dep1 + '/lib')
# rpaths from the underlying command will still appear # rpaths from the underlying command will still appear
# Spack will not add its own rpaths. # Spack will not add its own rpaths.
os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=darwin-x86_64" os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=darwin-x86_64"
self.check_ld('dump-args', reentrant_test_command, check_ld(
'ld ' + 'dump-args', ['-r'] + test_args,
'-I/test/include -I/other/include ' + ['ld'] +
'-r arg1 ' + test_include_paths +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' + test_library_paths +
'-Wl,--end-group ' + ['-L' + dep1 + '/lib'] +
'-llib3 -llib4 arg5 arg6 ' + test_rpaths +
'-L/test/lib -L/other/lib ' + ['-r'] +
'-L' + self.dep1 + '/lib ' + test_args_without_paths)
'-rpath /first/rpath -rpath /second/rpath ' +
'-rpath /third/rpath -rpath /fourth/rpath')

View File

@@ -22,8 +22,10 @@
# License along with this program; if not, write to the Free Software # License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
import contextlib
import os import os
system_paths = ['/', '/usr', '/usr/local'] system_paths = ['/', '/usr', '/usr/local']
suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64'] suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64']
system_dirs = [os.path.join(p, s) for s in suffixes for p in system_paths] + \ system_dirs = [os.path.join(p, s) for s in suffixes for p in system_paths] + \
@@ -86,3 +88,30 @@ def dump_environment(path):
with open(path, 'w') as env_file: with open(path, 'w') as env_file:
for key, val in sorted(os.environ.items()): for key, val in sorted(os.environ.items()):
env_file.write('export %s="%s"\n' % (key, val)) env_file.write('export %s="%s"\n' % (key, val))
@contextlib.contextmanager
def set_env(**kwargs):
"""Temporarily sets and restores environment variables.
Variables can be set as keyword arguments to this function.
"""
saved = {}
for var, value in kwargs.items():
if var in os.environ:
saved[var] = os.environ[var]
if value is None:
if var in os.environ:
del os.environ[var]
else:
os.environ[var] = value
yield
for var, value in kwargs.items():
if var in saved:
os.environ[var] = saved[var]
else:
if var in os.environ:
del os.environ[var]