Merge pull request #5560 from scivision/cstd18_bug

add clang c_std=c18 alias and cleanup logic for compiler version unit tests
pull/5641/head
Michael Hirsch, Ph.D 5 years ago committed by GitHub
commit d5cb1c2f19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      mesonbuild/compilers/c.py
  2. 13
      mesonbuild/mesonlib.py
  3. 64
      run_unittests.py

@ -89,13 +89,16 @@ class ClangCCompiler(ClangCompiler, CCompiler):
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
c_stds = ['c89', 'c99', 'c11'] c_stds = ['c89', 'c99', 'c11']
g_stds = ['gnu89', 'gnu99', 'gnu11'] g_stds = ['gnu89', 'gnu99', 'gnu11']
if self.compiler_type is CompilerType.CLANG_OSX: # https://releases.llvm.org/6.0.0/tools/clang/docs/ReleaseNotes.html
v = '>=10.0.0' # https://en.wikipedia.org/wiki/Xcode#Latest_versions
else: v = '>=10.0.0' if self.compiler_type is CompilerType.CLANG_OSX else '>=6.0.0'
v = '>=7.0.0'
if version_compare(self.version, v): if version_compare(self.version, v):
c_stds += ['c17'] c_stds += ['c17']
g_stds += ['gnu17'] g_stds += ['gnu17']
v = '>=11.0.0' if self.compiler_type is CompilerType.CLANG_OSX else '>=8.0.0'
if version_compare(self.version, v):
c_stds += ['c18']
g_stds += ['gnu18']
opts.update({'c_std': coredata.UserComboOption('C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none'] + c_stds + g_stds, ['none'] + c_stds + g_stds,
'none')}) 'none')})

@ -14,7 +14,6 @@
"""A library of random helper functionality.""" """A library of random helper functionality."""
from pathlib import Path from pathlib import Path
from typing import List
import sys import sys
import stat import stat
import time import time
@ -259,7 +258,7 @@ class File:
def endswith(self, ending: str) -> bool: def endswith(self, ending: str) -> bool:
return self.fname.endswith(ending) return self.fname.endswith(ending)
def split(self, s: str) -> List[str]: def split(self, s: str) -> typing.List[str]:
return self.fname.split(s) return self.fname.split(s)
def __eq__(self, other) -> bool: def __eq__(self, other) -> bool:
@ -463,7 +462,7 @@ def is_dragonflybsd() -> bool:
def is_freebsd() -> bool: def is_freebsd() -> bool:
return platform.system().lower() == 'freebsd' return platform.system().lower() == 'freebsd'
def exe_exists(arglist: List[str]) -> bool: def exe_exists(arglist: typing.List[str]) -> bool:
try: try:
if subprocess.run(arglist, timeout=10).returncode == 0: if subprocess.run(arglist, timeout=10).returncode == 0:
return True return True
@ -574,7 +573,7 @@ class Version:
# otherwise, the version with a suffix remaining is greater # otherwise, the version with a suffix remaining is greater
return comparator(len(self._v), len(other._v)) return comparator(len(self._v), len(other._v))
def _version_extract_cmpop(vstr2): def _version_extract_cmpop(vstr2: str) -> typing.Tuple[typing.Callable[[typing.Any, typing.Any], bool], str]:
if vstr2.startswith('>='): if vstr2.startswith('>='):
cmpop = operator.ge cmpop = operator.ge
vstr2 = vstr2[2:] vstr2 = vstr2[2:]
@ -601,7 +600,7 @@ def _version_extract_cmpop(vstr2):
return (cmpop, vstr2) return (cmpop, vstr2)
def version_compare(vstr1, vstr2): def version_compare(vstr1: str, vstr2: str) -> bool:
(cmpop, vstr2) = _version_extract_cmpop(vstr2) (cmpop, vstr2) = _version_extract_cmpop(vstr2)
return cmpop(Version(vstr1), Version(vstr2)) return cmpop(Version(vstr1), Version(vstr2))
@ -619,7 +618,7 @@ def version_compare_many(vstr1, conditions):
# determine if the minimum version satisfying the condition |condition| exceeds # determine if the minimum version satisfying the condition |condition| exceeds
# the minimum version for a feature |minimum| # the minimum version for a feature |minimum|
def version_compare_condition_with_min(condition, minimum): def version_compare_condition_with_min(condition: str, minimum: str) -> bool:
if condition.startswith('>='): if condition.startswith('>='):
cmpop = operator.le cmpop = operator.le
condition = condition[2:] condition = condition[2:]
@ -682,7 +681,7 @@ def default_libexecdir():
def default_prefix(): def default_prefix():
return 'c:/' if is_windows() else '/usr/local' return 'c:/' if is_windows() else '/usr/local'
def get_library_dirs() -> List[str]: def get_library_dirs() -> typing.List[str]:
if is_windows(): if is_windows():
return ['C:/mingw/lib'] # TODO: get programatically return ['C:/mingw/lib'] # TODO: get programatically
if is_osx(): if is_osx():

