Repository: spack/spack

Issue:
Changing compiler in dependency does not change compiler flags
So here's the situation. I have both GCC and PGI in my `compilers.yaml`. GCC does not have any compiler flags, but PGI does:
```yaml
compilers:
- compiler:
    environment: {}
    extra_rpaths: []
    flags: {}
    modules: []
    operating_system: centos6
    paths:
      cc:  /soft/spack/opt/spack/linux-x86_64/gcc-5.3.0/gcc-6.1.0-q2zosj3igepi3pjnqt74bwazmptr5gpj/bin/gcc
      cxx: /soft/spack/opt/spack/linux-x86_64/gcc-5.3.0/gcc-6.1.0-q2zosj3igepi3pjnqt74bwazmptr5gpj/bin/g++
      f77: /soft/spack/opt/spack/linux-x86_64/gcc-5.3.0/gcc-6.1.0-q2zosj3igepi3pjnqt74bwazmptr5gpj/bin/gfortran
      fc:  /soft/spack/opt/spack/linux-x86_64/gcc-5.3.0/gcc-6.1.0-q2zosj3igepi3pjnqt74bwazmptr5gpj/bin/gfortran
    spec: gcc@6.1.0
    target: x86_64
- compiler:
    environment: {}
    extra_rpaths: []
    flags:
      cflags:   -tp=haswell,sandybridge
      cxxflags: -tp=haswell,sandybridge
      fflags:   -tp=haswell,sandybridge
    modules: []
    operating_system: centos6
    paths:
      cc:  /soft/spack-0.9.1/opt/spack/linux-centos6-x86_64/gcc-4.4.7/pgi-16.5-pa5hji6khmosol3h7u65zhw6cy2dnekn/linux86-64/16.5/bin/pgcc
      cxx: /soft/spack-0.9.1/opt/spack/linux-centos6-x86_64/gcc-4.4.7/pgi-16.5-pa5hji6khmosol3h7u65zhw6cy2dnekn/linux86-64/16.5/bin/pgc++
      f77: /soft/spack-0.9.1/opt/spack/linux-centos6-x86_64/gcc-4.4.7/pgi-16.5-pa5hji6khmosol3h7u65zhw6cy2dnekn/linux86-64/16.5/bin/pgfortran
      fc:  /soft/spack-0.9.1/opt/spack/linux-centos6-x86_64/gcc-4.4.7/pgi-16.5-pa5hji6khmosol3h7u65zhw6cy2dnekn/linux86-64/16.5/bin/pgfortran
    spec: pgi@16.5-0
    target: x86_64
```
Now I want to build `openmpi` with PGI, but `libpciaccess` can't be built with PGI, so I tell Spack to build it with GCC instead:
```
$ spack spec openmpi %pgi ^libpciaccess%gcc
Input spec
--------------------------------
openmpi%pgi
    ^libpciaccess%gcc

Normalized
--------------------------------
openmpi%pgi
    ^hwloc
        ^libpciaccess%gcc
            ^libtool
                ^m4@1.4.6:
            ^pkg-config@0.9.0:
            ^util-macros

Concretized
--------------------------------
openmpi@2.0.1%pgi@16.5-0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge"+java~mxm~pmi+psm~psm2~slurm~sqlite3+thread_multiple+tm~verbs+vt arch=linux-centos6-x86_64
    ^hwloc@1.11.4%pgi@16.5-0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge" arch=linux-centos6-x86_64
        ^libpciaccess@0.13.4%gcc@6.1.0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge" arch=linux-centos6-x86_64
            ^libtool@2.4.6%gcc@6.1.0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge" arch=linux-centos6-x86_64
                ^m4@1.4.17%gcc@6.1.0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge"+sigsegv arch=linux-centos6-x86_64
                    ^libsigsegv@2.10%gcc@6.1.0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge" arch=linux-centos6-x86_64
            ^pkg-config@0.29.1%gcc@6.1.0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge"+internal_glib arch=linux-centos6-x86_64
            ^util-macros@1.19.0%gcc@6.1.0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge" arch=linux-centos6-x86_64
    ^jdk@8u92-linux-x64%pgi@16.5-0 cflags="-tp=haswell,sandybridge" cxxflags="-tp=haswell,sandybridge" fflags="-tp=haswell,sandybridge" arch=linux-centos6-x86_64
```
The problem is that although Spack will now correctly build libpciaccess and its dependencies with GCC, it is still trying to use the PGI compiler flags, which will fail.


