diff --git a/docs/markdown/snippets/configure_file_macro_guard.md b/docs/markdown/snippets/configure_file_macro_guard.md new file mode 100644 index 000000000..ebb4fc554 --- /dev/null +++ b/docs/markdown/snippets/configure_file_macro_guard.md @@ -0,0 +1,6 @@ +## [[configure_file]] now has a `macro_name` parameter. + +This new paramater, `macro_name` allows C macro-style include guards to be added +to [[configure_file]]'s output when a template file is not given. This change +simplifies the creation of configure files that define macros with dynamic names +and want the C-style include guards. diff --git a/docs/yaml/functions/configure_file.yaml b/docs/yaml/functions/configure_file.yaml index 6fb972b3e..34cb3c1bd 100644 --- a/docs/yaml/functions/configure_file.yaml +++ b/docs/yaml/functions/configure_file.yaml @@ -144,3 +144,10 @@ kwargs: Set the file encoding for the input and output file. The supported encodings are those of python3, see [standard-encodings](https://docs.python.org/3/library/codecs.html#standard-encodings). + + macro_name: + type: str + since: 1.3.0 + description: | + When specified, macro guards will be used instead of '#pragma once'. The + macro guard name will be the specified name. diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index d9a260cff..9b005cb78 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2585,6 +2585,7 @@ class Interpreter(InterpreterBase, HoldableObject): OUTPUT_KW, KwargInfo('output_format', str, default='c', since='0.47.0', since_values={'json': '1.3.0'}, validator=in_set_validator({'c', 'json', 'nasm'})), + KwargInfo('macro_name', (str, NoneType), default=None, since='1.3.0'), ) def func_configure_file(self, node: mparser.BaseNode, args: T.List[TYPE_var], kwargs: kwtypes.ConfigureFile): @@ -2676,7 +2677,8 @@ class Interpreter(InterpreterBase, HoldableObject): 'copy a file to the build dir, use the \'copy:\' keyword ' 'argument added in 0.47.0', location=node) else: - mesonlib.dump_conf_header(ofile_abs, conf, output_format) + macro_name = kwargs['macro_name'] + mesonlib.dump_conf_header(ofile_abs, conf, output_format, macro_name) conf.used = True elif kwargs['command'] is not None: if len(inputs) > 1: diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 0aee16432..1aee41435 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -296,6 +296,7 @@ class ConfigureFile(TypedDict): command: T.Optional[T.List[T.Union[build.Executable, ExternalProgram, Compiler, File, str]]] input: T.List[FileOrString] configuration: T.Optional[T.Union[T.Dict[str, T.Union[str, int, bool]], build.ConfigurationData]] + macro_name: T.Optional[str] class Subproject(ExtractRequired): diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 7f0f3852a..1d0e382a8 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -1351,7 +1351,7 @@ CONF_C_PRELUDE = '''/* * Do not edit, your changes will be lost. */ -#pragma once +{} ''' @@ -1360,10 +1360,16 @@ CONF_NASM_PRELUDE = '''; Autogenerated by the Meson build system. ''' -def _dump_c_header(ofile: T.TextIO, cdata: ConfigurationData, output_format: Literal['c', 'nasm']) -> None: +def _dump_c_header(ofile: T.TextIO, + cdata: ConfigurationData, + output_format: Literal['c', 'nasm'], + macro_name: T.Optional[str]) -> None: format_desc: T.Callable[[str], str] if output_format == 'c': - prelude = CONF_C_PRELUDE + if macro_name: + prelude = CONF_C_PRELUDE.format('#ifndef {0}\n#define {0}'.format(macro_name)) + else: + prelude = CONF_C_PRELUDE.format('#pragma once') prefix = '#' format_desc = lambda desc: f'/* {desc} */\n' else: # nasm @@ -1385,17 +1391,20 @@ def _dump_c_header(ofile: T.TextIO, cdata: ConfigurationData, output_format: Lit ofile.write(f'{prefix}define {k} {v}\n\n') else: raise MesonException('Unknown data type in configuration file entry: ' + k) + if output_format == 'c' and macro_name: + ofile.write('#endif\n') def dump_conf_header(ofilename: str, cdata: ConfigurationData, - output_format: Literal['c', 'nasm', 'json']) -> None: + output_format: Literal['c', 'nasm', 'json'], + macro_name: T.Optional[str]) -> None: ofilename_tmp = ofilename + '~' with open(ofilename_tmp, 'w', encoding='utf-8') as ofile: 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) + _dump_c_header(ofile, cdata, output_format, macro_name) replace_if_different(ofilename, ofilename_tmp) diff --git a/test cases/common/269 configure file output format/expected/config.mg b/test cases/common/269 configure file output format/expected/config.mg new file mode 100644 index 000000000..ccdb4e720 --- /dev/null +++ b/test cases/common/269 configure file output format/expected/config.mg @@ -0,0 +1,23 @@ +/* + * Autogenerated by the Meson build system. + * Do not edit, your changes will be lost. + */ + +#ifndef CONFIG_MAGNESIUM_H +#define CONFIG_MAGNESIUM_H + +#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 + +#endif diff --git a/test cases/common/269 configure file output format/meson.build b/test cases/common/269 configure file output format/meson.build index 796b9d6a2..17650e3c0 100644 --- a/test cases/common/269 configure file output format/meson.build +++ b/test cases/common/269 configure file output format/meson.build @@ -27,12 +27,21 @@ config_json = configure_file( output: 'config.json' ) +config_mg = configure_file( + configuration: data, + macro_name: 'CONFIG_MAGNESIUM_H', + output_format: 'c', + output: 'config_mg.h' +) + 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') +expected_config_mg = files('expected/config.mg') 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]) +test('c_mg_output', py, args: [compare_py, expected_config_mg, config_mg])