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:
		| @@ -65,6 +65,27 @@ def dumpversion(compiler_path): | ||||
|     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): | ||||
|     """This class encapsulates a Spack "compiler", which includes C, | ||||
|        C++, and Fortran compilers.  Subclasses should implement | ||||
| @@ -147,7 +168,7 @@ def check(exe): | ||||
|         for flag in spack.spec.FlagMap.valid_compiler_flags(): | ||||
|             value = kwargs.get(flag, None) | ||||
|             if value is not None: | ||||
|                 self.flags[flag] = value.split() | ||||
|                 self.flags[flag] = tokenize_flags(value) | ||||
|  | ||||
|     @property | ||||
|     def version(self): | ||||
|   | ||||
| @@ -366,6 +366,9 @@ def concretize_compiler_flags(self, spec): | ||||
|                 nearest_flags = set(nearest.compiler_flags.get(flag, [])) | ||||
|                 flags = set(spec.compiler_flags.get(flag, [])) | ||||
|                 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) | ||||
|                     ret = True | ||||
|             except StopIteration: | ||||
|   | ||||
| @@ -1122,7 +1122,7 @@ def _add_flag(self, name, value): | ||||
|             self._set_architecture(target=value) | ||||
|         elif name in valid_flags: | ||||
|             assert(self.compiler_flags is not None) | ||||
|             self.compiler_flags[name] = value.split() | ||||
|             self.compiler_flags[name] = spack.compiler.tokenize_flags(value) | ||||
|         else: | ||||
|             # FIXME: | ||||
|             # All other flags represent variants. 'foo=true' and 'foo=false' | ||||
|   | ||||
| @@ -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 filtered if x.operating_system == 'SuSE11'] | ||||
|         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']) | ||||
|   | ||||
| @@ -203,6 +203,12 @@ def test_different_compilers_get_different_flags(self): | ||||
|         assert set(client.compiler_flags['fflags']) == set(['-O0']) | ||||
|         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): | ||||
|         s = Spec('mpileaks ^multi-provider-mpi@3.0') | ||||
|         s.concretize() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 scheibelp
					scheibelp