From c756d06fbb54651c2ba19f7801885018c1c389df Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Tue, 25 Jun 2019 21:00:58 -0400 Subject: [PATCH 1/4] add clang c_std=c18 alias fix unit test skips for clang c18 correct unittests clang minimum version cleanup unittest clang skip c_std finesse unittest vs. clang version --- mesonbuild/compilers/c.py | 11 +++++---- mesonbuild/mesonlib.py | 6 ++--- run_unittests.py | 48 +++++++++++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 3b58a076d1b7..fb2f8c5bd10c 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -89,13 +89,16 @@ def get_options(self): opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] - if self.compiler_type is CompilerType.CLANG_OSX: - v = '>=10.0.0' - else: - v = '>=7.0.0' + # https://releases.llvm.org/6.0.0/tools/clang/docs/ReleaseNotes.html + # https://en.wikipedia.org/wiki/Xcode#Latest_versions + v = '>=10.0.0' if self.compiler_type is CompilerType.CLANG_OSX else '>=6.0.0' if version_compare(self.version, v): c_stds += ['c17'] 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', ['none'] + c_stds + g_stds, 'none')}) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index d052a2b690c9..485a0e15393a 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -574,7 +574,7 @@ def __cmp(self, other, comparator): # otherwise, the version with a suffix remaining is greater return comparator(len(self._v), len(other._v)) -def _version_extract_cmpop(vstr2): +def _version_extract_cmpop(vstr2: str) -> tuple: if vstr2.startswith('>='): cmpop = operator.ge vstr2 = vstr2[2:] @@ -601,7 +601,7 @@ def _version_extract_cmpop(vstr2): return (cmpop, vstr2) -def version_compare(vstr1, vstr2): +def version_compare(vstr1: str, vstr2: str) -> bool: (cmpop, vstr2) = _version_extract_cmpop(vstr2) return cmpop(Version(vstr1), Version(vstr2)) @@ -619,7 +619,7 @@ def version_compare_many(vstr1, conditions): # determine if the minimum version satisfying the condition |condition| exceeds # the minimum version for a feature |minimum| -def version_compare_condition_with_min(condition, minimum): +def version_compare_condition_with_min(condition, minimum) -> bool: if condition.startswith('>='): cmpop = operator.le condition = condition[2:] diff --git a/run_unittests.py b/run_unittests.py index 214def16013c..3357ed38a268 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4545,19 +4545,43 @@ def test_compiler_check_flags_order(self): def _test_stds_impl(self, testdir, compiler, p): lang_std = p + '_std' - # Check that all the listed -std=xxx options for this compiler work - # just fine when used + clangLT5 = (compiler.get_id() == 'clang' and + (version_compare(compiler.version, '<5.0.0') or + (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))) + clangLT6 = (compiler.get_id() == 'clang' and + (version_compare(compiler.version, '<6.0.0') or + (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<10.0')))) + clangLT8 = (compiler.get_id() == 'clang' and + (version_compare(compiler.version, '<8.0.0') or + (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<11.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: - if (compiler.get_id() == 'clang' and '17' in v and - (version_compare(compiler.version, '<5.0.0') or - (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))): - continue - if (compiler.get_id() == 'clang' and '2a' in v and - (version_compare(compiler.version, '<6.0.0') or - (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))): - continue - if (compiler.get_id() == 'gcc' and '2a' in v and version_compare(compiler.version, '<8.0.0')): - continue + # we do it like this to handle gnu++17,c++17 and gnu17,c17 cleanly + # thus, C++ first + if '++17' in v: + if clangLT5: + continue + if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<5.0.0'): + continue + elif '++2a' in v: + # https://en.cppreference.com/w/cpp/compiler_support + if clangLT6: + continue + if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<8.0.0'): + continue + # now C + elif '17' in v: + if clangLT6: + continue + if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<8.0.0'): + continue + elif '18' in v: + if clangLT8: + continue + if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<8.0.0'): + continue std_opt = '{}={}'.format(lang_std, v) self.init(testdir, extra_args=['-D' + std_opt]) cmd = self.get_compdb()[0]['command'] From 8e0acae4390f13aa6ec4f8c5a07720e44c832e06 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Mon, 8 Jul 2019 08:34:36 -0400 Subject: [PATCH 2/4] type hints @dcbaker --- mesonbuild/mesonlib.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 485a0e15393a..585a5bb2d311 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -14,7 +14,6 @@ """A library of random helper functionality.""" from pathlib import Path -from typing import List import sys import stat import time @@ -259,7 +258,7 @@ def absolute_path(self, srcdir: str, builddir: str) -> str: def endswith(self, ending: str) -> bool: 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) def __eq__(self, other) -> bool: @@ -463,7 +462,7 @@ def is_dragonflybsd() -> bool: def is_freebsd() -> bool: return platform.system().lower() == 'freebsd' -def exe_exists(arglist: List[str]) -> bool: +def exe_exists(arglist: typing.List[str]) -> bool: try: if subprocess.run(arglist, timeout=10).returncode == 0: return True @@ -574,7 +573,7 @@ def __cmp(self, other, comparator): # otherwise, the version with a suffix remaining is greater return comparator(len(self._v), len(other._v)) -def _version_extract_cmpop(vstr2: str) -> tuple: +def _version_extract_cmpop(vstr2: str) -> typing.Tuple[typing.Callable[[typing.Any, typing.Any], bool], str]: if vstr2.startswith('>='): cmpop = operator.ge vstr2 = vstr2[2:] @@ -619,7 +618,7 @@ def version_compare_many(vstr1, conditions): # determine if the minimum version satisfying the condition |condition| exceeds # the minimum version for a feature |minimum| -def version_compare_condition_with_min(condition, minimum) -> bool: +def version_compare_condition_with_min(condition: str, minimum: str) -> bool: if condition.startswith('>='): cmpop = operator.le condition = condition[2:] @@ -682,7 +681,7 @@ def default_libexecdir(): def default_prefix(): return 'c:/' if is_windows() else '/usr/local' -def get_library_dirs() -> List[str]: +def get_library_dirs() -> typing.List[str]: if is_windows(): return ['C:/mingw/lib'] # TODO: get programatically if is_osx(): From 763b05e074c4eaad8e6b3124ea283d890f63d185 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Mon, 8 Jul 2019 09:19:08 -0400 Subject: [PATCH 3/4] cleanup clang version minimum --- run_unittests.py | 82 ++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index 3357ed38a268..e596a34dc2c9 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -279,6 +279,7 @@ class PatchModule: Fancy monkey-patching! Whee! Can't use mock.patch because it only patches in the local namespace. ''' + def __init__(self, func, name, impl): self.func = func assert(isinstance(name, str)) @@ -1483,6 +1484,7 @@ class AllPlatformTests(BasePlatformTests): ''' Tests that should run on all platforms ''' + def test_default_options_prefix(self): ''' Tests that setting a prefix in default_options in project() works. @@ -4042,6 +4044,7 @@ class WindowsTests(BasePlatformTests): ''' Tests that should run on Cygwin, MinGW, and MSVC ''' + def setUp(self): super().setUp() self.platform_test_dir = os.path.join(self.src_root, 'test cases/windows') @@ -4156,6 +4159,7 @@ class DarwinTests(BasePlatformTests): ''' Tests that should run on macOS ''' + def setUp(self): super().setUp() self.platform_test_dir = os.path.join(self.src_root, 'test cases/osx') @@ -4255,6 +4259,7 @@ class LinuxlikeTests(BasePlatformTests): ''' Tests that should run on Linux, macOS, and *BSD ''' + def test_basic_soname(self): ''' Test that the soname is set correctly for shared libraries. This can't @@ -4543,45 +4548,33 @@ def test_compiler_check_flags_order(self): Oargs = [arg for arg in cmd if arg.startswith('-O')] 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' - clangLT5 = (compiler.get_id() == 'clang' and - (version_compare(compiler.version, '<5.0.0') or - (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))) - clangLT6 = (compiler.get_id() == 'clang' and - (version_compare(compiler.version, '<6.0.0') or - (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<10.0')))) - clangLT8 = (compiler.get_id() == 'clang' and - (version_compare(compiler.version, '<8.0.0') or - (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<11.0')))) + + 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: # we do it like this to handle gnu++17,c++17 and gnu17,c17 cleanly # thus, C++ first - if '++17' in v: - if clangLT5: - continue - if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<5.0.0'): - continue - elif '++2a' in v: - # https://en.cppreference.com/w/cpp/compiler_support - if clangLT6: - continue - if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<8.0.0'): - continue + if '++17' in v and not has_cpp17: + continue + elif '++2a' in v and not has_cpp2a_c17: # https://en.cppreference.com/w/cpp/compiler_support + continue # now C - elif '17' in v: - if clangLT6: - continue - if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<8.0.0'): - continue - elif '18' in v: - if clangLT8: - continue - if compiler.get_id() == 'gcc' and version_compare(compiler.version, '<8.0.0'): - continue + elif '17' in v and not has_cpp2a_c17: + continue + elif '18' in v and not has_c18: + continue std_opt = '{}={}'.format(lang_std, v) self.init(testdir, extra_args=['-D' + std_opt]) cmd = self.get_compdb()[0]['command'] @@ -5337,6 +5330,7 @@ class LinuxCrossArmTests(BasePlatformTests): ''' Tests that cross-compilation to Linux/ARM works ''' + def setUp(self): super().setUp() src_root = os.path.dirname(__file__) @@ -5396,6 +5390,7 @@ class LinuxCrossMingwTests(BasePlatformTests): ''' Tests that cross-compilation to Windows/MinGW works ''' + def setUp(self): super().setUp() src_root = os.path.dirname(__file__) @@ -5449,6 +5444,7 @@ class PythonTests(BasePlatformTests): ''' Tests that verify compilation of python extension modules ''' + def test_versions(self): if self.backend is not Backend.ninja: raise unittest.SkipTest('Skipping python tests with {} backend'.format(self.backend.name)) @@ -6493,6 +6489,30 @@ def test_yaml(self): self.assert_test(events, number=2, name='', result=TestResult.FAIL) 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(): # For unit tests we must fully control all command lines # so that there are no unexpected changes coming from the From 2dc11bcb53e794dc37b71ed4e4d00b9fa27742d3 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Mon, 8 Jul 2019 22:33:34 -0400 Subject: [PATCH 4/4] typo --- run_unittests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index e596a34dc2c9..dbfe16d5e399 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4551,13 +4551,13 @@ def test_compiler_check_flags_order(self): def _test_stds_impl(self, testdir, compiler, p: str): lang_std = p + '_std' - has_cpp17 = (compiler.get_Id() not in {'clang', 'gcc'} or + 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 + 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 + 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