Repository: spack/spack

Issue:
Fix libunwind compilation with GCC 10
Compilation is failing on GCC 10 due to changes in default flags.

Apply the patch detailed here: https://github.com/libunwind/libunwind/pull/166 when building on GCC 10+.


Discussion:
Am I missing something obvious here? 
Did y'all actually try building this with gcc 10.x?

I tried adding this (without the conditional)

```
    def setup_build_environment(self):
        env.set('CFLAGS', '-fcommon')
```

And spack install crashed with:

```
==> Error: TypeError: setup_build_environment() takes 1 positional argument but 2 were given
```

>     def setup_build_environment(self):
>         env.set('CFLAGS', '-fcommon')

You are missing the second `env` parameter.

Edit: Oops, sorry, I just noticed that this is missing in @nickrobison-usds's version as well (but was included in my suggestion). @nickrobison-usds please fix this. Thanks!
There is another issue, one that I'm very reluctant to bring up.

By setting `env.set('CFLAGS', '-fcommon')`, configure will see this in
the environment and use exactly `CFLAGS=-fcommon` and drop the `-g -O2`.
That is, spack will build libunwind without optimization.  For a longer
description, see #14430.

Spack doesn't have the tools to handle this cleanly.  You can see how
I worked around this (awkwardly) in libmonitor and intel-xed.

If you like, you can ignore this for now and I'll do something the
next time I add a new version.

And yes, please fix the `self, env` typo/bug.
@mwkrentel what about `env.append_flags('CFLAGS', '-fcommon')`?
I think the problem is that autotools will behave differently depending on whether CFLAGS is set or not. If it is not set at all (which is the case without this modification), autotools will use a sane default. If it is set to anything, it will just use this value.

We could also use `flag_handler`, which seems to set `SPACK_CFLAGS`, which is then set internally by the compiler wrappers.
Just gave this a try. The following also works:
```diff
-    flag_handler = AutotoolsPackage.build_system_flags
+    def flag_handler(self, name, flags):
+        if name == 'cflags':
+            if self.spec.satisfies('@:1.4 %gcc@10:'):
+                flags.append('-fcommon')
+
+        return (flags, None, None)
```
But I am not 100% sure what `flag_handler = AutotoolsPackage.build_system_flags` does and whether this will break something else.

Edit: To clarify, this will set `SPACK_CFLAGS`, which autotools does not pick up and we still get the sane default of `-g -O2`.
Yes, the basic problem is that unset and set to empty are very
different in autotools world.

Note: the triple returned from `flag_handler` is: (1) at the front of
the spack wrapper (inject flags), (2) in the environment, and (3) on
the configure line (build system).  So, `build_system_flags` is the
same as `return (None, None, flags)`.

The problem with putting the flags in the inject flags is that
configure doesn't see them, so autotools will then choose `-g -O2`.
For `-fcommon`, this doesn't matter, but if you wrote `cflags='-O0'`,
then you'd end up with `-O0 -g -O2`.  That's less of a sin, but still
not correct.

I think it may work to put `-fcommon` in inject flags and show the
rest to configure.  Something like:

```
if ...:
    return ('-fcommon', None, flags)
```

Btw, IMO, it's not really necessary to make old versions run with the
newest compilers, especially if that compiler didn't exist at the time
the version was released.  If it already works out of the box for
1.5-rc1, then if it were me, I'd just do nothing, or else add a conflict.
> Btw, IMO, it's not really necessary to make old versions run with the
> newest compilers, especially if that compiler didn't exist at the time
> the version was released. If it already works out of the box for
> 1.5-rc1, then if it were me, I'd just do nothing, or else add a conflict.

Agreed, but since we prefer version 1.4.0 at the moment, that makes for a bad out-of-the-box experience in my opinion. I think at least the default versions should compile with the current compiler so users can just do `spack install something` without having to figure out that they should manually specify a newer version of a certain package.
Ok, fair enough.  I forgot that we don't count 1.5-rc1 as a "real"
release, even though I'm the one that set preferred.  :-)
I've verified that the following seems to do what we want:
```diff
-    flag_handler = AutotoolsPackage.build_system_flags
+    def flag_handler(self, name, flags):
+        wrapper_flags = None
+
+        if name == 'cflags':
+            # https://github.com/libunwind/libunwind/pull/166
+            if self.spec.satisfies('@:1.4 %gcc@10:'):
+                wrapper_flags = ['-fcommon']
+
+        return (wrapper_flags, None, flags)
```

@nickrobison-usds Sorry for hijacking this PR. :smile:
Yes, I believe that should work.  I approve.
I think this is a good idiom for handling this situation,
at least for the state of spack today.

@michaelkuhn It's up to you, but if you want to add yourself as
another maintainer, feel free.

Resolving patch:
diff --git a/var/spack/repos/builtin/packages/libunwind/package.py b/var/spack/repos/builtin/packages/libunwind/package.py
--- a/var/spack/repos/builtin/packages/libunwind/package.py
+++ b/var/spack/repos/builtin/packages/libunwind/package.py
@@ -47,7 +47,15 @@ class Libunwind(AutotoolsPackage):
 
     provides('unwind')
 
-    flag_handler = AutotoolsPackage.build_system_flags
+    def flag_handler(self, name, flags):
+        wrapper_flags = None
+
+        if name == 'cflags':
+            # https://github.com/libunwind/libunwind/pull/166
+            if self.spec.satisfies('@:1.4 %gcc@10:'):
+                wrapper_flags = ['-fcommon']
+
+        return (wrapper_flags, None, flags)
 
     def configure_args(self):
         spec = self.spec


Test patch: