From 38a65821454495cb48ceeb6446de46805fcd2d41 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 21 Sep 2018 14:18:31 -0400 Subject: [PATCH] configure_file: Support taking values from a dict Closes #4218 --- docs/markdown/Configuration.md | 32 +++++++++++++++++++ docs/markdown/Reference-manual.md | 9 ++++-- mesonbuild/interpreter.py | 22 ++++++++++--- .../common/14 configure file/meson.build | 24 ++++++++++++++ test cases/common/14 configure file/prog9.c | 18 +++++++++++ 5 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 test cases/common/14 configure file/prog9.c diff --git a/docs/markdown/Configuration.md b/docs/markdown/Configuration.md index 8b79bc6e9..cd1af14d1 100644 --- a/docs/markdown/Configuration.md +++ b/docs/markdown/Configuration.md @@ -121,6 +121,38 @@ you to specify which file encoding to use. It is however strongly advised to convert your non utf-8 file to utf-8 whenever possible. Supported file encodings are those of python3, see [standard-encodings](https://docs.python.org/3/library/codecs.html#standard-encodings). +## Using dictionaries + +Since *0.49.0* `configuration_data()` takes an optional dictionary as first +argument. If provided, each key/value pair is added into the +`configuration_data` as if `set()` method was called for each of them. +`configure_file()`'s `configuration` kwarg also accepts a dictionary instead of +a configuration_data object. + +Example: +```meson +cdata = configuration_data({ + 'STRING' : '"foo"', + 'INT' : 42, + 'DEFINED' : true, + 'UNDEFINED' : false, +}) + +configure_file(output : 'config1.h', + configuration : cdata, +) + +configure_file(output : 'config2.h', + configuration : { + 'STRING' : '"foo"', + 'INT' : 42, + 'DEFINED' : true, + 'UNDEFINED' : false, + } +) + +``` + # A full example Generating and using a configuration file requires the following steps: diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 0fb9f1797..cc4ba9ba0 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -167,13 +167,17 @@ methods section](#build-target-object) below. ### configuration_data() ``` meson - configuration_data_object = configuration_data() + configuration_data_object = configuration_data(...) ``` Creates an empty configuration object. You should add your configuration with [its method calls](#configuration-data-object) and finally use it in a call to `configure_file`. +Since *0.49.0* takes an optional dictionary as first argument. If provided, each +key/value pair is added into the `configuration_data` as if `set()` method was +called for each of them. + ### configure_file() ``` meson @@ -187,7 +191,8 @@ When a [`configuration_data()`](#configuration_data) object is passed to the `configuration:` keyword argument, it takes a template file as the `input:` (optional) and produces the `output:` (required) by substituting values from the configuration data as detailed in [the -configuration file documentation](Configuration.md). +configuration file documentation](Configuration.md). Since *0.49.0* a dictionary +can be passed instead of a [`configuration_data()`](#configuration_data) object. When a list of strings is passed to the `command:` keyword argument, it takes any source or configured file as the `input:` and assumes diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 2d5dd9245..9a41fabd3 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2372,9 +2372,18 @@ external dependencies (including libraries) must go to "dependencies".''') @noKwargs def func_configuration_data(self, node, args, kwargs): - if args: - raise InterpreterException('configuration_data takes no arguments') - return ConfigurationDataHolder(self.subproject) + if len(args) > 1: + raise InterpreterException('configuration_data takes only one optional positional arguments') + elif len(args) == 1: + initial_values = args[0] + if not isinstance(initial_values, dict): + raise InterpreterException('configuration_data first argument must be a dictionary') + else: + initial_values = {} + cdata = ConfigurationDataHolder(self.subproject) + for k, v in initial_values.items(): + cdata.set_method([k, v], {}) + return cdata def set_options(self, default_options): # Set default options as if they were passed to the command line. @@ -3552,7 +3561,12 @@ root and issuing %s. # Perform the appropriate action if 'configuration' in kwargs: conf = kwargs['configuration'] - if not isinstance(conf, ConfigurationDataHolder): + if isinstance(conf, dict): + cdata = ConfigurationDataHolder(self.subproject) + for k, v in conf.items(): + cdata.set_method([k, v], {}) + conf = cdata + elif not isinstance(conf, ConfigurationDataHolder): raise InterpreterException('Argument "configuration" is not of type configuration_data') mlog.log('Configuring', mlog.bold(output), 'using configuration') if inputfile is not None: diff --git a/test cases/common/14 configure file/meson.build b/test cases/common/14 configure file/meson.build index b040c89d6..53b06f34b 100644 --- a/test cases/common/14 configure file/meson.build +++ b/test cases/common/14 configure file/meson.build @@ -246,3 +246,27 @@ test('configure-file', test_file) cdata = configuration_data() cdata.set('invalid_value', ['array']) + +# Dictionaries + +cdata = configuration_data({ + 'A_STRING' : '"foo"', + 'A_INT' : 42, + 'A_DEFINED' : true, + 'A_UNDEFINED' : false, +}) + +configure_file(output : 'config9a.h', + configuration : cdata, +) + +configure_file(output : 'config9b.h', + configuration : { + 'B_STRING' : '"foo"', + 'B_INT' : 42, + 'B_DEFINED' : true, + 'B_UNDEFINED' : false, + } +) + +test('test9', executable('prog9', 'prog9.c')) diff --git a/test cases/common/14 configure file/prog9.c b/test cases/common/14 configure file/prog9.c new file mode 100644 index 000000000..28c735491 --- /dev/null +++ b/test cases/common/14 configure file/prog9.c @@ -0,0 +1,18 @@ +#include +#include +#include + +#if defined(A_UNDEFINED) || defined(B_UNDEFINED) +#error "Should not be defined" +#endif + +#if !defined(A_DEFINED) || !defined(B_DEFINED) +#error "Should be defined" +#endif + +int main(int argc, char **argv) { + return strcmp(A_STRING, "foo") + || strcmp(B_STRING, "foo") + || A_INT != 42 + || B_INT != 42; +}