From 19718a8d9c5cb6d9ac2c2cbb5459178906a3a007 Mon Sep 17 00:00:00 2001 From: Evgenii Shatokhin Date: Sun, 25 Feb 2018 16:02:10 +0300 Subject: [PATCH] Allow passing a compiler object to run_command() Sometimes it is needed to run the current compiler with specific options not to compile a file but rather to obtain additional info. For example, GCC has several -print-* options to query it about the paths to different libraries and development files. One use case is to get the location of development files for GCC plugins, which is not easily obtainable by other means: gcc -print-file-name=plugin For this purpose, it would be convenient if the compiler object returned by meson.get_compiler(lang) could be used in run_command() directly. This commit implements it. Signed-off-by: Evgenii Shatokhin --- docs/markdown/Reference-manual.md | 10 +++++++--- docs/markdown/snippets/compiler-object-run_command.md | 10 ++++++++++ mesonbuild/interpreter.py | 11 +++++++++-- run_unittests.py | 8 ++++++++ test cases/unit/23 compiler run_command/meson.build | 10 ++++++++++ 5 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 docs/markdown/snippets/compiler-object-run_command.md create mode 100644 test cases/unit/23 compiler run_command/meson.build diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index e816795b9..b05c55595 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -980,9 +980,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, 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 000000000..0308416e5 --- /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/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7a76fad52..71c9f4bd4 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1679,10 +1679,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/run_unittests.py b/run_unittests.py index 35c5eec4e..cbae559c0 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1850,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 000000000..6d9e0b969 --- /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