add json output format to configure file

pull/12170/head
Charles Brunet 2 years ago committed by Eli Schwartz
parent cd30d1889f
commit cf5adf0c64
  1. 5
      docs/markdown/snippets/json_output_format.md
  2. 2
      docs/yaml/functions/configure_file.yaml
  3. 4
      mesonbuild/interpreter/interpreter.py
  4. 2
      mesonbuild/interpreter/kwargs.py
  5. 50
      mesonbuild/utils/universal.py
  6. 5
      test cases/common/269 configure file output format/compare.py
  7. 21
      test cases/common/269 configure file output format/expected/config.h
  8. 1
      test cases/common/269 configure file output format/expected/config.json
  9. 17
      test cases/common/269 configure file output format/expected/config.nasm
  10. 38
      test cases/common/269 configure file output format/meson.build

@ -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.

@ -134,7 +134,7 @@ kwargs:
The format of the output to generate when no input The format of the output to generate when no input
was specified. It defaults to `c`, in which case preprocessor directives was specified. It defaults to `c`, in which case preprocessor directives
will be prefixed with `#`, you can also use `nasm`, in which case the 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: encoding:
type: str type: str

@ -2594,8 +2594,8 @@ class Interpreter(InterpreterBase, HoldableObject):
KwargInfo('install_dir', (str, bool), default='', KwargInfo('install_dir', (str, bool), default='',
validator=lambda x: 'must be `false` if boolean' if x is True else None), validator=lambda x: 'must be `false` if boolean' if x is True else None),
OUTPUT_KW, OUTPUT_KW,
KwargInfo('output_format', str, default='c', since='0.47.0', KwargInfo('output_format', str, default='c', since='0.47.0', since_values={'json': '1.3.0'},
validator=in_set_validator({'c', 'nasm'})), validator=in_set_validator({'c', 'json', 'nasm'})),
) )
def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var],
kwargs: kwtypes.ConfigureFile): kwargs: kwtypes.ConfigureFile):

@ -286,7 +286,7 @@ class ConfigureFile(TypedDict):
output: str output: str
capture: bool capture: bool
format: T.Literal['meson', 'cmake', 'cmake@'] format: T.Literal['meson', 'cmake', 'cmake@']
output_format: T.Literal['c', 'nasm'] output_format: T.Literal['c', 'json', 'nasm']
depfile: T.Optional[str] depfile: T.Optional[str]
install: T.Optional[bool] install: T.Optional[bool]
install_dir: T.Union[str, T.Literal[False]] install_dir: T.Union[str, T.Literal[False]]

@ -32,6 +32,7 @@ import textwrap
import copy import copy
import pickle import pickle
import errno import errno
import json
from mesonbuild import mlog from mesonbuild import mlog
from .core import MesonException, HoldableObject 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': if output_format == 'c':
prelude = CONF_C_PRELUDE prelude = CONF_C_PRELUDE
prefix = '#' prefix = '#'
else: format_desc = lambda desc: f'/* {desc} */\n'
else: # nasm
prelude = CONF_NASM_PRELUDE prelude = CONF_NASM_PRELUDE
prefix = '%' 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 + '~' ofilename_tmp = ofilename + '~'
with open(ofilename_tmp, 'w', encoding='utf-8') as ofile: with open(ofilename_tmp, 'w', encoding='utf-8') as ofile:
ofile.write(prelude) if output_format == 'json':
for k in sorted(cdata.keys()): data = {k: v[0] for k, v in cdata.values.items()}
(v, desc) = cdata.get(k) json.dump(data, ofile, sort_keys=True)
if desc: else: # c, nasm
if output_format == 'c': _dump_c_header(ofile, cdata, output_format)
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)
replace_if_different(ofilename, ofilename_tmp) replace_if_different(ofilename, ofilename_tmp)

@ -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')

@ -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

@ -0,0 +1 @@
{"bool": true, "false": false, "int": 42, "str": "\"hello world!\"", "unquoted": "float"}

@ -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

@ -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])
Loading…
Cancel
Save