Discussion:
@becker33: can you look at this one?
I offered to take a look at this issue. I intend to have a PR for it by the end of 3/9

Resolving patch:
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -377,41 +377,26 @@ def concretize_compiler_flags(self, spec):
             # running.
             return True
 
+        compiler_match = lambda other: (
+            spec.compiler == other.compiler and
+            spec.architecture == other.architecture)
+
         ret = False
         for flag in spack.spec.FlagMap.valid_compiler_flags():
+            if flag not in spec.compiler_flags:
+                spec.compiler_flags[flag] = list()
             try:
                 nearest = next(p for p in spec.traverse(direction='parents')
-                               if ((p.compiler == spec.compiler and
-                                    p is not spec) and
+                               if (compiler_match(p) and
+                                   (p is not spec) and
                                    flag in p.compiler_flags))
-                if flag not in spec.compiler_flags or \
-                        not (sorted(spec.compiler_flags[flag]) >=
-                             sorted(nearest.compiler_flags[flag])):
-                    if flag in spec.compiler_flags:
-                        spec.compiler_flags[flag] = list(
-                            set(spec.compiler_flags[flag]) |
-                            set(nearest.compiler_flags[flag]))
-                    else:
-                        spec.compiler_flags[
-                            flag] = nearest.compiler_flags[flag]
+                nearest_flags = set(nearest.compiler_flags.get(flag, []))
+                flags = set(spec.compiler_flags.get(flag, []))
+                if (nearest_flags - flags):
+                    spec.compiler_flags[flag] = list(nearest_flags | flags)
                     ret = True
-
             except StopIteration:
-                if (flag in spec.root.compiler_flags and
-                    ((flag not in spec.compiler_flags) or
-                     sorted(spec.compiler_flags[flag]) !=
-                     sorted(spec.root.compiler_flags[flag]))):
-                    if flag in spec.compiler_flags:
-                        spec.compiler_flags[flag] = list(
-                            set(spec.compiler_flags[flag]) |
-                            set(spec.root.compiler_flags[flag]))
-                    else:
-                        spec.compiler_flags[
-                            flag] = spec.root.compiler_flags[flag]
-                    ret = True
-                else:
-                    if flag not in spec.compiler_flags:
-                        spec.compiler_flags[flag] = []
+                pass
 
         # Include the compiler flag defaults from the config files
         # This ensures that spack will detect conflicts that stem from a change
@@ -419,19 +404,11 @@ def concretize_compiler_flags(self, spec):
         compiler = spack.compilers.compiler_for_spec(
             spec.compiler, spec.architecture)
         for flag in compiler.flags:
-            if flag not in spec.compiler_flags:
-                spec.compiler_flags[flag] = compiler.flags[flag]
-                if compiler.flags[flag] != []:
-                    ret = True
-            else:
-                if ((sorted(spec.compiler_flags[flag]) !=
-                     sorted(compiler.flags[flag])) and
-                    (not set(spec.compiler_flags[flag]) >=
-                     set(compiler.flags[flag]))):
-                    ret = True
-                    spec.compiler_flags[flag] = list(
-                        set(spec.compiler_flags[flag]) |
-                        set(compiler.flags[flag]))
+            config_flags = set(compiler.flags.get(flag, []))
+            flags = set(spec.compiler_flags.get(flag, []))
+            spec.compiler_flags[flag] = list(config_flags | flags)
+            if (config_flags - flags):
+                ret = True
 
         return ret
 


Test patch:
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -175,6 +175,16 @@ def test_provides_handles_multiple_providers_of_same_vesrion(self):
         assert Spec('builtin.mock.multi-provider-mpi@1.10.0') in providers
         assert Spec('builtin.mock.multi-provider-mpi@1.8.8') in providers
 
+    def test_different_compilers_get_different_flags(self):
+        client = Spec('cmake-client %gcc@4.7.2 platform=test os=fe target=fe' +
+                      ' ^cmake %clang@3.5 platform=test os=fe target=fe')
+        client.concretize()
+        cmake = client['cmake']
+        assert set(client.compiler_flags['cflags']) == set(['-O0'])
+        assert set(cmake.compiler_flags['cflags']) == set(['-O3'])
+        assert set(client.compiler_flags['fflags']) == set(['-O0'])
+        assert not set(cmake.compiler_flags['fflags'])
+
     def concretize_multi_provider(self):
         s = Spec('mpileaks ^multi-provider-mpi@3.0')
         s.concretize()