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(
'dump-mode',
['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'],
"ccld")
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): pytestmark = pytest.mark.usefixtures('wrapper_environment')
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
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 def check_cc(command, args, expected):
self.check_cpp('dump-args', test_command, with set_env(SPACK_TEST_COMMAND=command):
"cpp " + assert cc(*args, output=str).strip().split() == expected
'-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
# 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, def check_cxx(command, args, expected):
self.realcc + ' ' + with set_env(SPACK_TEST_COMMAND=command):
'-g -O1 -Werror -L foo ' + assert cxx(*args, output=str).strip().split() == expected
'-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,
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'] def check_fc(command, args, expected):
del os.environ['SPACK_CXXFLAGS'] with set_env(SPACK_TEST_COMMAND=command):
del os.environ['SPACK_FFLAGS'] assert fc(*args, output=str).strip().split() == expected
del os.environ['SPACK_CPPFLAGS']
del os.environ['SPACK_LDFLAGS']
del os.environ['SPACK_LDLIBS']
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): def check_ld(command, args, expected):
"""Ensure a single dependency include directory is added.""" with set_env(SPACK_TEST_COMMAND=command):
os.environ['SPACK_DEPENDENCIES'] = self.dep4 assert ld(*args, output=str).strip().split() == expected
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 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): def check_cpp(command, args, expected):
"""Ensure a single dependency link flag is added with no dep RPATH.""" with set_env(SPACK_TEST_COMMAND=command):
os.environ['SPACK_DEPENDENCIES'] = self.dep2 assert cpp(*args, output=str).strip().split() == expected
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 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): def test_vcheck_mode():
"""Ensure includes and RPATHs for all deps are added. """ check_cc(
os.environ['SPACK_DEPENDENCIES'] = ':'.join([ 'dump-mode', ['-I/include', '--version'], ['vcheck'])
self.dep1, self.dep2, self.dep3, self.dep4]) check_cc(
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] 'dump-mode', ['-I/include', '-V'], ['vcheck'])
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES'] 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): def test_cpp_mode():
"""Ensure no (extra) -I args or -Wl, are passed in ld mode.""" check_cc('dump-mode', ['-E'], ['cpp'])
os.environ['SPACK_DEPENDENCIES'] = ':'.join([ check_cpp('dump-mode', [], ['cpp'])
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']
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_as_mode():
"""Ensure SPACK_RPATH_DEPS controls RPATHs for ld.""" check_cc('dump-mode', ['-S'], ['as'])
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): def test_ccld_mode():
"""Ensure SPACK_LINK_DEPS controls -L for ld.""" check_cc(
os.environ['SPACK_DEPENDENCIES'] = ':'.join([ 'dump-mode', [], ['ccld'])
self.dep1, self.dep2, self.dep3, self.dep4]) check_cc(
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] '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): def test_ld_mode():
"""Make sure ld -r is handled correctly on OS's where it doesn't check_ld('dump-mode', [], ['ld'])
support rpaths.""" check_ld(
os.environ['SPACK_DEPENDENCIES'] = ':'.join([self.dep1]) 'dump-mode',
os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES'] ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], ['ld'])
os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
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" 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]