diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2019-09-06 18:52:50 -0400 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2019-09-17 13:05:40 -0400 |
commit | ef3992f1cc2db7467fef2395ac3ec191eea154f0 (patch) | |
tree | 8b62e92179b0ea41fd7ac22aaa91a604362ac64e | |
parent | 5d0ced220c56a7599913c9e249b85f0d6a060821 (diff) | |
download | meson-ef3992f1cc2db7467fef2395ac3ec191eea154f0.zip meson-ef3992f1cc2db7467fef2395ac3ec191eea154f0.tar.gz meson-ef3992f1cc2db7467fef2395ac3ec191eea154f0.tar.bz2 |
configure_file(): Allow multiple inputs in command mode
Closes: #5893
-rw-r--r-- | docs/markdown/Reference-manual.md | 5 | ||||
-rw-r--r-- | docs/markdown/snippets/configure_file_enhancements.md | 3 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 75 | ||||
-rw-r--r-- | test cases/common/14 configure file/check_inputs.py | 14 | ||||
-rw-r--r-- | test cases/common/14 configure file/meson.build | 6 |
5 files changed, 61 insertions, 42 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index bdcbe1f..c701caf 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -251,7 +251,10 @@ These are all the supported keyword arguments: `output`. Available since v0.41.0. - `command` as explained above, if specified, Meson does not create the file itself but rather runs the specified command, which allows - you to do fully custom file generation. + you to do fully custom file generation. Since *0.52.0* the command can contain + file objects and more than one file can be passed to the `input` keyword + argument, see [`custom_target()`](#custom_target) for details about string + substitutions. - `copy` *(added 0.47.0)* as explained above, if specified Meson only copies the file from input to output. - `format` *(added 0.46.0)* the format of defines. It defaults to `meson`, and so substitutes diff --git a/docs/markdown/snippets/configure_file_enhancements.md b/docs/markdown/snippets/configure_file_enhancements.md new file mode 100644 index 0000000..35a64b4 --- /dev/null +++ b/docs/markdown/snippets/configure_file_enhancements.md @@ -0,0 +1,3 @@ +## Enhancements to `configure_file()` + +`input:` now accepts multiple input file names for `command:`-configured file. diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 03910b2..d324549 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3673,30 +3673,20 @@ This will become a hard error in the future.''' % kwargs['input'], location=self raise InterpreterException('"format" possible values are "c" or "nasm".') # Validate input - inputfile = None - ifile_abs = None - if 'input' in kwargs: - inputfile = kwargs['input'] - if isinstance(inputfile, list): - if len(inputfile) != 1: - m = "Keyword argument 'input' requires exactly one file" - raise InterpreterException(m) - inputfile = inputfile[0] - if not isinstance(inputfile, (str, mesonlib.File)): - raise InterpreterException('Input must be a string or a file') - if isinstance(inputfile, str): - inputfile = mesonlib.File.from_source_file(self.environment.source_dir, - self.subdir, inputfile) - ifile_abs = inputfile.absolute_path(self.environment.source_dir, - self.environment.build_dir) - elif 'command' in kwargs and '@INPUT@' in kwargs['command']: - raise InterpreterException('@INPUT@ used as command argument, but no input file specified.') + inputs = self.source_strings_to_files(extract_as_list(kwargs, 'input')) + inputs_abs = [] + for f in inputs: + if isinstance(f, mesonlib.File): + inputs_abs.append(f.absolute_path(self.environment.source_dir, + self.environment.build_dir)) + else: + raise InterpreterException('Inputs can only be strings or file objects') # Validate output output = kwargs['output'] if not isinstance(output, str): raise InterpreterException('Output file name must be a string') - if ifile_abs: - values = mesonlib.get_filenames_templates_dict([ifile_abs], None) + if inputs_abs: + values = mesonlib.get_filenames_templates_dict(inputs_abs, None) outputs = mesonlib.substitute_values([output], values) output = outputs[0] ofile_rpath = os.path.join(self.subdir, output) @@ -3722,20 +3712,22 @@ This will become a hard error in the future.''' % kwargs['input'], location=self 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: + if len(inputs) > 1: + raise InterpreterException('At most one input file can given in configuration mode') + if inputs: os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) file_encoding = kwargs.setdefault('encoding', 'utf-8') missing_variables, confdata_useless = \ - mesonlib.do_conf_file(ifile_abs, ofile_abs, conf.held_object, + mesonlib.do_conf_file(inputs_abs[0], ofile_abs, conf.held_object, fmt, file_encoding) if missing_variables: var_list = ", ".join(map(repr, sorted(missing_variables))) mlog.warning( "The variable(s) %s in the input file '%s' are not " "present in the given configuration data." % ( - var_list, inputfile), location=node) + var_list, inputs[0]), location=node) if confdata_useless: - ifbase = os.path.basename(ifile_abs) + ifbase = os.path.basename(inputs_abs[0]) mlog.warning('Got an empty configuration_data() object and found no ' 'substitutions in the input file {!r}. If you want to ' 'copy a file to the build dir, use the \'copy:\' keyword ' @@ -3744,13 +3736,12 @@ This will become a hard error in the future.''' % kwargs['input'], location=self mesonlib.dump_conf_header(ofile_abs, conf.held_object, output_format) conf.mark_used() elif 'command' in kwargs: + if len(inputs) > 1: + FeatureNew('multiple inputs in configure_file()', '0.52.0').use(self.subproject) # We use absolute paths for input and output here because the cwd # that the command is run from is 'unspecified', so it could change. # Currently it's builddir/subdir for in_builddir else srcdir/subdir. - if ifile_abs: - values = mesonlib.get_filenames_templates_dict([ifile_abs], [ofile_abs]) - else: - values = mesonlib.get_filenames_templates_dict(None, [ofile_abs]) + values = mesonlib.get_filenames_templates_dict(inputs_abs, [ofile_abs]) # Substitute @INPUT@, @OUTPUT@, etc here. cmd = mesonlib.substitute_values(kwargs['command'], values) mlog.log('Configuring', mlog.bold(output), 'with command') @@ -3763,26 +3754,28 @@ This will become a hard error in the future.''' % kwargs['input'], location=self file_encoding = kwargs.setdefault('encoding', 'utf-8') with open(dst_tmp, 'w', encoding=file_encoding) as f: f.writelines(res.stdout) - if ifile_abs: - shutil.copymode(ifile_abs, dst_tmp) + if inputs_abs: + shutil.copymode(inputs_abs[0], dst_tmp) mesonlib.replace_if_different(ofile_abs, dst_tmp) elif 'copy' in kwargs: + if len(inputs_abs) != 1: + raise InterpreterException('Exactly one input file must be given in copy mode') os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) - shutil.copyfile(ifile_abs, ofile_abs) - shutil.copymode(ifile_abs, ofile_abs) + shutil.copyfile(inputs_abs[0], ofile_abs) + shutil.copymode(inputs_abs[0], ofile_abs) else: # Not reachable raise AssertionError # If the input is a source file, add it to the list of files that we - # need to reconfigure on when they change. FIXME: Do the same for - # files() objects in the command: kwarg. - if inputfile and not inputfile.is_built: - # Normalize the path of the conffile (relative to the - # source root) to avoid duplicates. This is especially - # important to convert '/' to '\' on Windows - conffile = os.path.normpath(inputfile.relative_name()) - if conffile not in self.build_def_files: - self.build_def_files.append(conffile) + # need to reconfigure on when they change. + for f in chain(inputs, kwargs.get('command', [])): + if isinstance(f, mesonlib.File) and not f.is_built: + # Normalize the path of the conffile (relative to the + # source root) to avoid duplicates. This is especially + # important to convert '/' to '\' on Windows + conffile = os.path.normpath(f.relative_name()) + if conffile not in self.build_def_files: + self.build_def_files.append(conffile) # Install file if requested, we check for the empty string # for backwards compatibility. That was the behaviour before # 0.45.0 so preserve it. diff --git a/test cases/common/14 configure file/check_inputs.py b/test cases/common/14 configure file/check_inputs.py new file mode 100644 index 0000000..1faa8ba --- /dev/null +++ b/test cases/common/14 configure file/check_inputs.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +from pathlib import Path + +files = [Path(f) for f in sys.argv[1:]] +names = [f.name for f in files] + +assert names == ['check_inputs.txt', 'prog.c', 'prog.c', 'prog2.c', 'prog4.c', 'prog5.c'] +for f in files[1:]: + assert f.exists() + +with files[0].open('w') as ofile: + ofile.write("#define ZERO_RESULT 0\n") diff --git a/test cases/common/14 configure file/meson.build b/test cases/common/14 configure file/meson.build index 50393e9..d0f3d54 100644 --- a/test cases/common/14 configure file/meson.build +++ b/test cases/common/14 configure file/meson.build @@ -283,3 +283,9 @@ configure_file(output : 'config9b.h', ) test('test9', executable('prog9', 'prog9.c')) + +check_inputs = find_program('check_inputs.py') +configure_file(output : 'check_inputs.txt', + input : ['prog.c', files('prog2.c', 'prog4.c')], + command : [check_inputs, '@OUTPUT@', '@INPUT0@', '@INPUT@', files('prog5.c')] +) |