Make `-std=` fallback remapping more robust

* The current version matching logic is brittle
  with respect to Clang. LLVM and Apple Clang use
  slightly different but nowadays overlapping
  version ranges. Instead, we now just check whether
  the compiler supports the given `-std=` variant
  and try its respective fallback instead of
  testing version ranges.
pull/4099/head
David Seifert 7 years ago committed by Jussi Pakkanen
parent cc37a66077
commit 28c1f31d7e
  1. 65
      mesonbuild/compilers/cpp.py

@ -12,10 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import os.path
from .. import coredata
from ..mesonlib import version_compare
from .. import mlog
from ..mesonlib import MesonException, version_compare
from .c import CCompiler, VisualStudioCCompiler
from .compilers import (
@ -67,6 +69,55 @@ class CPPCompiler(CCompiler):
int main () {{ return 0; }}'''
return self.compiles(t.format(**fargs), env, extra_args, dependencies)
def _test_cpp_std_arg(self, cpp_std_value):
# Test whether the compiler understands a -std=XY argument
assert(cpp_std_value.startswith('-std='))
# This test does not use has_multi_arguments() for two reasons:
# 1. has_multi_arguments() requires an env argument, which the compiler
# object does not have at this point.
# 2. even if it did have an env object, that might contain another more
# recent -std= argument, which might lead to a cascaded failure.
CPP_TEST = 'int i = static_cast<int>(0);'
with self.compile(code=CPP_TEST, extra_args=[cpp_std_value], mode='compile') as p:
if p.returncode == 0:
mlog.debug('Compiler accepts {}:'.format(cpp_std_value), 'YES')
return True
else:
mlog.debug('Compiler accepts {}:'.format(cpp_std_value), 'NO')
return False
@functools.lru_cache()
def _find_best_cpp_std(self, cpp_std):
# The initial version mapping approach to make falling back
# from '-std=c++14' to '-std=c++1y' was too brittle. For instance,
# Apple's Clang uses a different versioning scheme to upstream LLVM,
# making the whole detection logic awfully brittle. Instead, let's
# just see if feeding GCC or Clang our '-std=' setting works, and
# if not, try the fallback argument.
CPP_FALLBACKS = {
'c++11': 'c++0x',
'gnu++11': 'gnu++0x',
'c++14': 'c++1y',
'gnu++14': 'gnu++1y',
'c++17': 'c++1z',
'gnu++17': 'gnu++1z'
}
# Currently, remapping is only supported for Clang and GCC
assert(self.id in frozenset(['clang', 'gcc']))
if cpp_std not in CPP_FALLBACKS:
# 'c++03' and 'c++98' don't have fallback types
return '-std=' + cpp_std
for i in (cpp_std, CPP_FALLBACKS[cpp_std]):
cpp_std_value = '-std=' + i
if self._test_cpp_std_arg(cpp_std_value):
return cpp_std_value
raise MesonException('C++ Compiler does not support -std={}'.format(cpp_std))
class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None, **kwargs):
@ -89,11 +140,7 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
args = []
std = options['cpp_std']
if std.value != 'none':
cpp_std_value = std.value
# Clang 3.2, 3.3, 3.4 only understand -std={c,gnu}++1y and not -std={c,gnu}++14
if version_compare(self.version, '>=3.2') and version_compare(self.version, '<3.5'):
cpp_std_value = cpp_std_value.replace('++14', '++1y')
args.append('-std=' + cpp_std_value)
args.append(self._find_best_cpp_std(std.value))
return args
def get_option_link_args(self, options):
@ -159,11 +206,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
args = []
std = options['cpp_std']
if std.value != 'none':
cpp_std_value = std.value
# GCC 4.8 only understands -std={c,gnu}++1y and not -std={c,gnu}++14
if version_compare(self.version, '>=4.8') and version_compare(self.version, '<4.9'):
cpp_std_value = cpp_std_value.replace('++14', '++1y')
args.append('-std=' + cpp_std_value)
args.append(self._find_best_cpp_std(std.value))
if options['cpp_debugstl'].value:
args.append('-D_GLIBCXX_DEBUG=1')
return args

Loading…
Cancel
Save