diff options
31 files changed, 250 insertions, 102 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 3a21cef..6be3ed7 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -131,7 +131,7 @@ This function creates a new top-level target. Like all top-level targets, this integrates with the selected backend. For instance, with Ninja you can run it as `ninja target_name`. This is a dummy target that does not execute any command, but ensures that all dependencies are built. Dependencies can be any -build target (e.g. return value of executable(), custom_target(), etc) +build target (e.g. return value of [executable()](#executable), custom_target(), etc) ### assert() @@ -586,7 +586,7 @@ be passed to [shared and static libraries](#library). - `include_directories` one or more objects created with the `include_directories` function, or, since 0.50.0, strings, which will be transparently expanded to include directory objects -- `install`, when set to true, this executable should be installed +- `install`, when set to true, this executable should be installed, defaults to `false` - `install_dir` override install directory for this file. The value is relative to the `prefix` specified. F.ex, if you want to install plugins into a subdir, you'd use something like this: `install_dir : @@ -1794,6 +1794,7 @@ are immutable, all operations return their results as a new string. - `is_even()` returns true if the number is even - `is_odd()` returns true if the number is odd + - `to_string()` returns the value of the number as a string. ### `boolean` object @@ -2225,7 +2226,7 @@ an external dependency with the following methods: - sources: any compiled or static sources the dependency has - `get_variable(cmake : str, pkgconfig : str, configtool : str, - default_value : str, pkgconfig_define : [str, str]) *(Added in + default_value : str, pkgconfig_define : [str, str])` *(Added in 0.51.0)* A generic variable getter method, which repalces the get_*type*_variable methods. This allows one to get the variable from a dependency without knowing specifically how that dependency @@ -2253,7 +2254,7 @@ and has the following methods: - `path()` which returns a string pointing to the script or executable **NOTE:** You should not need to use this method. Passing the object - itself should work in all cases. F.ex.: `run_command(obj, arg1, arg2)` + itself should work in all cases. For example: `run_command(obj, arg1, arg2)` ### `environment` object diff --git a/docs/markdown/Release-notes-for-0.51.0.md b/docs/markdown/Release-notes-for-0.51.0.md index 86b2f70..b7e441c 100644 --- a/docs/markdown/Release-notes-for-0.51.0.md +++ b/docs/markdown/Release-notes-for-0.51.0.md @@ -110,7 +110,7 @@ dependency you have. ```meson dep = dependency('could_be_cmake_or_pkgconfig') # cmake returns 'YES', pkg-config returns 'ON' -if ['YES', 'ON'].contains(dep.get_variable(pkg-config : 'var-name', cmake : 'COP_VAR_NAME', default_value : 'NO')) +if ['YES', 'ON'].contains(dep.get_variable(pkgconfig : 'var-name', cmake : 'COP_VAR_NAME', default_value : 'NO')) error('Cannot build your project when dep is built with var-name support') endif ``` diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md index 7802b92..24d9deb 100644 --- a/docs/markdown/Syntax.md +++ b/docs/markdown/Syntax.md @@ -78,6 +78,13 @@ string_var = '42' num = string_var.to_int() ``` +Numbers can be converted to a string: + +```meson +int_var = 42 +string_var = int_var.to_string() +``` + Booleans -- diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md index 694c190..3c27732 100644 --- a/docs/markdown/Unit-tests.md +++ b/docs/markdown/Unit-tests.md @@ -71,10 +71,23 @@ The simplest thing to do is just to run all tests, which is equivalent to runnin $ meson test ``` -You can also run only a single test by giving its name: +### Run subsets of tests + +For clarity, consider the meson.build containing: + +```meson + +test('A', ..., suite: 'foo') +test('B', ..., suite: 'foo') +test('C', ..., suite: 'bar') +test('D', ..., suite: 'baz') + +``` + +Specify test(s) by name like: ```console -$ meson test testname +$ meson test A D ``` Tests belonging to a suite `suite` can be run as follows @@ -85,6 +98,18 @@ $ meson test --suite (sub)project_name:suite Since version *0.46*, `(sub)project_name` can be omitted if it is the top-level project. +Multiple suites are specified like: + +```console +$ meson test --suite foo --suite bar +``` + +NOTE: If you choose to specify both suite(s) and specific test name(s), the +test name(s) must be contained in the suite(s). This however is redundant-- +it would be more useful to specify either specific test names or suite(s). + +### Other test options + Sometimes you need to run the tests multiple times, which is done like this: ```console @@ -127,4 +152,8 @@ Meson will report the output produced by the failing tests along with other usef For further information see the command line help of Meson by running `meson test -h`. -**NOTE:** If `meson test` does not work for you, you likely have a old version of Meson. In that case you should call `mesontest` instead. If `mesontest` doesn't work either you have a very old version prior to 0.37.0 and should upgrade. +## Legacy notes + +If `meson test` does not work for you, you likely have a old version of Meson. +In that case you should call `mesontest` instead. If `mesontest` doesn't work +either you have a very old version prior to 0.37.0 and should upgrade. diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index 0e490ab..13c717b 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -325,7 +325,7 @@ class AstInterpreter(interpreterbase.InterpreterBase): for key, val in kwargs.items(): if isinstance(val, ElementaryNode): flattend_kwargs[key] = val.value - elif isinstance(val, (ArrayNode, ArgumentNode)): + elif isinstance(val, (ArrayNode, ArgumentNode, ArithmeticNode, MethodNode)): flattend_kwargs[key] = self.flatten_args(val, include_unknown_args) elif isinstance(val, (str, bool, int, float)) or include_unknown_args: flattend_kwargs[key] = val diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 617b140..aeb0400 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -158,16 +158,20 @@ class IntrospectionInterpreter(AstInterpreter): args = self.flatten_args(args) if not args or not isinstance(args[0], str): return - kwargs = self.flatten_kwargs(kwargs, True) name = args[0] srcqueue = [node] + + # Process the soruces BEFORE flattening the kwargs, to preserve the original nodes if 'sources' in kwargs: - srcqueue += kwargs['sources'] + srcqueue += mesonlib.listify(kwargs['sources']) + + kwargs = self.flatten_kwargs(kwargs, True) source_nodes = [] while srcqueue: curr = srcqueue.pop(0) arg_node = None + assert(isinstance(curr, BaseNode)) if isinstance(curr, FunctionNode): arg_node = curr.args elif isinstance(curr, ArrayNode): diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 44f53eb..6ae2673 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -274,7 +274,6 @@ class PGICPPCompiler(PGICompiler, CPPCompiler): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) PGICompiler.__init__(self, compiler_type) - class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs): GnuCPPCompiler.__init__(self, exelist, version, compiler_type, for_machine, is_cross, exe_wrapper, defines, **kwargs) diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index e417566..c10e2ca 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -321,6 +321,9 @@ class FlangFortranCompiler(ClangCompiler, FortranCompiler): '2': default_warn_args, '3': default_warn_args} + def language_stdlib_only_link_flags(self) -> List[str]: + return ['-lflang', '-lpgmath'] + class Open64FortranCompiler(FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 0591b7f..37d2424 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -209,25 +209,25 @@ class CLikeCompiler: ''' return self.get_compiler_dirs(env, 'programs') - def get_pic_args(self): + def get_pic_args(self) -> typing.List[str]: return ['-fPIC'] - def name_string(self): + def name_string(self) -> str: return ' '.join(self.exelist) - def get_pch_use_args(self, pch_dir, header): + def get_pch_use_args(self, pch_dir: str, header: str) -> typing.List[str]: return ['-include', os.path.basename(header)] - def get_pch_name(self, header_name): + def get_pch_name(self, header_name: str) -> str: return os.path.basename(header_name) + '.' + self.get_pch_suffix() - def get_linker_search_args(self, dirname): + def get_linker_search_args(self, dirname: str) -> typing.List[str]: return ['-L' + dirname] def get_default_include_dirs(self): return [] - def gen_export_dynamic_link_args(self, env): + def gen_export_dynamic_link_args(self, env) -> typing.List[str]: m = env.machines[self.for_machine] if m.is_windows() or m.is_cygwin(): return ['-Wl,--export-all-symbols'] @@ -236,7 +236,7 @@ class CLikeCompiler: else: return ['-Wl,-export-dynamic'] - def gen_import_library_args(self, implibname): + def gen_import_library_args(self, implibname: str) -> typing.List[str]: """ The name of the outputted import library diff --git a/mesonbuild/compilers/mixins/intel.py b/mesonbuild/compilers/mixins/intel.py index f147c4c..7fadb50 100644 --- a/mesonbuild/compilers/mixins/intel.py +++ b/mesonbuild/compilers/mixins/intel.py @@ -22,14 +22,13 @@ import os import typing from ... import mesonlib +from ..compilers import CompilerType from .gnu import GnuLikeCompiler from .visualstudio import VisualStudioLikeCompiler if typing.TYPE_CHECKING: import subprocess # noqa: F401 - from ..compilers import CompilerType - # XXX: avoid circular dependencies # TODO: this belongs in a posix compiler class clike_optimization_args = { diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py index a75c62d..0613e79 100644 --- a/mesonbuild/compilers/mixins/pgi.py +++ b/mesonbuild/compilers/mixins/pgi.py @@ -16,6 +16,7 @@ import typing import os +from pathlib import Path from ..compilers import clike_debug_args, clike_optimization_args @@ -42,8 +43,9 @@ pgi_buildtype_linker_args = { } # type: typing.Dict[str, typing.List[str]] -class PGICompiler: +class PGICompiler(): def __init__(self, compiler_type: 'CompilerType'): + self.base_options = ['b_pch'] self.id = 'pgi' self.compiler_type = compiler_type @@ -59,9 +61,21 @@ class PGICompiler: def get_no_warn_args(self) -> typing.List[str]: return ['-silent'] + def gen_import_library_args(self, implibname: str) -> typing.List[str]: + return [] + + def get_std_shared_lib_link_args(self) -> typing.List[str]: + # PGI -shared is Linux only. + if self.compiler_type.is_windows_compiler: + return ['-Bdynamic', '-Mmakedll'] + elif not self.compiler_type.is_osx_compiler: + return ['-shared'] + return [] + def get_pic_args(self) -> typing.List[str]: + # PGI -fPIC is Linux only. if self.compiler_type.is_osx_compiler or self.compiler_type.is_windows_compiler: - return [] # PGI -fPIC is Linux only. + return [] return ['-fPIC'] def openmp_flags(self) -> typing.List[str]: @@ -93,3 +107,17 @@ class PGICompiler: def get_always_args(self) -> typing.List[str]: return [] + + def get_pch_suffix(self) -> str: + # PGI defaults to .pch suffix for PCH on Linux and Windows with --pch option + return 'pch' + + def get_pch_use_args(self, pch_dir: str, header: str) -> typing.List[str]: + # PGI supports PCH for C++ only. + hdr = Path(pch_dir).resolve().parent / header + if self.language == 'cpp': + return ['--pch', + '--pch_dir', str(hdr.parent), + '-I{}'.format(hdr.parent)] + else: + return [] diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 1bb1b6e..cdfa48b 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -370,21 +370,30 @@ class OpenMPDependency(ExternalDependency): language = kwargs.get('language') super().__init__('openmp', environment, language, kwargs) self.is_found = False + if self.clib_compiler.get_id() == 'pgi': + # through at least PGI 19.4, there is no macro defined for OpenMP, but OpenMP 3.1 is supported. + self.version = '3.1' + self.is_found = True + self.compile_args = self.link_args = self.clib_compiler.openmp_flags() + return try: openmp_date = self.clib_compiler.get_define( '_OPENMP', '', self.env, self.clib_compiler.openmp_flags(), [self], disable_cache=True)[0] except mesonlib.EnvironmentException as e: mlog.debug('OpenMP support not available in the compiler') mlog.debug(e) - openmp_date = False + openmp_date = None if openmp_date: self.version = self.VERSIONS[openmp_date] - if self.clib_compiler.has_header('omp.h', '', self.env, dependencies=[self], disable_cache=True)[0]: - self.is_found = True - self.compile_args = self.link_args = self.clib_compiler.openmp_flags() - else: - mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.') + # Flang has omp_lib.h + header_names = ('omp.h', 'omp_lib.h') + for name in header_names: + if self.clib_compiler.has_header(name, '', self.env, dependencies=[self], disable_cache=True)[0]: + self.is_found = True + self.compile_args = self.link_args = self.clib_compiler.openmp_flags() + else: + mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.') class ThreadDependency(ExternalDependency): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 4b4d776..0891094 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -444,7 +444,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder): @FeatureNew('dep.get_variable', '0.51.0') @noPosargs - @permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'default', 'pkgconfig_define'}) + @permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'default_value', 'pkgconfig_define'}) def variable_method(self, args, kwargs): return self.held_object.get_variable(**kwargs) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 7af0194..2d1aaf9 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -20,6 +20,7 @@ import sys import shutil import subprocess import hashlib +import json from glob import glob from mesonbuild.environment import detect_ninja from mesonbuild.mesonlib import windows_proof_rmtree @@ -143,7 +144,7 @@ def create_dist_hg(dist_name, archives, src_root, bld_root, dist_sub, dist_scrip return output_names -def check_dist(packagename, meson_command, privdir): +def check_dist(packagename, meson_command, bld_root, privdir): print('Testing distribution package %s' % packagename) unpackdir = os.path.join(privdir, 'dist-unpack') builddir = os.path.join(privdir, 'dist-build') @@ -158,6 +159,9 @@ def check_dist(packagename, meson_command, privdir): unpacked_files = glob(os.path.join(unpackdir, '*')) assert(len(unpacked_files) == 1) unpacked_src_dir = unpacked_files[0] + with open(os.path.join(bld_root, 'meson-info', 'intro-buildoptions.json')) as boptions: + meson_command += ['-D{name}={value}'.format(**o) for o in json.load(boptions) + if o['name'] not in ['backend', 'install_umask']] if subprocess.call(meson_command + ['--backend=ninja', unpacked_src_dir, builddir]) != 0: print('Running Meson on distribution package failed') return 1 @@ -214,7 +218,7 @@ def run(options): if names is None: return 1 # Check only one. - rc = check_dist(names[0], meson_command, priv_dir) + rc = check_dist(names[0], meson_command, bld_root, priv_dir) if rc == 0: for name in names: create_hash(name) diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index 253f4ab..dc5c9d1 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -14,6 +14,7 @@ # A tool to run tests in many different ways. +from pathlib import Path from collections import namedtuple from copy import deepcopy import argparse @@ -426,18 +427,18 @@ def run_with_mono(fname: str) -> bool: return False def load_benchmarks(build_dir: str) -> typing.List['TestSerialisation']: - datafile = os.path.join(build_dir, 'meson-private', 'meson_benchmark_setup.dat') - if not os.path.isfile(datafile): - raise TestException('Directory ${!r} does not seem to be a Meson build directory.'.format(build_dir)) - with open(datafile, 'rb') as f: + datafile = Path(build_dir) / 'meson-private' / 'meson_benchmark_setup.dat' + if not datafile.is_file(): + raise TestException('Directory {!r} does not seem to be a Meson build directory.'.format(build_dir)) + with datafile.open('rb') as f: obj = typing.cast(typing.List['TestSerialisation'], pickle.load(f)) return obj def load_tests(build_dir: str) -> typing.List['TestSerialisation']: - datafile = os.path.join(build_dir, 'meson-private', 'meson_test_setup.dat') - if not os.path.isfile(datafile): - raise TestException('Directory ${!r} does not seem to be a Meson build directory.'.format(build_dir)) - with open(datafile, 'rb') as f: + datafile = Path(build_dir) / 'meson-private' / 'meson_test_setup.dat' + if not datafile.is_file(): + raise TestException('Directory {!r} does not seem to be a Meson build directory.'.format(build_dir)) + with datafile.open('rb') as f: obj = typing.cast(typing.List['TestSerialisation'], pickle.load(f)) return obj @@ -833,8 +834,9 @@ Timeout: %4d return False def test_suitable(self, test: 'TestSerialisation') -> bool: - return (not self.options.include_suites or TestHarness.test_in_suites(test, self.options.include_suites)) \ - and not TestHarness.test_in_suites(test, self.options.exclude_suites) + return ((not self.options.include_suites or + TestHarness.test_in_suites(test, self.options.include_suites)) and not + TestHarness.test_in_suites(test, self.options.exclude_suites)) def get_tests(self) -> typing.List['TestSerialisation']: if not self.tests: @@ -849,6 +851,7 @@ Timeout: %4d else: tests = self.tests + # allow specifying test names like "meson test foo1 foo2", where test('foo1', ...) if self.options.args: tests = [t for t in tests if t.name in self.options.args] @@ -975,7 +978,7 @@ def list_tests(th: TestHarness) -> bool: return not tests def rebuild_all(wd: str) -> bool: - if not os.path.isfile(os.path.join(wd, 'build.ninja')): + if not (Path(wd) / 'build.ninja').is_file(): print('Only ninja backend is supported to rebuild tests before running them.') return True @@ -984,11 +987,9 @@ def rebuild_all(wd: str) -> bool: print("Can't find ninja, can't rebuild test.") return False - p = subprocess.Popen([ninja, '-C', wd]) - p.communicate() - - if p.returncode != 0: - print('Could not rebuild') + ret = subprocess.run([ninja, '-C', wd]).returncode + if ret != 0: + print('Could not rebuild {}'.format(wd)) return False return True diff --git a/run_project_tests.py b/run_project_tests.py index 80b56bb..a161525 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import List, Tuple +import typing import itertools import os import subprocess @@ -109,18 +109,10 @@ def setup_commands(optbackend): compile_commands, clean_commands, test_commands, install_commands, \ uninstall_commands = get_backend_commands(backend, do_debug) -def get_relative_files_list_from_dir(fromdir): - paths = [] - for (root, _, files) in os.walk(fromdir): - reldir = os.path.relpath(root, start=fromdir) - for f in files: - path = os.path.join(reldir, f).replace('\\', '/') - if path.startswith('./'): - path = path[2:] - paths.append(path) - return paths - -def platform_fix_name(fname, compiler, env): +def get_relative_files_list_from_dir(fromdir: Path) -> typing.List[Path]: + return [file.relative_to(fromdir) for file in fromdir.rglob('*') if file.is_file()] + +def platform_fix_name(fname: str, compiler, env) -> str: # canonicalize compiler if compiler in {'clang-cl', 'intel-cl'}: canonical_compiler = 'msvc' @@ -200,35 +192,36 @@ def platform_fix_name(fname, compiler, env): return fname -def validate_install(srcdir, installdir, compiler, env): +def validate_install(srcdir: str, installdir: Path, compiler, env) -> str: # List of installed files - info_file = os.path.join(srcdir, 'installed_files.txt') + info_file = Path(srcdir) / 'installed_files.txt' + installdir = Path(installdir) # If this exists, the test does not install any other files - noinst_file = 'usr/no-installed-files' - expected = {} + noinst_file = Path('usr/no-installed-files') + expected = {} # type: typing.Dict[Path, bool] ret_msg = '' # Generate list of expected files - if os.path.exists(os.path.join(installdir, noinst_file)): + if (installdir / noinst_file).is_file(): expected[noinst_file] = False - elif os.path.exists(info_file): - with open(info_file) as f: + elif info_file.is_file(): + with info_file.open() as f: for line in f: line = platform_fix_name(line.strip(), compiler, env) if line: - expected[line] = False + expected[Path(line)] = False # Check if expected files were found for fname in expected: - file_path = os.path.join(installdir, fname) - if os.path.exists(file_path) or os.path.islink(file_path): + file_path = installdir / fname + if file_path.is_file() or file_path.is_symlink(): expected[fname] = True for (fname, found) in expected.items(): if not found: - ret_msg += 'Expected file {0} missing.\n'.format(fname) + ret_msg += 'Expected file {} missing.\n'.format(fname) # Check if there are any unexpected files found = get_relative_files_list_from_dir(installdir) for fname in found: if fname not in expected: - ret_msg += 'Extra file {0} found.\n'.format(fname) + ret_msg += 'Extra file {} found.\n'.format(fname) if ret_msg != '': ret_msg += '\nInstall dir contents:\n' for i in found: @@ -445,7 +438,7 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen return TestResult(validate_install(testdir, install_dir, compiler, builddata.environment), BuildStep.validate, stdo, stde, mesonlog, gen_time, build_time, test_time) -def gather_tests(testdir: Path) -> List[Path]: +def gather_tests(testdir: Path) -> typing.List[Path]: test_names = [t.name for t in testdir.glob('*') if t.is_dir()] test_names = [t for t in test_names if not t.startswith('.')] # Filter non-tests files (dot files, etc) test_nums = [(int(t.split()[0]), t) for t in test_names] @@ -598,7 +591,7 @@ def should_skip_rust() -> bool: return True return False -def detect_tests_to_run(only: List[str]) -> List[Tuple[str, List[Path], bool]]: +def detect_tests_to_run(only: typing.List[str]) -> typing.List[typing.Tuple[str, typing.List[Path], bool]]: """ Parameters ---------- @@ -611,10 +604,8 @@ def detect_tests_to_run(only: List[str]) -> List[Tuple[str, List[Path], bool]]: tests to run """ - ninja_fortran_compiler = shutil.which('gfortran') or shutil.which('flang') or shutil.which('pgfortran') or (not mesonlib.is_windows() and shutil.which('ifort')) - ninja_fortran = backend is Backend.ninja and ninja_fortran_compiler - vs_fortran = mesonlib.is_windows() and backend is Backend.vs and shutil.which('ifort') - skip_fortran = not(ninja_fortran or vs_fortran) + skip_fortran = not(shutil.which('gfortran') or shutil.which('flang') or + shutil.which('pgfortran') or shutil.which('ifort')) # Name, subdirectory, skip condition. all_tests = [ @@ -637,7 +628,7 @@ def detect_tests_to_run(only: List[str]) -> List[Tuple[str, List[Path], bool]]: ('d', 'd', backend is not Backend.ninja or not have_d_compiler()), ('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or not have_objc_compiler()), ('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or not have_objcpp_compiler()), - ('fortran', 'fortran', skip_fortran), + ('fortran', 'fortran', skip_fortran or backend != Backend.ninja), ('swift', 'swift', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('swiftc')), ('cuda', 'cuda', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('nvcc')), ('python3', 'python3', backend is not Backend.ninja), @@ -654,14 +645,14 @@ def detect_tests_to_run(only: List[str]) -> List[Tuple[str, List[Path], bool]]: gathered_tests = [(name, gather_tests(Path('test cases', subdir)), skip) for name, subdir, skip in all_tests] return gathered_tests -def run_tests(all_tests, log_name_base, failfast, extra_args): +def run_tests(all_tests, log_name_base, failfast: bool, extra_args): global logfile txtname = log_name_base + '.txt' with open(txtname, 'w', encoding='utf-8', errors='ignore') as lf: logfile = lf return _run_tests(all_tests, log_name_base, failfast, extra_args) -def _run_tests(all_tests, log_name_base, failfast, extra_args): +def _run_tests(all_tests, log_name_base, failfast: bool, extra_args): global stop, executor, futures, system_compiler xmlname = log_name_base + '.xml' junit_root = ET.Element('testsuites') @@ -767,8 +758,8 @@ def _run_tests(all_tests, log_name_base, failfast, extra_args): stdeel = ET.SubElement(current_test, 'system-err') stdeel.text = result.stde - if failfast and failing_tests > 0: - break + if failfast and failing_tests > 0: + break print("\nTotal configuration time: %.2fs" % conf_time) print("Total build time: %.2fs" % build_time) diff --git a/run_tests.py b/run_tests.py index 38c65c5..6a42681 100755 --- a/run_tests.py +++ b/run_tests.py @@ -34,11 +34,13 @@ from mesonbuild import mlog from mesonbuild.environment import Environment, detect_ninja from mesonbuild.coredata import backendlist -def guess_backend(backend, msbuild_exe): +def guess_backend(backend, msbuild_exe: str): # Auto-detect backend if unspecified backend_flags = [] if backend is None: - if msbuild_exe is not None and mesonlib.is_windows(): + if (msbuild_exe is not None and + mesonlib.is_windows() and not + (os.environ.get('CC') == 'icl' or os.environ.get('CXX') == 'icl' or os.environ.get('FC') == 'ifort')): backend = 'vs' # Meson will auto-detect VS version to use else: backend = 'ninja' diff --git a/run_unittests.py b/run_unittests.py index 1ac4c53..0bd2c02 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -6605,6 +6605,21 @@ def unset_envs(): if v in os.environ: del os.environ[v] +def convert_args(argv): + # If we got passed a list of tests, pass it on + pytest_args = ['-v'] if '-v' in argv else [] + test_list = [] + for arg in argv: + if arg.startswith('-'): + continue + # ClassName.test_name => 'ClassName and test_name' + if '.' in arg: + arg = ' and '.join(arg.split('.')) + test_list.append(arg) + if test_list: + pytest_args += ['-k', ' or '.join(test_list)] + return pytest_args + def main(): unset_envs() try: @@ -6612,6 +6627,7 @@ def main(): # Need pytest-xdist for `-n` arg import xdist # noqa: F401 pytest_args = ['-n', 'auto', './run_unittests.py'] + pytest_args += convert_args(sys.argv[1:]) return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode except ImportError: print('pytest-xdist not found, using unittest instead') diff --git a/test cases/common/13 pch/c/meson.build b/test cases/common/13 pch/c/meson.build index fe4ac68..6fba15b 100644 --- a/test cases/common/13 pch/c/meson.build +++ b/test cases/common/13 pch/c/meson.build @@ -1,8 +1,14 @@ cc = meson.get_compiler('c') cc_id = cc.get_id() + if cc_id == 'lcc' error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.') endif +# PGI compiler only supports PCH for C++ +if cc_id == 'pgi' + subdir_done() +endif + exe = executable('prog', 'prog.c', c_pch : 'pch/prog.h') diff --git a/test cases/common/13 pch/cpp/prog.cc b/test cases/common/13 pch/cpp/prog.cc index 629d880..ea258c6 100644 --- a/test cases/common/13 pch/cpp/prog.cc +++ b/test cases/common/13 pch/cpp/prog.cc @@ -1,8 +1,11 @@ +// Note: if using PGI compilers, you will need to add #include "prog.hh" +// even though you're using precompiled headers. void func() { std::cout << "This is a function that fails to compile if iostream is not included." << std::endl; } int main(int argc, char **argv) { + func(); return 0; } diff --git a/test cases/common/13 pch/generated/meson.build b/test cases/common/13 pch/generated/meson.build index 1ef771b..ba06bce 100644 --- a/test cases/common/13 pch/generated/meson.build +++ b/test cases/common/13 pch/generated/meson.build @@ -1,9 +1,15 @@ cc = meson.get_compiler('c') cc_id = cc.get_id() + if cc_id == 'lcc' error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.') endif +# PGI compiler only supports PCH for C++ +if cc_id == 'pgi' + subdir_done() +endif + generated_customTarget = custom_target('makeheader', output: 'generated_customTarget.h', command : [find_program('gen_custom.py'), '@OUTPUT0@']) diff --git a/test cases/common/13 pch/meson.build b/test cases/common/13 pch/meson.build index 4438c9e..334afc5 100644 --- a/test cases/common/13 pch/meson.build +++ b/test cases/common/13 pch/meson.build @@ -1,4 +1,12 @@ -project('pch test', 'c', 'cpp') +project('pch test', 'c', 'cpp', + meson_version: '>= 0.46.0') + +cc = meson.get_compiler('c') +cc_id = cc.get_id() + +if cc_id == 'pgi' + error('MESON_SKIP_TEST: PGI compiler does support PCH, however, PGI cannot tolerate spaces in the --pch_dir path and Meson run_project_tests.py uses spaces in temporary build path names. If this test is run individually with no spaces in build path, it will pass.') +endif subdir('c') subdir('cpp') diff --git a/test cases/common/13 pch/mixed/meson.build b/test cases/common/13 pch/mixed/meson.build index cbb7bac..266e7a5 100644 --- a/test cases/common/13 pch/mixed/meson.build +++ b/test cases/common/13 pch/mixed/meson.build @@ -1,3 +1,11 @@ +cc = meson.get_compiler('c') +cc_id = cc.get_id() + +# PGI compiler only supports PCH for C++ +if cc_id == 'pgi' + subdir_done() +endif + exe = executable( 'prog', files('main.cc', 'func.c'), diff --git a/test cases/common/13 pch/withIncludeDirectories/meson.build b/test cases/common/13 pch/withIncludeDirectories/meson.build index 68e544b..95f7888 100644 --- a/test cases/common/13 pch/withIncludeDirectories/meson.build +++ b/test cases/common/13 pch/withIncludeDirectories/meson.build @@ -1,9 +1,15 @@ cc = meson.get_compiler('c') cc_id = cc.get_id() + if cc_id == 'lcc' error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.') endif +# PGI compiler only supports PCH for C++ +if cc_id == 'pgi' + subdir_done() +endif + exe = executable('prog', 'prog.c', include_directories: 'include', c_pch : 'pch/prog.h') diff --git a/test cases/common/190 openmp/meson.build b/test cases/common/190 openmp/meson.build index 71bf697..a1154c2 100644 --- a/test cases/common/190 openmp/meson.build +++ b/test cases/common/190 openmp/meson.build @@ -1,4 +1,4 @@ -project('openmp', 'c', 'cpp') +project('openmp', 'c') cc = meson.get_compiler('c') if cc.get_id() == 'gcc' and cc.version().version_compare('<4.2.0') @@ -21,21 +21,22 @@ if host_machine.system() == 'darwin' endif openmp = dependency('openmp') +env = environment() +env.set('OMP_NUM_THREADS', '2') exec = executable('exec', 'main.c', dependencies : [openmp]) - -execpp = executable('execpp', - 'main.cpp', - dependencies : [openmp]) - -env = environment() -env.set('OMP_NUM_THREADS', '2') - test('OpenMP C', exec, env : env) -test('OpenMP C++', execpp, env : env) +if not(build_machine.system() == 'windows' and cc.get_id() == 'pgi') + if add_languages('cpp', required : false) + execpp = executable('execpp', + 'main.cpp', + dependencies : [openmp]) + test('OpenMP C++', execpp, env : env) + endif +endif if add_languages('fortran', required : false) # Mixing compilers (msvc/clang with gfortran) does not seem to work on Windows. diff --git a/test cases/common/223 source set realistic example/meson.build b/test cases/common/223 source set realistic example/meson.build index f983e8b..2a9475a 100644 --- a/test cases/common/223 source set realistic example/meson.build +++ b/test cases/common/223 source set realistic example/meson.build @@ -2,6 +2,12 @@ # modules, inspired by QEMU's build system project('sourceset-example', 'cpp') + +cppid = meson.get_compiler('cpp').get_id() +if cppid == 'pgi' + error('MESON_SKIP_TEST: Even PGI 19.4 that claims C++17 full support, cannot handle auto x = y syntax used in this test.') +endif + ss = import('sourceset') kconfig = import('unstable-kconfig') diff --git a/test cases/fortran/13 coarray/meson.build b/test cases/fortran/13 coarray/meson.build index 3160aa6..3e52dde 100644 --- a/test cases/fortran/13 coarray/meson.build +++ b/test cases/fortran/13 coarray/meson.build @@ -1,6 +1,13 @@ project('Fortran coarray', 'fortran', meson_version: '>=0.50') +fc = meson.get_compiler('fortran') +fcid = fc.get_id() + +if ['pgi', 'flang'].contains(fcid) + error('MESON_SKIP_TEST: At least through PGI 19.4 and Flang 7.1 do not support Fortran Coarrays.') +endif + # coarray is required because single-image fallback is an intrinsic feature coarray = dependency('coarray', required : true) diff --git a/test cases/fortran/14 fortran links c/meson.build b/test cases/fortran/14 fortran links c/meson.build index 1ac47e4..a45f06f 100644 --- a/test cases/fortran/14 fortran links c/meson.build +++ b/test cases/fortran/14 fortran links c/meson.build @@ -1,5 +1,6 @@ project('Fortran calling C', 'fortran', 'c', - meson_version: '>= 0.51.0') + meson_version: '>= 0.51.0', + default_options : ['default_library=static']) ccid = meson.get_compiler('c').get_id() if ccid == 'msvc' or ccid == 'clang-cl' diff --git a/test cases/fortran/2 modules/meson.build b/test cases/fortran/2 modules/meson.build index fb58b9d..791ae63 100644 --- a/test cases/fortran/2 modules/meson.build +++ b/test cases/fortran/2 modules/meson.build @@ -1,4 +1,5 @@ -project('modules', 'fortran') +project('modules', 'fortran', + default_options : ['default_library=static']) commented = library('commented', 'comment_mod.f90') diff --git a/test cases/fortran/6 dynamic/meson.build b/test cases/fortran/6 dynamic/meson.build index 244a38b..413223b 100644 --- a/test cases/fortran/6 dynamic/meson.build +++ b/test cases/fortran/6 dynamic/meson.build @@ -1,9 +1,11 @@ project('dynamic_fortran', 'fortran') -if meson.get_compiler('fortran').get_id() == 'intel-cl' - error('MESON_SKIP_TEST: Windows ifort does not use shared_library in a sane way') +fcid = meson.get_compiler('fortran').get_id() +if fcid == 'intel-cl' or (host_machine.system() == 'windows' and fcid == 'pgi') + error('MESON_SKIP_TEST: non-Gfortran Windows Fortran compilers do not do shared libraries in a Fortran standard way') # !DEC$ ATTRIBUTES DLLEXPORT must be used! # https://software.intel.com/en-us/node/535306 + # https://www.pgroup.com/resources/docs/19.4/x86/pgi-user-guide/index.htm#lib-dynlnk-bld-dll-fort endif dynamic = shared_library('dynamic', 'dynamic.f90') diff --git a/test cases/unit/55 introspection/meson.build b/test cases/unit/55 introspection/meson.build index 3f013aa..7589f3f 100644 --- a/test cases/unit/55 introspection/meson.build +++ b/test cases/unit/55 introspection/meson.build @@ -25,7 +25,7 @@ var2 = 2.to_string() var3 = 'test3' t1 = executable('test' + var1, ['t1.cpp'], link_with: [sharedlib], install: true, build_by_default: get_option('test_opt2')) -t2 = executable('test@0@'.format('@0@'.format(var2)), 't2.cpp', link_with: [staticlib]) +t2 = executable('test@0@'.format('@0@'.format(var2)), sources: ['t2.cpp'], link_with: [staticlib]) t3 = executable(var3, 't3.cpp', link_with: [sharedlib, staticlib], dependencies: [dep1]) ### BEGIN: Test inspired by taisei: https://github.com/taisei-project/taisei/blob/master/meson.build#L293 |