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.
"""
import os
import unittest
import tempfile
import shutil
import pytest
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
#
# Complicated compiler test command
test_command = [
#
test_args = [
'-I/test/include', '-L/test/lib', '-L/other/lib', '-I/other/include',
'arg1',
'-Wl,--start-group',
@ -45,422 +45,482 @@
'-llib1', '-llib2',
'arg4',
'-Wl,--end-group',
'-Xlinker', '-rpath', '-Xlinker', '/third/rpath', '-Xlinker',
'-rpath', '-Xlinker', '/fourth/rpath',
'-Xlinker', '-rpath', '-Xlinker', '/third/rpath',
'-Xlinker', '-rpath', '-Xlinker', '/fourth/rpath',
'-llib3', '-llib4',
'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):
self.cc = Executable(os.path.join(build_env_path, "cc"))
self.ld = Executable(os.path.join(build_env_path, "ld"))
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"))
test_wl_rpaths = [
'-Wl,-rpath,/first/rpath', '-Wl,-rpath,/second/rpath',
'-Wl,-rpath,/third/rpath', '-Wl,-rpath,/fourth/rpath']
self.realcc = "/bin/mycc"
self.prefix = "/spack-test-prefix"
test_rpaths = [
'-rpath', '/first/rpath', '-rpath', '/second/rpath',
'-rpath', '/third/rpath', '-rpath', '/fourth/rpath']
os.environ['SPACK_CC'] = self.realcc
os.environ['SPACK_CXX'] = self.realcc
os.environ['SPACK_FC'] = self.realcc
test_args_without_paths = [
'arg1',
'-Wl,--start-group',
'arg2', 'arg3', '-llib1', '-llib2', 'arg4',
'-Wl,--end-group',
'-llib3', '-llib4', 'arg5', 'arg6']
os.environ['SPACK_PREFIX'] = self.prefix
os.environ['SPACK_ENV_PATH'] = "test"
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")
#: The prefix of the package being mock installed
pkg_prefix = '/spack-test-prefix'
os.environ['SPACK_CC_RPATH_ARG'] = "-Wl,-rpath,"
os.environ['SPACK_CXX_RPATH_ARG'] = "-Wl,-rpath,"
os.environ['SPACK_F77_RPATH_ARG'] = "-Wl,-rpath,"
os.environ['SPACK_FC_RPATH_ARG'] = "-Wl,-rpath,"
#
# Expected RPATHs for the package itself. The package is expected to
# have only one of /lib or /lib64, but we add both b/c we can't know
# before installing.
#
pkg_wl_rpaths = [
'-Wl,-rpath,' + pkg_prefix + '/lib',
'-Wl,-rpath,' + pkg_prefix + '/lib64']
# Make some fake dependencies
self.tmp_deps = tempfile.mkdtemp()
self.dep1 = os.path.join(self.tmp_deps, 'dep1')
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')
pkg_rpaths = [
'-rpath', '/spack-test-prefix/lib',
'-rpath', '/spack-test-prefix/lib64']
mkdirp(os.path.join(self.dep1, 'include'))
mkdirp(os.path.join(self.dep1, 'lib'))
# Compilers to use during tests
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'))
mkdirp(os.path.join(self.dep3, 'lib64'))
# mock flags to use in the wrapper environment
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:
del os.environ['SPACK_DEPENDENCIES']
@pytest.fixture(scope='session')
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):
os.environ['SPACK_TEST_COMMAND'] = command
self.assertEqual(self.cc(*args, output=str).strip(), expected)
@pytest.fixture()
def wrapper_flags():
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):
os.environ['SPACK_TEST_COMMAND'] = command
self.assertEqual(self.fc(*args, output=str).strip(), expected)
@pytest.fixture(scope='session')
def dep1(tmpdir_factory):
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):
os.environ['SPACK_TEST_COMMAND'] = command
self.assertEqual(self.cpp(*args, output=str).strip(), expected)
@pytest.fixture(scope='session')
def dep2(tmpdir_factory):
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):
self.check_cc('dump-mode', ['-E'], "cpp")
self.check_cpp('dump-mode', [], "cpp")
@pytest.fixture(scope='session')
def dep3(tmpdir_factory):
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):
self.check_cc('dump-mode', [], "ccld")
self.check_cc('dump-mode', ['foo.c', '-o', 'foo'], "ccld")
self.check_cc('dump-mode', ['foo.c', '-o',
'foo', '-Wl,-rpath,foo'], "ccld")
self.check_cc(
'dump-mode',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'],
"ccld")
@pytest.fixture(scope='session')
def dep4(tmpdir_factory):
path = tmpdir_factory.mktemp('cc-dep4')
path.mkdir('include')
yield str(path)
def test_ld_mode(self):
self.check_ld('dump-mode', [], "ld")
self.check_ld(
'dump-mode',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'],
"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'
pytestmark = pytest.mark.usefixtures('wrapper_environment')
# Test ldflags added properly in ld mode
self.check_ld('dump-args', test_command,
'ld -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 ' +
'-rpath /first/rpath -rpath /second/rpath ' +
'-rpath /third/rpath -rpath /fourth/rpath ' +
'-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')
def check_cc(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert cc(*args, output=str).strip().split() == expected
# Test ldflags, cppflags, and language specific flags are added in
# proper order
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-g -O1 -Wall -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_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')
def check_cxx(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert cxx(*args, output=str).strip().split() == expected
self.check_fc('dump-args', test_command,
self.realcc + ' ' +
'-w -g -O1 -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')
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 check_fc(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert fc(*args, output=str).strip().split() == expected
def test_dep_rpath(self):
"""Ensure RPATHs for root package are added."""
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-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 ' +
'-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')
def test_dep_include(self):
"""Ensure a single dependency include directory is added."""
os.environ['SPACK_DEPENDENCIES'] = self.dep4
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-I/test/include -I/other/include ' +
'-I' + self.dep4 + '/include arg1 ' +
'-Wl,--start-group arg2 arg3 -llib1 -llib2 arg4 ' +
'-Wl,--end-group ' +
'-llib3 -llib4 arg5 arg6 ' +
'-L/test/lib -L/other/lib ' +
'-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')
def check_ld(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert ld(*args, output=str).strip().split() == expected
def test_dep_lib(self):
"""Ensure a single dependency RPATH is added."""
os.environ['SPACK_DEPENDENCIES'] = self.dep2
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-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.dep2 + '/lib64 ' +
'-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 ' +
'-Wl,-rpath,' + self.dep2 + '/lib64')
def test_dep_lib_no_rpath(self):
"""Ensure a single dependency link flag is added with no dep RPATH."""
os.environ['SPACK_DEPENDENCIES'] = self.dep2
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-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.dep2 + '/lib64 ' +
'-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')
def check_cpp(command, args, expected):
with set_env(SPACK_TEST_COMMAND=command):
assert cpp(*args, output=str).strip().split() == expected
def test_dep_lib_no_lib(self):
"""Ensure a single dependency RPATH is added with no -L."""
os.environ['SPACK_DEPENDENCIES'] = self.dep2
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-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 ' +
'-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 ' +
'-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']
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'])
# This is probably more constrained than it needs to be; it
# checks order within prepended args and doesn't strictly have
# to. We could loosen that if it becomes necessary
self.check_cc('dump-args', test_command,
self.realcc + ' ' +
'-I/test/include -I/other/include ' +
'-I' + self.dep1 + '/include ' +
'-I' + self.dep3 + '/include ' +
'-I' + self.dep4 + '/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 ' +
'-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 ' +
'-Wl,-rpath,' + self.dep1 + '/lib ' +
'-Wl,-rpath,' + self.dep2 + '/lib64 ' +
'-Wl,-rpath,' + self.dep3 + '/lib64')
def test_ld_deps(self):
"""Ensure no (extra) -I args or -Wl, are passed in ld mode."""
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']
def test_cpp_mode():
check_cc('dump-mode', ['-E'], ['cpp'])
check_cpp('dump-mode', [], ['cpp'])
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):
"""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']
def test_as_mode():
check_cc('dump-mode', ['-S'], ['as'])
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."""
os.environ['SPACK_DEPENDENCIES'] = ':'.join([
self.dep1, self.dep2, self.dep3, self.dep4])
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
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',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['ccld'])
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):
"""Make sure ld -r is handled correctly on OS's where it doesn't
support rpaths."""
os.environ['SPACK_DEPENDENCIES'] = ':'.join([self.dep1])
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
def test_ld_mode():
check_ld('dump-mode', [], ['ld'])
check_ld(
'dump-mode',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['ld'])
def test_ld_flags(wrapper_flags):
check_ld(
'dump-args', test_args,
['ld'] +
spack_ldflags +
test_include_paths +
test_library_paths +
test_rpaths +
pkg_rpaths +
test_args_without_paths +
spack_ldlibs)
def test_cpp_flags(wrapper_flags):
check_cpp(
'dump-args', test_args,
['cpp'] +
spack_cppflags +
test_include_paths +
test_library_paths +
test_args_without_paths)
def test_cc_flags(wrapper_flags):
check_cc(
'dump-args', test_args,
[real_cc] +
spack_cppflags +
spack_cflags +
spack_ldflags +
test_include_paths +
test_library_paths +
test_wl_rpaths +
pkg_wl_rpaths +
test_args_without_paths +
spack_ldlibs)
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."""
check_cc(
'dump-args', test_args,
[real_cc] +
test_include_paths +
test_library_paths +
test_wl_rpaths +
pkg_wl_rpaths +
test_args_without_paths)
def test_dep_include(dep4):
"""Ensure a single dependency include directory is added."""
with set_env(SPACK_DEPENDENCIES=dep4,
SPACK_RPATH_DEPS=dep4,
SPACK_LINK_DEPS=dep4):
check_cc(
'dump-args', test_args,
[real_cc] +
test_include_paths +
['-I' + dep4 + '/include'] +
test_library_paths +
test_wl_rpaths +
pkg_wl_rpaths +
test_args_without_paths)
def test_dep_lib(dep2):
"""Ensure a single dependency RPATH is added."""
with set_env(SPACK_DEPENDENCIES=dep2,
SPACK_RPATH_DEPS=dep2,
SPACK_LINK_DEPS=dep2):
check_cc(
'dump-args', test_args,
[real_cc] +
test_include_paths +
test_library_paths +
['-L' + dep2 + '/lib64'] +
test_wl_rpaths +
pkg_wl_rpaths +
['-Wl,-rpath,' + dep2 + '/lib64'] +
test_args_without_paths)
def test_dep_lib_no_rpath(dep2):
"""Ensure a single dependency link flag is added with no dep RPATH."""
with set_env(SPACK_DEPENDENCIES=dep2,
SPACK_LINK_DEPS=dep2):
check_cc(
'dump-args', test_args,
[real_cc] +
test_include_paths +
test_library_paths +
['-L' + dep2 + '/lib64'] +
test_wl_rpaths +
pkg_wl_rpaths +
test_args_without_paths)
def test_dep_lib_no_lib(dep2):
"""Ensure a single dependency RPATH is added with no -L."""
with set_env(SPACK_DEPENDENCIES=dep2,
SPACK_RPATH_DEPS=dep2):
check_cc(
'dump-args', test_args,
[real_cc] +
test_include_paths +
test_library_paths +
test_wl_rpaths +
pkg_wl_rpaths +
['-Wl,-rpath,' + dep2 + '/lib64'] +
test_args_without_paths)
def test_ccld_deps(dep1, dep2, dep3, dep4):
"""Ensure all flags are added in ccld 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', test_args,
[real_cc] +
test_include_paths +
['-I' + dep1 + '/include',
'-I' + dep3 + '/include',
'-I' + dep4 + '/include'] +
test_library_paths +
['-L' + dep1 + '/lib',
'-L' + dep2 + '/lib64',
'-L' + dep3 + '/lib64'] +
test_wl_rpaths +
pkg_wl_rpaths +
['-Wl,-rpath,' + dep1 + '/lib',
'-Wl,-rpath,' + dep2 + '/lib64',
'-Wl,-rpath,' + dep3 + '/lib64'] +
test_args_without_paths)
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."""
deps = ':'.join((dep1, dep2, dep3, dep4))
with set_env(SPACK_DEPENDENCIES=deps,
SPACK_RPATH_DEPS=deps,
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)
def test_ld_deps_no_rpath(dep1, dep2, dep3, dep4):
"""Ensure SPACK_LINK_DEPS controls -L for ld."""
deps = ':'.join((dep1, dep2, dep3, dep4))
with set_env(SPACK_DEPENDENCIES=deps,
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)
def test_ld_deps_no_link(dep1, dep2, dep3, dep4):
"""Ensure SPACK_RPATH_DEPS controls -rpath for ld."""
deps = ':'.join((dep1, dep2, dep3, dep4))
with set_env(SPACK_DEPENDENCIES=deps,
SPACK_RPATH_DEPS=deps):
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"
reentrant_test_command = ['-r'] + test_command
self.check_ld('dump-args', reentrant_test_command,
'ld ' +
'-I/test/include -I/other/include ' +
'-r 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 ' +
'-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')
check_ld(
'dump-args', ['-r'] + test_args,
['ld'] +
test_include_paths +
test_library_paths +
['-L' + dep1 + '/lib'] +
test_rpaths +
pkg_rpaths +
['-rpath', dep1 + '/lib'] +
['-r'] +
test_args_without_paths)
# rpaths from the underlying command will still appear
# Spack will not add its own rpaths.
os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=darwin-x86_64"
self.check_ld('dump-args', reentrant_test_command,
'ld ' +
'-I/test/include -I/other/include ' +
'-r 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 ' +
'-rpath /first/rpath -rpath /second/rpath ' +
'-rpath /third/rpath -rpath /fourth/rpath')
check_ld(
'dump-args', ['-r'] + test_args,
['ld'] +
test_include_paths +
test_library_paths +
['-L' + dep1 + '/lib'] +
test_rpaths +
['-r'] +
test_args_without_paths)

View File

@ -22,8 +22,10 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
import contextlib
import os
system_paths = ['/', '/usr', '/usr/local']
suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64']
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:
for key, val in sorted(os.environ.items()):
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]