Fix ABI detection issues with macOS gcc. (#3854)

- gcc on macOS says it's version 4.2.1, but it's really clang, and it's
  actually the *same* clang as the system clang.

- It also doesn't respond with a full path when called with
  --print-file-name=libstdc++.dylib, which is expected from gcc in abi.py.
  Instead, it gives a relative path and _gcc_compiler_compare doesn't
  understand what to do with it.  This results in errors like:

  ```
  lib/spack/spack/abi.py, line 71, in _gcc_get_libstdcxx_version
      libpath = os.readlink(output.strip())
  OSError: [Errno 2] No such file or directory: 'libstdc++.dylib'
  ```

- This commit does two things:

  1. Ignore any gcc that's actually clang in abi.py.  We can probably do
     better than this, but it's not clear there is a need to, since we
     should handle the compiler as clang, not gcc.

  2. Don't auto-detect any "gcc" that is actually clang anymore.  Ignore
     it and expect people to use clang (which is the default macOS
     compiler anyway).

Users can still add fake gccs to their compilers.yaml if they want, but
it's discouraged.
This commit is contained in:
Todd Gamblin 2017-04-21 15:45:12 -07:00 committed by GitHub
parent 63c3410370
commit c67f8e4aa1
4 changed files with 23 additions and 7 deletions

View File

@ -29,6 +29,7 @@
from spack.build_environment import dso_suffix
from spack.spec import CompilerSpec
from spack.util.executable import Executable, ProcessError
from spack.compilers.clang import Clang
from llnl.util.lang import memoized
@ -44,7 +45,7 @@ def architecture_compatible(self, parent, child):
@memoized
def _gcc_get_libstdcxx_version(self, version):
"""Returns gcc ABI compatibility info by getting the library version of
a compiler's libstdc++.so or libgcc_s.so"""
a compiler's libstdc++ or libgcc_s"""
spec = CompilerSpec("gcc", version)
compilers = spack.compilers.compilers_for_spec(spec)
if not compilers:
@ -62,6 +63,12 @@ def _gcc_get_libstdcxx_version(self, version):
else:
return None
try:
# Some gcc's are actually clang and don't respond properly to
# --print-file-name (they just print the filename, not the
# full path). Ignore these and expect them to be handled as clang.
if Clang.default_version(rungcc.exe[0]) != 'unknown':
return None
output = rungcc("--print-file-name=%s" % libname,
return_output=True)
except ProcessError:

View File

@ -49,14 +49,15 @@ def _verify_executables(*paths):
def get_compiler_version(compiler_path, version_arg, regex='(.*)'):
if compiler_path not in _version_cache:
key = (compiler_path, version_arg, regex)
if key not in _version_cache:
compiler = Executable(compiler_path)
output = compiler(version_arg, output=str, error=str)
match = re.search(regex, output)
_version_cache[compiler_path] = match.group(1) if match else 'unknown'
_version_cache[key] = match.group(1) if match else 'unknown'
return _version_cache[compiler_path]
return _version_cache[key]
def dumpversion(compiler_path):

View File

@ -87,6 +87,16 @@ def cxx17_flag(self):
def pic_flag(self):
return "-fPIC"
@classmethod
def default_version(cls, cc):
# Skip any gcc versions that are actually clang, like Apple's gcc.
# Returning "unknown" makes them not detected by default.
# Users can add these manually to compilers.yaml at their own risk.
if spack.compilers.clang.Clang.default_version(cc) != 'unknown':
return 'unknown'
return super(Gcc, cls).default_version(cc)
@classmethod
def fc_version(cls, fc):
return get_compiler_version(

View File

@ -89,6 +89,4 @@ def test_compiler_add(self, mock_compiler_dir):
# Ensure new compiler is in there
new_compilers = set(spack.compilers.all_compiler_specs())
new_compiler = new_compilers - old_compilers
assert new_compiler
assert sum(1 for c in new_compiler if
c.version == Version(test_version)) > 0
assert any(c.version == Version(test_version) for c in new_compiler)