diff options
-rw-r--r-- | .github/workflows/ci_frameworks.yml | 18 | ||||
-rw-r--r-- | .github/workflows/lint_mypy.yml | 8 | ||||
-rw-r--r-- | .github/workflows/os_comp.yml | 1 | ||||
-rw-r--r-- | docs/markdown/IDE-integration.md | 6 | ||||
-rw-r--r-- | docs/markdown/Reference-manual.md | 44 | ||||
-rw-r--r-- | docs/markdown/snippets/introspect_test_deps.md | 5 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 12 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 4 | ||||
-rw-r--r-- | mesonbuild/environment.py | 16 | ||||
-rw-r--r-- | mesonbuild/mcompile.py | 2 | ||||
-rw-r--r-- | mesonbuild/mdist.py | 12 | ||||
-rw-r--r-- | mesonbuild/minit.py | 2 | ||||
-rw-r--r-- | mesonbuild/mintro.py | 1 | ||||
-rw-r--r-- | mesonbuild/mtest.py | 2 | ||||
-rw-r--r-- | mesonbuild/scripts/scanbuild.py | 2 | ||||
-rwxr-xr-x | run_unittests.py | 18 | ||||
-rw-r--r-- | test cases/unit/57 introspection/cp.py | 5 | ||||
-rw-r--r-- | test cases/unit/57 introspection/meson.build | 7 |
18 files changed, 107 insertions, 58 deletions
diff --git a/.github/workflows/ci_frameworks.yml b/.github/workflows/ci_frameworks.yml index 12d41f8..172c12c 100644 --- a/.github/workflows/ci_frameworks.yml +++ b/.github/workflows/ci_frameworks.yml @@ -17,14 +17,14 @@ jobs: scalapackMacOS: runs-on: macos-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: '3.x' - run: python -m pip install -e . - run: brew install pkg-config ninja gcc openmpi lapack scalapack - run: meson setup "test cases/frameworks/30 scalapack" build - - run: ninja -C build + - run: meson compile -C build - uses: actions/upload-artifact@v1 if: failure() with: @@ -40,14 +40,14 @@ jobs: HDF5macos: runs-on: macos-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: '3.x' - run: python -m pip install -e . - run: brew install pkg-config ninja gcc hdf5 - run: meson setup "test cases/frameworks/25 hdf5" build - - run: ninja -C build + - run: meson compile -C build - uses: actions/upload-artifact@v1 if: failure() with: @@ -63,8 +63,8 @@ jobs: Qt4macos: runs-on: macos-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: '3.x' - run: python -m pip install -e . @@ -72,7 +72,7 @@ jobs: - run: brew tap cartr/qt4 - run: brew install qt@4 - run: meson setup "test cases/frameworks/4 qt" build -Drequired=qt4 - - run: ninja -C build + - run: meson compile -C build - uses: actions/upload-artifact@v1 if: failure() with: diff --git a/.github/workflows/lint_mypy.yml b/.github/workflows/lint_mypy.yml index 056f96e..e1615c2 100644 --- a/.github/workflows/lint_mypy.yml +++ b/.github/workflows/lint_mypy.yml @@ -15,8 +15,8 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: '3.x' # pylint version constraint can be removed when https://github.com/PyCQA/pylint/issues/3524 is resolved @@ -26,8 +26,8 @@ jobs: mypy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 with: python-version: '3.x' - run: python -m pip install mypy diff --git a/.github/workflows/os_comp.yml b/.github/workflows/os_comp.yml index a5abf7d..3b38bab 100644 --- a/.github/workflows/os_comp.yml +++ b/.github/workflows/os_comp.yml @@ -25,7 +25,6 @@ jobs: - name: Run tests run: LD_LIBRARY_PATH=/usr/local/share/boost/1.69.0/lib/:$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH python3 run_tests.py env: - CI: '1' XENIAL: '1' arch: diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md index 816225f..5188359 100644 --- a/docs/markdown/IDE-integration.md +++ b/docs/markdown/IDE-integration.md @@ -247,6 +247,7 @@ line arguments, environment variable settings and how to process the output. "is_parallel": true / false, "protocol": "exitcode" / "tap", "cmd": ["command", "to", "run"], + "depends": ["target1-id", "target2-id"], "env": { "VARIABLE1": "value 1", "VARIABLE2": "value 2" @@ -254,6 +255,11 @@ line arguments, environment variable settings and how to process the output. } ``` +The `depends` entry *(since 0.56.0)* contains target ids; they can be +looked up in the targets introspection data. The executable +pointed to by `cmd` is also included in the entry, as are any +arguments to the test that are build products. + ## Build system files It is also possible to get Meson build files used in your current project. This diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index a860f85..fafc9cb 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1776,7 +1776,7 @@ the following methods. `MESONINTROSPECT` contains the path to the introspect command that corresponds to the `meson` executable that was used to configure the - build. (This might be a different path then the first executable + build. (This might be a different path than the first executable found in `PATH`.) It can be used to query build configuration. Note that the value will contain many parts, f.ex., it may be `python3 /path/to/meson.py introspect`. The user is responsible for splitting @@ -2155,27 +2155,27 @@ the following methods: `args` keyword, you can specify external dependencies to use with `dependencies` keyword argument. -- `check_header` *(since 0.47.0)*: returns true if the specified header is *usable* with - the specified prefix, dependencies, and arguments. - You can specify external dependencies to use with `dependencies` - keyword argument and extra code to put above the header test with - the `prefix` keyword. In order to look for headers in a specific - directory you can use `args : '-I/extra/include/dir`, but this - should only be used in exceptional cases for includes that can't be - detected via pkg-config and passed via `dependencies`. *(since 0.50.0)* The - `required` keyword argument can be used to abort if the header cannot be - found. - -- `has_header`: returns true if the specified header *exists*, and is - faster than `check_header()` since it only does a pre-processor check. - You can specify external dependencies to use with `dependencies` - keyword argument and extra code to put above the header test with - the `prefix` keyword. In order to look for headers in a specific - directory you can use `args : '-I/extra/include/dir`, but this - should only be used in exceptional cases for includes that can't be - detected via pkg-config and passed via `dependencies`. *(since 0.50.0)* The - `required` keyword argument can be used to abort if the header cannot be - found. +- `check_header(header_name)` *(since 0.47.0)*: returns true if the + specified header is *usable* with the specified prefix, + dependencies, and arguments. You can specify external dependencies + to use with `dependencies` keyword argument and extra code to put + above the header test with the `prefix` keyword. In order to look + for headers in a specific directory you can use `args : + '-I/extra/include/dir`, but this should only be used in exceptional + cases for includes that can't be detected via pkg-config and passed + via `dependencies`. *(since 0.50.0)* The `required` keyword argument + can be used to abort if the header cannot be found. + +- `has_header(header_name)`: returns true if the specified header + *exists*, and is faster than `check_header()` since it only does a + pre-processor check. You can specify external dependencies to use + with `dependencies` keyword argument and extra code to put above the + header test with the `prefix` keyword. In order to look for headers + in a specific directory you can use `args : '-I/extra/include/dir`, + but this should only be used in exceptional cases for includes that + can't be detected via pkg-config and passed via `dependencies`. + *(since 0.50.0)* The `required` keyword argument can be used to + abort if the header cannot be found. - `has_header_symbol(headername, symbolname)`: detects whether a particular symbol (function, variable, #define, type diff --git a/docs/markdown/snippets/introspect_test_deps.md b/docs/markdown/snippets/introspect_test_deps.md new file mode 100644 index 0000000..a29ea09 --- /dev/null +++ b/docs/markdown/snippets/introspect_test_deps.md @@ -0,0 +1,5 @@ +## Dependencies listed in test and benchmark introspection + +The introspection data for tests and benchmarks now includes the target +ids for executables and built files that are needed by the test. IDEs can +use this feature to update the build more quickly before running a test. diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 7bdccbf..6c5b75a 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -120,7 +120,8 @@ class TestSerialisation: env: build.EnvironmentVariables, should_fail: bool, timeout: T.Optional[int], workdir: T.Optional[str], extra_paths: T.List[str], protocol: TestProtocol, priority: int, - cmd_is_built: bool): + cmd_is_built: bool, + depends: T.List[str]): self.name = name self.project_name = project self.suite = suite @@ -140,6 +141,7 @@ class TestSerialisation: self.priority = priority self.needs_exe_wrapper = needs_exe_wrapper self.cmd_is_built = cmd_is_built + self.depends = depends def get_backend_from_name(backend: str, build: T.Optional[build.Build] = None, interpreter: T.Optional['Interpreter'] = None) -> T.Optional['Backend']: @@ -830,7 +832,12 @@ class Backend: extra_paths = [] cmd_args = [] + depends = set(t.depends) + if isinstance(exe, build.Target): + depends.add(exe) for a in unholder(t.cmd_args): + if isinstance(a, build.Target): + depends.add(a) if isinstance(a, build.BuildTarget): extra_paths += self.determine_windows_extra_paths(a, []) if isinstance(a, mesonlib.File): @@ -852,7 +859,8 @@ class Backend: t.is_parallel, cmd_args, t.env, t.should_fail, t.timeout, t.workdir, extra_paths, t.protocol, t.priority, - isinstance(exe, build.Executable)) + isinstance(exe, build.Executable), + [x.get_id() for x in depends]) arr.append(ts) return arr diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 2d0a0b9..9004165 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -548,7 +548,7 @@ int dummy; rules += ["%s%s" % (rule, ext) for rule in [self.get_pch_rule_name(lang, for_machine)] for ext in ['', '_RSP']] compdb_options = ['-x'] if mesonlib.version_compare(self.ninja_version, '>=1.9') else [] - ninja_compdb = [self.ninja_command, '-t', 'compdb'] + compdb_options + rules + ninja_compdb = self.ninja_command + ['-t', 'compdb'] + compdb_options + rules builddir = self.environment.get_build_dir() try: jsondb = subprocess.check_output(ninja_compdb, cwd=builddir) @@ -2958,7 +2958,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY') - elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean']) + elem.add_item('COMMAND', self.ninja_command + ['-t', 'clean']) elem.add_item('description', 'Cleaning') # Alias that runs the above-defined meson-clean target self.create_target_alias('meson-clean') diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 5600f9d..f8282c0 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -168,15 +168,19 @@ def find_coverage_tools(): return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe -def detect_ninja(version: str = '1.7', log: bool = False) -> str: +def detect_ninja(version: str = '1.7', log: bool = False) -> T.List[str]: r = detect_ninja_command_and_version(version, log) return r[0] if r else None -def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> (str, str): +def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> (T.List[str], str): + from .dependencies.base import ExternalProgram env_ninja = os.environ.get('NINJA', None) for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']: + prog = ExternalProgram(n, silent=True) + if not prog.found(): + continue try: - p, found = Popen_safe([n, '--version'])[0:2] + p, found = Popen_safe(prog.command + ['--version'])[0:2] except (FileNotFoundError, PermissionError): # Doesn't exist in PATH or isn't executable continue @@ -184,7 +188,6 @@ def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> # Perhaps we should add a way for the caller to know the failure mode # (not found or too old) if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version): - n = shutil.which(n) if log: name = os.path.basename(n) if name.endswith('-' + found): @@ -193,8 +196,9 @@ def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> name = 'ninja' if name == 'samu': name = 'samurai' - mlog.log('Found {}-{} at {}'.format(name, found, quote_arg(n))) - return (n, found) + mlog.log('Found {}-{} at {}'.format(name, found, + ' '.join([quote_arg(x) for x in prog.command]))) + return (prog.command, found) def get_llvm_tool_names(tool: str) -> T.List[str]: # Ordered list of possible suffixes of LLVM executables to try. Start with diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index 3199f59..8e2a38f 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -139,7 +139,7 @@ def get_parsed_args_ninja(options: 'argparse.Namespace', builddir: Path) -> T.Li raise MesonException('Cannot find ninja.') mlog.log('Found runner:', runner) - cmd = [runner, '-C', builddir.as_posix()] + cmd = runner + ['-C', builddir.as_posix()] if options.targets: intro_data = parse_introspect_data(builddir) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 9d94ace..fbda240 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -180,19 +180,19 @@ def create_dist_hg(dist_name, archives, src_root, bld_root, dist_sub, dist_scrip output_names.append(zipname) return output_names -def run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_bin): +def run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_args): if subprocess.call(meson_command + ['--backend=ninja', unpacked_src_dir, builddir]) != 0: print('Running Meson on distribution package failed') return 1 - if subprocess.call([ninja_bin], cwd=builddir) != 0: + if subprocess.call(ninja_args, cwd=builddir) != 0: print('Compiling the distribution package failed') return 1 - if subprocess.call([ninja_bin, 'test'], cwd=builddir) != 0: + if subprocess.call(ninja_args + ['test'], cwd=builddir) != 0: print('Running unit tests on the distribution package failed') return 1 myenv = os.environ.copy() myenv['DESTDIR'] = installdir - if subprocess.call([ninja_bin, 'install'], cwd=builddir, env=myenv) != 0: + if subprocess.call(ninja_args + ['install'], cwd=builddir, env=myenv) != 0: print('Installing the distribution package failed') return 1 return 0 @@ -206,7 +206,7 @@ def check_dist(packagename, meson_command, extra_meson_args, bld_root, privdir): if os.path.exists(p): windows_proof_rmtree(p) os.mkdir(p) - ninja_bin = detect_ninja() + ninja_args = detect_ninja() shutil.unpack_archive(packagename, unpackdir) unpacked_files = glob(os.path.join(unpackdir, '*')) assert(len(unpacked_files) == 1) @@ -216,7 +216,7 @@ def check_dist(packagename, meson_command, extra_meson_args, bld_root, privdir): if o['name'] not in ['backend', 'install_umask', 'buildtype']] meson_command += extra_meson_args - ret = run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_bin) + ret = run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_args) if ret > 0: print('Dist check build directory was {}'.format(builddir)) else: diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index d0aff49..06e6dd4 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -174,7 +174,7 @@ def run(options) -> int: ret = subprocess.run(cmd) if ret.returncode: raise SystemExit - cmd = [detect_ninja(), '-C', options.builddir] + cmd = detect_ninja() + ['-C', options.builddir] ret = subprocess.run(cmd) if ret.returncode: raise SystemExit diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 0049bbd..d55227a 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -325,6 +325,7 @@ def get_test_list(testdata) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], to['is_parallel'] = t.is_parallel to['priority'] = t.priority to['protocol'] = str(t.protocol) + to['depends'] = t.depends result.append(to) return result diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index de82234..b9a1176 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -1178,7 +1178,7 @@ def rebuild_all(wd: str) -> bool: print("Can't find ninja, can't rebuild test.") return False - ret = subprocess.run([ninja, '-C', wd]).returncode + ret = subprocess.run(ninja + ['-C', wd]).returncode if ret != 0: print('Could not rebuild {}'.format(wd)) return False diff --git a/mesonbuild/scripts/scanbuild.py b/mesonbuild/scripts/scanbuild.py index b9e96d2..0190067 100644 --- a/mesonbuild/scripts/scanbuild.py +++ b/mesonbuild/scripts/scanbuild.py @@ -22,7 +22,7 @@ from ..environment import detect_ninja, detect_scanbuild def scanbuild(exelist, srcdir, blddir, privdir, logdir, args): with tempfile.TemporaryDirectory(dir=privdir) as scandir: meson_cmd = exelist + args - build_cmd = exelist + ['-o', logdir, detect_ninja(), '-C', scandir] + build_cmd = exelist + ['-o', logdir] + detect_ninja() + ['-C', scandir] rc = subprocess.call(meson_cmd + [srcdir, scandir]) if rc != 0: return rc diff --git a/run_unittests.py b/run_unittests.py index 8c03693..2ff2af5 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4281,6 +4281,7 @@ recommended as it is not supported on some platforms''') ('suite', list), ('is_parallel', bool), ('protocol', str), + ('depends', list), ] buildoptions_keylist = [ @@ -4338,12 +4339,28 @@ recommended as it is not supported on some platforms''') assertKeyTypes(root_keylist, res) + # Match target ids to input and output files for ease of reference + src_to_id = {} + out_to_id = {} + for i in res['targets']: + print(json.dump(i, sys.stdout)) + out_to_id.update({os.path.relpath(out, self.builddir): i['id'] + for out in i['filename']}) + for group in i['target_sources']: + src_to_id.update({os.path.relpath(src, testdir): i['id'] + for src in group['sources']}) + # Check Tests and benchmarks tests_to_find = ['test case 1', 'test case 2', 'benchmark 1'] + deps_to_find = {'test case 1': [src_to_id['t1.cpp']], + 'test case 2': [src_to_id['t2.cpp'], src_to_id['t3.cpp']], + 'benchmark 1': [out_to_id['file2'], src_to_id['t3.cpp']]} for i in res['benchmarks'] + res['tests']: assertKeyTypes(test_keylist, i) if i['name'] in tests_to_find: tests_to_find.remove(i['name']) + self.assertEqual(sorted(i['depends']), + sorted(deps_to_find[i['name']])) self.assertListEqual(tests_to_find, []) # Check buildoptions @@ -4484,6 +4501,7 @@ recommended as it is not supported on some platforms''') res_nb = self.introspect_directory(testfile, ['--targets'] + self.meson_args) # Account for differences in output + res_wb = [i for i in res_wb if i['type'] != 'custom'] for i in res_wb: i['filename'] = [os.path.relpath(x, self.builddir) for x in i['filename']] if 'install_filename' in i: diff --git a/test cases/unit/57 introspection/cp.py b/test cases/unit/57 introspection/cp.py new file mode 100644 index 0000000..cb09cf3 --- /dev/null +++ b/test cases/unit/57 introspection/cp.py @@ -0,0 +1,5 @@ +#! /usr/bin/env python3 + +import sys +from shutil import copyfile +copyfile(*sys.argv[1:]) diff --git a/test cases/unit/57 introspection/meson.build b/test cases/unit/57 introspection/meson.build index 5d4dd02..3a3db10 100644 --- a/test cases/unit/57 introspection/meson.build +++ b/test cases/unit/57 introspection/meson.build @@ -26,6 +26,9 @@ var1 = '1' var2 = 2.to_string() var3 = 'test3' +cus = custom_target('custom target test', output: 'file2', input: 'cp.py', + command: [find_program('cp.py'), '@INPUT@', '@OUTPUT@']) + t1 = executable('test' + var1, ['t1.cpp'], link_with: [sharedlib], install: not false, build_by_default: get_option('test_opt2')) 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]) @@ -44,8 +47,8 @@ osmesa_lib_name = osmesa_lib_name + osmesa_bits message(osmesa_lib_name) # Infinite recursion gets triggered here when the parameter osmesa_lib_name is resolved test('test case 1', t1) -test('test case 2', t2) -benchmark('benchmark 1', t3) +test('test case 2', t2, depends: t3) +benchmark('benchmark 1', t3, args: cus) ### Stuff to test the AST JSON printer foreach x : ['a', 'b', 'c'] |