aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Reference-manual.md5
-rw-r--r--docs/markdown/snippets/configure_file_enhancements.md3
-rw-r--r--mesonbuild/interpreter.py75
-rw-r--r--test cases/common/14 configure file/check_inputs.py14
-rw-r--r--test cases/common/14 configure file/meson.build6
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')]
+)