aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Reference-manual.md26
-rw-r--r--docs/markdown/snippets/compiler-object-run_command.md10
-rw-r--r--docs/markdown/snippets/improved-help.md6
-rw-r--r--mesonbuild/interpreter.py11
-rw-r--r--mesonbuild/mesonmain.py7
-rwxr-xr-xrun_unittests.py24
-rw-r--r--test cases/unit/23 compiler run_command/meson.build10
7 files changed, 84 insertions, 10 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 6f6cb36..5b22fec 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -982,9 +982,13 @@ Project supports the following keyword arguments.
runresult run_command(command, list_of_args)
```
-Runs the command specified in positional arguments. Returns [an opaque
-object](#run-result-object) containing the result of the
-invocation. The script is run from an *unspecified* directory, and
+Runs the command specified in positional arguments.
+`command` can be a string, or the output of [`find_program()`](#find_program),
+[`files()`](#files) or [`configure_file()`](#configure_file), or
+[a compiler object](#compiler-object).
+
+Returns [an opaque object](#run-result-object) containing the result of the
+invocation. The command is run from an *unspecified* directory, and
Meson will set three environment variables `MESON_SOURCE_ROOT`,
`MESON_BUILD_ROOT` and `MESON_SUBDIR` that specify the source
directory, build directory and subdirectory the target was defined in,
@@ -1199,10 +1203,18 @@ be up to date on every build. Keywords are similar to `custom_target`.
Meson will read the contents of `input`, substitute the
`replace_string` with the detected revision number, and write the
-result to `output`. This method returns an opaque
-[`custom_target`](#custom_target) object that can be used as
-source. If you desire more specific behavior than what this command
-provides, you should use `custom_target`.
+result to `output`. This method returns a
+[`custom_target`](#custom_target) object that (as usual) should be
+used to signal dependencies if other targets use the file outputted
+by this.
+
+For example, if you generate a header with this and want to use that in
+a build target, you must add the return value to the sources of that
+build target. Without that, Meson will not know the order in which to
+build the targets.
+
+If you desire more specific behavior than what this command provides,
+you should use `custom_target`.
## Built-in objects
diff --git a/docs/markdown/snippets/compiler-object-run_command.md b/docs/markdown/snippets/compiler-object-run_command.md
new file mode 100644
index 0000000..0308416
--- /dev/null
+++ b/docs/markdown/snippets/compiler-object-run_command.md
@@ -0,0 +1,10 @@
+## Compiler object can now be passed to run_command()
+
+This can be used to run the current compiler with the specified arguments
+to obtain additional information from it.
+One of the use cases is to get the location of development files for the
+GCC plugins:
+
+ cc = meson.get_compiler('c')
+ result = run_command(cc, '-print-file-name=plugin')
+ plugin_dev_path = result.stdout().strip()
diff --git a/docs/markdown/snippets/improved-help.md b/docs/markdown/snippets/improved-help.md
new file mode 100644
index 0000000..db7e852
--- /dev/null
+++ b/docs/markdown/snippets/improved-help.md
@@ -0,0 +1,6 @@
+## "meson help" now shows command line help
+
+Command line parsing is now less surprising. "meson help" is now
+equivalent to "meson --help" and "meson help <subcommand>" is
+equivalent to "meson <subcommand> --help", instead of creating a build
+directory called "help" in these cases.
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 8421d70..f9f25e4 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1680,10 +1680,17 @@ external dependencies (including libraries) must go to "dependencies".''')
cargs = args[1:]
srcdir = self.environment.get_source_dir()
builddir = self.environment.get_build_dir()
- m = 'must be a string, or the output of find_program(), files(), or ' \
- 'configure_file(); not {!r}'
+ m = 'must be a string, or the output of find_program(), files() '\
+ 'or configure_file(), or a compiler object; not {!r}'
if isinstance(cmd, ExternalProgramHolder):
cmd = cmd.held_object
+ elif isinstance(cmd, CompilerHolder):
+ cmd = cmd.compiler.get_exelist()[0]
+ prog = ExternalProgram(cmd, silent=True)
+ if not prog.found():
+ raise InterpreterException('Program {!r} not found '
+ 'or not executable'.format(cmd))
+ cmd = prog
else:
if isinstance(cmd, mesonlib.File):
cmd = cmd.absolute_path(srcdir, builddir)
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index e354cce..69b4e31 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -284,6 +284,13 @@ def run(original_args, mainfile=None):
# First check if we want to run a subcommand.
cmd_name = args[0]
remaining_args = args[1:]
+ # "help" is a special case: Since printing of the help may be
+ # delegated to a subcommand, we edit cmd_name before executing
+ # the rest of the logic here.
+ if cmd_name == 'help':
+ remaining_args += ['--help']
+ args = remaining_args
+ cmd_name = args[0]
if cmd_name == 'test':
return mtest.run(remaining_args)
elif cmd_name == 'setup':
diff --git a/run_unittests.py b/run_unittests.py
index 8f69077..cbae559 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -25,7 +25,7 @@ import unittest
from unittest import mock
from configparser import ConfigParser
from glob import glob
-from pathlib import PurePath
+from pathlib import (PurePath, Path)
import mesonbuild.mlog
import mesonbuild.compilers
@@ -429,6 +429,20 @@ class InternalTests(unittest.TestCase):
kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
+ def test_snippets(self):
+ hashcounter = re.compile('^ *(#)+')
+ snippet_dir = Path('docs/markdown/snippets')
+ self.assertTrue(snippet_dir.is_dir())
+ for f in snippet_dir.glob('*'):
+ self.assertTrue(f.is_file())
+ if f.suffix == '.md':
+ for line in f.open():
+ m = re.match(hashcounter, line)
+ if m:
+ self.assertEqual(len(m.group(0)), 2, 'All headings in snippets must have two hash symbols: ' + f.name)
+ else:
+ if f.name != 'add_release_note_snippets_here':
+ self.assertTrue(False, 'A file without .md suffix in snippets dir: ' + f.name)
class BasePlatformTests(unittest.TestCase):
def setUp(self):
@@ -1836,6 +1850,14 @@ int main(int argc, char **argv) {
self.init(testdir, ['--cross-file=' + name], inprocess=True)
self.wipe()
+ def test_compiler_run_command(self):
+ '''
+ The test checks that the compiler object can be passed to
+ run_command().
+ '''
+ testdir = os.path.join(self.unit_test_dir, '23 compiler run_command')
+ self.init(testdir)
+
class FailureTests(BasePlatformTests):
'''
diff --git a/test cases/unit/23 compiler run_command/meson.build b/test cases/unit/23 compiler run_command/meson.build
new file mode 100644
index 0000000..6d9e0b9
--- /dev/null
+++ b/test cases/unit/23 compiler run_command/meson.build
@@ -0,0 +1,10 @@
+project('compiler_object_in_run_command', 'c')
+cc = meson.get_compiler('c')
+
+# This test only checks that the compiler object can be passed to
+# run_command(). If the compiler has been launched, it is expected
+# to output something either to stdout or to stderr.
+result = run_command(cc, '--version')
+if result.stdout() == '' and result.stderr() == ''
+ error('No output in stdout and stderr. Did the compiler run at all?')
+endif