diff options
-rw-r--r-- | mesonbuild/compilers/cpp.py | 65 |
1 files changed, 54 insertions, 11 deletions
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index d8203dd..85766f7 100644 --- a/mesonbuild/compilers/cpp.py +++ b/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 |