aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/snippets/json_output_format.md5
-rw-r--r--docs/yaml/functions/configure_file.yaml2
-rw-r--r--mesonbuild/interpreter/interpreter.py4
-rw-r--r--mesonbuild/interpreter/kwargs.py2
-rw-r--r--mesonbuild/utils/universal.py50
-rw-r--r--test cases/common/269 configure file output format/compare.py5
-rw-r--r--test cases/common/269 configure file output format/expected/config.h21
-rw-r--r--test cases/common/269 configure file output format/expected/config.json1
-rw-r--r--test cases/common/269 configure file output format/expected/config.nasm17
-rw-r--r--test cases/common/269 configure file output format/meson.build38
10 files changed, 121 insertions, 24 deletions
diff --git a/docs/markdown/snippets/json_output_format.md b/docs/markdown/snippets/json_output_format.md
new file mode 100644
index 0000000..626840f
--- /dev/null
+++ b/docs/markdown/snippets/json_output_format.md
@@ -0,0 +1,5 @@
+## Added 'json' output_format to configure_file()
+
+When no input file is specified, [[configure_file]] can now
+generate a `json` file from given [[@cfg_data]].
+Field descriptions are not preserved in the json file.
diff --git a/docs/yaml/functions/configure_file.yaml b/docs/yaml/functions/configure_file.yaml
index df37ff5..6fb972b 100644
--- a/docs/yaml/functions/configure_file.yaml
+++ b/docs/yaml/functions/configure_file.yaml
@@ -134,7 +134,7 @@ kwargs:
The format of the output to generate when no input
was specified. It defaults to `c`, in which case preprocessor directives
will be prefixed with `#`, you can also use `nasm`, in which case the
- prefix will be `%`.
+ prefix will be `%`. *(since 1.3.0)* `json` format can also be used.
encoding:
type: str
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index 4751af9..0ba8dc7 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -2594,8 +2594,8 @@ class Interpreter(InterpreterBase, HoldableObject):
KwargInfo('install_dir', (str, bool), default='',
validator=lambda x: 'must be `false` if boolean' if x is True else None),
OUTPUT_KW,
- KwargInfo('output_format', str, default='c', since='0.47.0',
- validator=in_set_validator({'c', 'nasm'})),
+ KwargInfo('output_format', str, default='c', since='0.47.0', since_values={'json': '1.3.0'},
+ validator=in_set_validator({'c', 'json', 'nasm'})),
)
def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var],
kwargs: kwtypes.ConfigureFile):
diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py
index af5733f..0aee164 100644
--- a/mesonbuild/interpreter/kwargs.py
+++ b/mesonbuild/interpreter/kwargs.py
@@ -286,7 +286,7 @@ class ConfigureFile(TypedDict):
output: str
capture: bool
format: T.Literal['meson', 'cmake', 'cmake@']
- output_format: T.Literal['c', 'nasm']
+ output_format: T.Literal['c', 'json', 'nasm']
depfile: T.Optional[str]
install: T.Optional[bool]
install_dir: T.Union[str, T.Literal[False]]
diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py
index a39825f..d44ec03 100644
--- a/mesonbuild/utils/universal.py
+++ b/mesonbuild/utils/universal.py
@@ -32,6 +32,7 @@ import textwrap
import copy
import pickle
import errno
+import json
from mesonbuild import mlog
from .core import MesonException, HoldableObject
@@ -1361,34 +1362,43 @@ CONF_NASM_PRELUDE = '''; Autogenerated by the Meson build system.
'''
-def dump_conf_header(ofilename: str, cdata: 'ConfigurationData', output_format: Literal['c', 'nasm']) -> None:
+def _dump_c_header(ofile: T.TextIO, cdata: ConfigurationData, output_format: Literal['c', 'nasm']) -> None:
+ format_desc: T.Callable[[str], str]
if output_format == 'c':
prelude = CONF_C_PRELUDE
prefix = '#'
- else:
+ format_desc = lambda desc: f'/* {desc} */\n'
+ else: # nasm
prelude = CONF_NASM_PRELUDE
prefix = '%'
+ format_desc = lambda desc: '; ' + '\n; '.join(desc.splitlines()) + '\n'
+
+ ofile.write(prelude)
+ for k in sorted(cdata.keys()):
+ (v, desc) = cdata.get(k)
+ if desc:
+ ofile.write(format_desc(desc))
+ if isinstance(v, bool):
+ if v:
+ ofile.write(f'{prefix}define {k}\n\n')
+ else:
+ ofile.write(f'{prefix}undef {k}\n\n')
+ elif isinstance(v, (int, str)):
+ ofile.write(f'{prefix}define {k} {v}\n\n')
+ else:
+ raise MesonException('Unknown data type in configuration file entry: ' + k)
+
+def dump_conf_header(ofilename: str, cdata: ConfigurationData,
+ output_format: Literal['c', 'nasm', 'json']) -> None:
ofilename_tmp = ofilename + '~'
with open(ofilename_tmp, 'w', encoding='utf-8') as ofile:
- ofile.write(prelude)
- for k in sorted(cdata.keys()):
- (v, desc) = cdata.get(k)
- if desc:
- if output_format == 'c':
- ofile.write('/* %s */\n' % desc)
- elif output_format == 'nasm':
- for line in desc.split('\n'):
- ofile.write('; %s\n' % line)
- if isinstance(v, bool):
- if v:
- ofile.write(f'{prefix}define {k}\n\n')
- else:
- ofile.write(f'{prefix}undef {k}\n\n')
- elif isinstance(v, (int, str)):
- ofile.write(f'{prefix}define {k} {v}\n\n')
- else:
- raise MesonException('Unknown data type in configuration file entry: ' + k)
+ if output_format == 'json':
+ data = {k: v[0] for k, v in cdata.values.items()}
+ json.dump(data, ofile, sort_keys=True)
+ else: # c, nasm
+ _dump_c_header(ofile, cdata, output_format)
+
replace_if_different(ofilename, ofilename_tmp)
diff --git a/test cases/common/269 configure file output format/compare.py b/test cases/common/269 configure file output format/compare.py
new file mode 100644
index 0000000..5188b02
--- /dev/null
+++ b/test cases/common/269 configure file output format/compare.py
@@ -0,0 +1,5 @@
+import sys
+
+with open(sys.argv[1], 'r', encoding='utf-8') as f, open(sys.argv[2], 'r', encoding='utf-8') as g:
+ if f.read() != g.read():
+ sys.exit('contents are not equal')
diff --git a/test cases/common/269 configure file output format/expected/config.h b/test cases/common/269 configure file output format/expected/config.h
new file mode 100644
index 0000000..33cfd89
--- /dev/null
+++ b/test cases/common/269 configure file output format/expected/config.h
@@ -0,0 +1,21 @@
+/*
+ * Autogenerated by the Meson build system.
+ * Do not edit, your changes will be lost.
+ */
+
+#pragma once
+
+#define bool
+
+#undef false
+
+/* ultimate question of life, the universe, and everything */
+#define int 42
+
+/* This is
+a multiline
+description */
+#define str "hello world!"
+
+#define unquoted float
+
diff --git a/test cases/common/269 configure file output format/expected/config.json b/test cases/common/269 configure file output format/expected/config.json
new file mode 100644
index 0000000..47d7832
--- /dev/null
+++ b/test cases/common/269 configure file output format/expected/config.json
@@ -0,0 +1 @@
+{"bool": true, "false": false, "int": 42, "str": "\"hello world!\"", "unquoted": "float"} \ No newline at end of file
diff --git a/test cases/common/269 configure file output format/expected/config.nasm b/test cases/common/269 configure file output format/expected/config.nasm
new file mode 100644
index 0000000..63c5c22
--- /dev/null
+++ b/test cases/common/269 configure file output format/expected/config.nasm
@@ -0,0 +1,17 @@
+; Autogenerated by the Meson build system.
+; Do not edit, your changes will be lost.
+
+%define bool
+
+%undef false
+
+; ultimate question of life, the universe, and everything
+%define int 42
+
+; This is
+; a multiline
+; description
+%define str "hello world!"
+
+%define unquoted float
+
diff --git a/test cases/common/269 configure file output format/meson.build b/test cases/common/269 configure file output format/meson.build
new file mode 100644
index 0000000..796b9d6
--- /dev/null
+++ b/test cases/common/269 configure file output format/meson.build
@@ -0,0 +1,38 @@
+project('configure file output format')
+
+data = configuration_data()
+data.set_quoted('str', 'hello world!', description: '''This is
+a multiline
+description''')
+data.set('unquoted', 'float')
+data.set('int', 42, description: 'ultimate question of life, the universe, and everything')
+data.set('bool', true)
+data.set('false', false)
+
+config_h = configure_file(
+ configuration: data,
+ output_format: 'c',
+ output: 'config.h'
+)
+
+config_nasm = configure_file(
+ configuration: data,
+ output_format: 'nasm',
+ output: 'config.nasm'
+)
+
+config_json = configure_file(
+ configuration: data,
+ output_format: 'json',
+ output: 'config.json'
+)
+
+py = find_program('python3')
+compare_py = files('compare.py')
+expected_config_h = files('expected/config.h')
+expected_config_nasm = files('expected/config.nasm')
+expected_config_json = files('expected/config.json')
+
+test('c_output', py, args: [compare_py, expected_config_h, config_h])
+test('nasm_output', py, args: [compare_py, expected_config_nasm, config_nasm])
+test('json_output', py, args: [compare_py, expected_config_json, config_json])