@ -279,6 +279,7 @@ class PatchModule:
Fancy monkey-patching! Whee! Can't use mock.patch because it only Fancy monkey-patching! Whee! Can't use mock.patch because it only
patches in the local namespace. patches in the local namespace.
''' '''
def __init__(self, func, name, impl): def __init__(self, func, name, impl):
self.func = func self.func = func
assert(isinstance(name, str)) assert(isinstance(name, str))
@ -1483,6 +1484,7 @@ class AllPlatformTests(BasePlatformTests):
''' '''
Tests that should run on all platforms Tests that should run on all platforms
''' '''
def test_default_options_prefix(self): def test_default_options_prefix(self):
''' '''
Tests that setting a prefix in default_options in project() works. Tests that setting a prefix in default_options in project() works.
@ -4055,6 +4057,7 @@ class WindowsTests(BasePlatformTests):
''' '''
Tests that should run on Cygwin, MinGW, and MSVC Tests that should run on Cygwin, MinGW, and MSVC
''' '''
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.platform_test_dir = os.path.join(self.src_root, 'test cases/windows') self.platform_test_dir = os.path.join(self.src_root, 'test cases/windows')
@ -4169,6 +4172,7 @@ class DarwinTests(BasePlatformTests):
''' '''
Tests that should run on macOS Tests that should run on macOS
''' '''
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.platform_test_dir = os.path.join(self.src_root, 'test cases/osx') self.platform_test_dir = os.path.join(self.src_root, 'test cases/osx')
@ -4268,6 +4272,7 @@ class LinuxlikeTests(BasePlatformTests):
''' '''
Tests that should run on Linux, macOS, and *BSD Tests that should run on Linux, macOS, and *BSD
''' '''
def test_basic_soname(self): def test_basic_soname(self):
''' '''
Test that the soname is set correctly for shared libraries. This can't Test that the soname is set correctly for shared libraries. This can't
@ -4556,20 +4561,32 @@ class LinuxlikeTests(BasePlatformTests):
Oargs = [arg for arg in cmd if arg.startswith('-O')] Oargs = [arg for arg in cmd if arg.startswith('-O')]
self.assertEqual(Oargs, [Oflag, '-O0']) self.assertEqual(Oargs, [Oflag, '-O0'])
def _test_stds_impl(self, testdir, compiler, p): def _test_stds_impl(self, testdir, compiler, p: str):
lang_std = p + '_std' lang_std = p + '_std'
# Check that all the listed -std=xxx options for this compiler work
# just fine when used has_cpp17 = (compiler.get_id() not in {'clang', 'gcc'} or
compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=5.0.0', '>=9.1') or
compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=5.0.0'))
has_cpp2a_c17 = (compiler.get_id() not in {'clang', 'gcc'} or
compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=6.0.0', '>=10.0') or
compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=8.0.0'))
has_c18 = (compiler.get_id() not in {'clang', 'gcc'} or
compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=8.0.0', '>=11.0') or
compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=8.0.0'))
# Check that all the listed -std=xxx options for this compiler work just fine when used
# https://en.wikipedia.org/wiki/Xcode#Latest_versions
# https://www.gnu.org/software/gcc/projects/cxx-status.html
for v in compiler.get_options()[lang_std].choices: for v in compiler.get_options()[lang_std].choices:
if (compiler.get_id() == 'clang' and '17' in v and # we do it like this to handle gnu++17,c++17 and gnu17,c17 cleanly
(version_compare(compiler.version, '<5.0.0') or # thus, C++ first
(compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))): if '++17' in v and not has_cpp17:
continue continue
if (compiler.get_id() == 'clang' and '2a' in v and elif '++2a' in v and not has_cpp2a_c17: # https://en.cppreference.com/w/cpp/compiler_support
(version_compare(compiler.version, '<6.0.0') or
(compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))):
continue continue
if (compiler.get_id() == 'gcc' and '2a' in v and version_compare(compiler.version, '<8.0.0')): # now C
elif '17' in v and not has_cpp2a_c17:
continue
elif '18' in v and not has_c18:
continue continue
std_opt = '{}={}'.format(lang_std, v) std_opt = '{}={}'.format(lang_std, v)
self.init(testdir, extra_args=['-D' + std_opt]) self.init(testdir, extra_args=['-D' + std_opt])
@ -5326,6 +5343,7 @@ class LinuxCrossArmTests(BasePlatformTests):
''' '''
Tests that cross-compilation to Linux/ARM works Tests that cross-compilation to Linux/ARM works
''' '''
def setUp(self): def setUp(self):
super().setUp() super().setUp()
src_root = os.path.dirname(__file__) src_root = os.path.dirname(__file__)
@ -5385,6 +5403,7 @@ class LinuxCrossMingwTests(BasePlatformTests):
''' '''
Tests that cross-compilation to Windows/MinGW works Tests that cross-compilation to Windows/MinGW works
''' '''
def setUp(self): def setUp(self):
super().setUp() super().setUp()
src_root = os.path.dirname(__file__) src_root = os.path.dirname(__file__)
@ -5438,6 +5457,7 @@ class PythonTests(BasePlatformTests):
''' '''
Tests that verify compilation of python extension modules Tests that verify compilation of python extension modules
''' '''
def test_versions(self): def test_versions(self):
if self.backend is not Backend.ninja: if self.backend is not Backend.ninja:
raise unittest.SkipTest('Skipping python tests with {} backend'.format(self.backend.name)) raise unittest.SkipTest('Skipping python tests with {} backend'.format(self.backend.name))
@ -6482,6 +6502,30 @@ class TAPParserTests(unittest.TestCase):
self.assert_test(events, number=2, name='', result=TestResult.FAIL) self.assert_test(events, number=2, name='', result=TestResult.FAIL)
self.assert_last(events) self.assert_last(events)
def _clang_at_least(compiler, minver: str, apple_minver: str) -> bool:
"""
check that Clang compiler is at least a specified version, whether AppleClang or regular Clang
Parameters
----------
compiler:
Meson compiler object
minver: str
Clang minimum version
apple_minver: str
AppleCLang minimum version
Returns
-------
at_least: bool
Clang is at least the specified version
"""
if compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX:
return version_compare(compiler.version, apple_minver)
return version_compare(compiler.version, minver)
def unset_envs(): def unset_envs():
# For unit tests we must fully control all command lines # For unit tests we must fully control all command lines
# so that there are no unexpected changes coming from the # so that there are no unexpected changes coming from the

Loading…
Cancel
Save