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') |     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): | ||||||
|   | |||||||
| @@ -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: | ||||||
|   | |||||||
| @@ -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' | ||||||
|   | |||||||
| @@ -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']) | ||||||
|   | |||||||
| @@ -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() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 scheibelp
					scheibelp