bugfix: use flags when computing implicit rpaths (#16634)

* make verbose_flag a property

* tests
This commit is contained in:
Greg Becker 2020-05-28 17:11:28 -07:00 committed by GitHub
parent 623cc7427e
commit 38ac78489a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 113 additions and 25 deletions

View file

@ -297,8 +297,10 @@ def implicit_rpaths(self):
if self.enable_implicit_rpaths is False:
return []
# Put CXX first since it has the most linking issues
# And because it has flags that affect linking
exe_paths = [
x for x in [self.cc, self.cxx, self.fc, self.f77] if x]
x for x in [self.cxx, self.cc, self.fc, self.f77] if x]
link_dirs = self._get_compiler_link_paths(exe_paths)
all_required_libs = (
@ -313,16 +315,24 @@ def required_libs(self):
# By default every compiler returns the empty list
return []
@classmethod
def _get_compiler_link_paths(cls, paths):
def _get_compiler_link_paths(self, paths):
first_compiler = next((c for c in paths if c), None)
if not first_compiler:
return []
if not cls.verbose_flag():
if not self.verbose_flag:
# In this case there is no mechanism to learn what link directories
# are used by the compiler
return []
# What flag types apply to first_compiler, in what order
flags = ['cppflags', 'ldflags']
if first_compiler == self.cc:
flags = ['cflags'] + flags
elif first_compiler == self.cxx:
flags = ['cxxflags'] + flags
else:
flags.append('fflags')
try:
tmpdir = tempfile.mkdtemp(prefix='spack-implicit-link-info')
fout = os.path.join(tmpdir, 'output')
@ -333,7 +343,10 @@ def _get_compiler_link_paths(cls, paths):
'int main(int argc, char* argv[]) { '
'(void)argc; (void)argv; return 0; }\n')
compiler_exe = spack.util.executable.Executable(first_compiler)
output = str(compiler_exe(cls.verbose_flag(), fin, '-o', fout,
for flag_type in flags:
for flag in self.flags.get(flag_type, []):
compiler_exe.add_default_arg(flag)
output = str(compiler_exe(self.verbose_flag, fin, '-o', fout,
output=str, error=str)) # str for py2
return _parse_non_system_link_dirs(output)
@ -344,8 +357,8 @@ def _get_compiler_link_paths(cls, paths):
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
"""
This property should be overridden in the compiler subclass if a
verbose flag is available.

View file

@ -51,8 +51,8 @@ def extract_version_from_output(cls, output):
temp = match.group(1) + "." + match.group(2)
return temp
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
@property

View file

@ -40,8 +40,8 @@ def version_argument(self):
version_regex = r'[Vv]ersion.*?(\d+(\.\d+)+)'
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
@property

View file

@ -81,8 +81,8 @@ def is_apple(self):
ver_string = str(self.version)
return ver_string.endswith('-apple')
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
@property

View file

@ -30,8 +30,8 @@ class Fj(spack.compiler.Compiler):
required_libs = ['libfj90i', 'libfj90f', 'libfjsrcinfo']
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
@property

View file

@ -38,8 +38,8 @@ class Gcc(Compiler):
PrgEnv = 'PrgEnv-gnu'
PrgEnv_compiler = 'gcc'
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
@property

View file

@ -32,8 +32,8 @@ class Intel(Compiler):
version_argument = '--version'
version_regex = r'\((?:IFORT|ICC)\) ([^ ]+)'
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
required_libs = ['libirc', 'libifcore', 'libifcoremt', 'libirng']

View file

@ -33,8 +33,8 @@ class Pgi(Compiler):
ignore_version_errors = [2] # `pgcc -V` on PowerPC annoyingly returns 2
version_regex = r'pg[^ ]* ([0-9.]+)-[0-9]+ (LLVM )?[^ ]+ target on '
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-v"
@property

View file

@ -29,8 +29,8 @@ class Xl(Compiler):
version_argument = '-qversion'
version_regex = r'([0-9]?[0-9]\.[0-9])'
@classmethod
def verbose_flag(cls):
@property
def verbose_flag(self):
return "-V"
@property

View file

@ -145,8 +145,8 @@ def test_compiler_flags_from_config_are_grouped():
'paths': {
'cc': 'cc-path',
'cxx': 'cxx-path',
'fc': None,
'f77': None
'fc': 'fc-path',
'f77': 'f77-path'
},
'flags': {},
'modules': None
@ -165,6 +165,8 @@ def __init__(self):
default_compiler_entry['paths']['fc'],
default_compiler_entry['paths']['f77']])
_get_compiler_link_paths = Compiler._get_compiler_link_paths
@property
def name(self):
return "mockcompiler"
@ -173,6 +175,12 @@ def name(self):
def version(self):
return "1.0.0"
_verbose_flag = "--verbose"
@property
def verbose_flag(self):
return self._verbose_flag
required_libs = ['libgfortran']
@ -192,6 +200,73 @@ def try_all_dirs(*args):
assert set(retrieved_rpaths) == expected_rpaths
no_flag_dirs = ['/path/to/first/lib', '/path/to/second/lib64']
no_flag_output = 'ld -L%s -L%s' % tuple(no_flag_dirs)
flag_dirs = ['/path/to/first/with/flag/lib', '/path/to/second/lib64']
flag_output = 'ld -L%s -L%s' % tuple(flag_dirs)
def call_compiler(exe, *args, **kwargs):
# This method can replace Executable.__call__ to emulate a compiler that
# changes libraries depending on a flag.
if '--correct-flag' in exe.exe:
return flag_output
return no_flag_output
@pytest.mark.parametrize('exe,flagname', [
('cxx', ''),
('cxx', 'cxxflags'),
('cxx', 'cppflags'),
('cxx', 'ldflags'),
('cc', ''),
('cc', 'cflags'),
('cc', 'cppflags'),
('fc', ''),
('fc', 'fflags'),
('f77', 'fflags'),
('f77', 'cppflags'),
])
def test_get_compiler_link_paths(monkeypatch, exe, flagname):
# create fake compiler that emits mock verbose output
compiler = MockCompiler()
monkeypatch.setattr(
spack.util.executable.Executable, '__call__', call_compiler)
# Grab executable path to test
paths = [getattr(compiler, exe)]
# Test without flags
dirs = compiler._get_compiler_link_paths(paths)
assert dirs == no_flag_dirs
if flagname:
# set flags and test
setattr(compiler, 'flags', {flagname: ['--correct-flag']})
dirs = compiler._get_compiler_link_paths(paths)
assert dirs == flag_dirs
def test_get_compiler_link_paths_no_path():
compiler = MockCompiler()
compiler.cc = None
compiler.cxx = None
compiler.f77 = None
compiler.fc = None
dirs = compiler._get_compiler_link_paths([compiler.cxx])
assert dirs == []
def test_get_compiler_link_paths_no_verbose_flag():
compiler = MockCompiler()
compiler._verbose_flag = None
dirs = compiler._get_compiler_link_paths([compiler.cxx])
assert dirs == []
# Get the desired flag from the specified compiler spec.
def flag_value(flag, spec):
compiler = None