Group flags and values separated by space (#6169)

Fixes #6154

For compiler options which set values using the syntax "-flag value"
(with a space between the flag and the flag's value) the flag and
value were treated as separate and reordered. This updates Spack's
logic to treat the flag and value as a single unit, even if there is
a space between them. It assumes that all flags are prefixed with
"-" and that all flag values are not.
This commit is contained in:
scheibelp 2017-11-10 16:33:50 -08:00 committed by GitHub
parent 917d021997
commit 8c458a856f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 2 deletions

View file

@ -65,6 +65,27 @@ def dumpversion(compiler_path):
return get_compiler_version(compiler_path, '-dumpversion') return get_compiler_version(compiler_path, '-dumpversion')
def tokenize_flags(flags_str):
"""Given a compiler flag specification as a string, this returns a list
where the entries are the flags. For compiler options which set values
using the syntax "-flag value", this function groups flags and their
values together. Any token not preceded by a "-" is considered the
value of a prior flag."""
tokens = flags_str.split()
if not tokens:
return []
flag = tokens[0]
flags = []
for token in tokens[1:]:
if not token.startswith('-'):
flag += ' ' + token
else:
flags.append(flag)
flag = token
flags.append(flag)
return flags
class Compiler(object): class Compiler(object):
"""This class encapsulates a Spack "compiler", which includes C, """This class encapsulates a Spack "compiler", which includes C,
C++, and Fortran compilers. Subclasses should implement C++, and Fortran compilers. Subclasses should implement
@ -147,7 +168,7 @@ def check(exe):
for flag in spack.spec.FlagMap.valid_compiler_flags(): for flag in spack.spec.FlagMap.valid_compiler_flags():
value = kwargs.get(flag, None) value = kwargs.get(flag, None)
if value is not None: if value is not None:
self.flags[flag] = value.split() self.flags[flag] = tokenize_flags(value)
@property @property
def version(self): def version(self):

View file

@ -366,6 +366,9 @@ def concretize_compiler_flags(self, spec):
nearest_flags = set(nearest.compiler_flags.get(flag, [])) nearest_flags = set(nearest.compiler_flags.get(flag, []))
flags = set(spec.compiler_flags.get(flag, [])) flags = set(spec.compiler_flags.get(flag, []))
if (nearest_flags - flags): if (nearest_flags - flags):
# TODO: these set operations may reorder the flags, which
# for some orders of flags can be invalid. See:
# https://github.com/spack/spack/issues/6154#issuecomment-342365573
spec.compiler_flags[flag] = list(nearest_flags | flags) spec.compiler_flags[flag] = list(nearest_flags | flags)
ret = True ret = True
except StopIteration: except StopIteration:

View file

@ -1122,7 +1122,7 @@ def _add_flag(self, name, value):
self._set_architecture(target=value) self._set_architecture(target=value)
elif name in valid_flags: elif name in valid_flags:
assert(self.compiler_flags is not None) assert(self.compiler_flags is not None)
self.compiler_flags[name] = value.split() self.compiler_flags[name] = spack.compiler.tokenize_flags(value)
else: else:
# FIXME: # FIXME:
# All other flags represent variants. 'foo=true' and 'foo=false' # All other flags represent variants. 'foo=true' and 'foo=false'

View file

@ -47,3 +47,23 @@ def test_all_compilers(self):
filtered = [x for x in all_compilers if str(x.spec) == 'clang@3.3'] filtered = [x for x in all_compilers if str(x.spec) == 'clang@3.3']
filtered = [x for x in filtered if x.operating_system == 'SuSE11'] filtered = [x for x in filtered if x.operating_system == 'SuSE11']
assert len(filtered) == 1 assert len(filtered) == 1
def test_compiler_flags_from_config_are_grouped():
compiler_entry = {
'spec': 'intel@17.0.2',
'operating_system': 'foo-os',
'paths': {
'cc': 'cc-path',
'cxx': 'cxx-path',
'fc': None,
'f77': None
},
'flags': {
'cflags': '-O0 -foo-flag foo-val'
},
'modules': None
}
compiler = compilers.compiler_from_config_entry(compiler_entry)
assert any(x == '-foo-flag foo-val' for x in compiler.flags['cflags'])

View file

@ -203,6 +203,12 @@ def test_different_compilers_get_different_flags(self):
assert set(client.compiler_flags['fflags']) == set(['-O0']) assert set(client.compiler_flags['fflags']) == set(['-O0'])
assert not set(cmake.compiler_flags['fflags']) assert not set(cmake.compiler_flags['fflags'])
def test_compiler_flags_from_user_are_grouped(self):
spec = Spec('a%gcc cflags="-O -foo-flag foo-val" platform=test')
spec.concretize()
cflags = spec.compiler_flags['cflags']
assert any(x == '-foo-flag foo-val' for x in cflags)
def concretize_multi_provider(self): def concretize_multi_provider(self):
s = Spec('mpileaks ^multi-provider-mpi@3.0') s = Spec('mpileaks ^multi-provider-mpi@3.0')
s.concretize() s.concretize()