configure_file: Add a new action 'copy'
This will copy the file to the build directory without trying to read it or substitute values into it. Also do this optimization if the configuration_data() object passed to the `configuration:` kwarg is empty, and print a warning about it. See also: https://github.com/mesonbuild/meson/issues/1542
This commit is contained in:
parent
b3f74b9c3a
commit
a00433fdbc
|
@ -1665,7 +1665,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
|
||||||
'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env'},
|
'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env'},
|
||||||
'benchmark': {'args', 'env', 'should_fail', 'timeout', 'workdir', 'suite'},
|
'benchmark': {'args', 'env', 'should_fail', 'timeout', 'workdir', 'suite'},
|
||||||
'build_target': known_build_target_kwargs,
|
'build_target': known_build_target_kwargs,
|
||||||
'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install', 'format'},
|
'configure_file': {'input', 'output', 'configuration', 'command', 'copy', 'install_dir', 'capture', 'install', 'format'},
|
||||||
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
|
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
|
||||||
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
|
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
|
||||||
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'link_whole', 'version'},
|
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'link_whole', 'version'},
|
||||||
|
@ -3126,10 +3126,19 @@ root and issuing %s.
|
||||||
raise InterpreterException("configure_file takes only keyword arguments.")
|
raise InterpreterException("configure_file takes only keyword arguments.")
|
||||||
if 'output' not in kwargs:
|
if 'output' not in kwargs:
|
||||||
raise InterpreterException('Required keyword argument "output" not defined.')
|
raise InterpreterException('Required keyword argument "output" not defined.')
|
||||||
if 'configuration' in kwargs and 'command' in kwargs:
|
actions = set(['configuration', 'command', 'copy']).intersection(kwargs.keys())
|
||||||
raise InterpreterException('Must not specify both "configuration" '
|
if len(actions) == 0:
|
||||||
'and "command" keyword arguments since '
|
raise InterpreterException('Must specify an action with one of these '
|
||||||
'they are mutually exclusive.')
|
'keyword arguments: \'configuration\', '
|
||||||
|
'\'command\', or \'copy\'.')
|
||||||
|
elif len(actions) == 2:
|
||||||
|
raise InterpreterException('Must not specify both {!r} and {!r} '
|
||||||
|
'keyword arguments since they are '
|
||||||
|
'mutually exclusive.'.format(*actions))
|
||||||
|
elif len(actions) == 3:
|
||||||
|
raise InterpreterException('Must specify one of {!r}, {!r}, and '
|
||||||
|
'{!r} keyword arguments since they are '
|
||||||
|
'mutually exclusive.'.format(*actions))
|
||||||
if 'capture' in kwargs:
|
if 'capture' in kwargs:
|
||||||
if not isinstance(kwargs['capture'], bool):
|
if not isinstance(kwargs['capture'], bool):
|
||||||
raise InterpreterException('"capture" keyword must be a boolean.')
|
raise InterpreterException('"capture" keyword must be a boolean.')
|
||||||
|
@ -3177,6 +3186,20 @@ root and issuing %s.
|
||||||
raise InterpreterException('Output file name must not contain a subdirectory.')
|
raise InterpreterException('Output file name must not contain a subdirectory.')
|
||||||
(ofile_path, ofile_fname) = os.path.split(os.path.join(self.subdir, output))
|
(ofile_path, ofile_fname) = os.path.split(os.path.join(self.subdir, output))
|
||||||
ofile_abs = os.path.join(self.environment.build_dir, ofile_path, ofile_fname)
|
ofile_abs = os.path.join(self.environment.build_dir, ofile_path, ofile_fname)
|
||||||
|
# Optimize copies by not doing substitution if there's nothing to
|
||||||
|
# substitute, and warn about this legacy hack
|
||||||
|
if 'configuration' in kwargs:
|
||||||
|
conf = kwargs['configuration']
|
||||||
|
if not isinstance(conf, ConfigurationDataHolder):
|
||||||
|
raise InterpreterException('Argument "configuration" must be of type configuration_data')
|
||||||
|
if ifile_abs and not conf.keys():
|
||||||
|
del kwargs['configuration']
|
||||||
|
kwargs['copy'] = True
|
||||||
|
mlog.warning('Got an empty configuration_data() object: '
|
||||||
|
'optimizing copy automatically; if you want to '
|
||||||
|
'copy a file to the build dir, use the \'copy:\' '
|
||||||
|
'keyword argument added in 0.46.0', location=node)
|
||||||
|
# Perform the appropriate action
|
||||||
if 'configuration' in kwargs:
|
if 'configuration' in kwargs:
|
||||||
conf = kwargs['configuration']
|
conf = kwargs['configuration']
|
||||||
if not isinstance(conf, ConfigurationDataHolder):
|
if not isinstance(conf, ConfigurationDataHolder):
|
||||||
|
@ -3217,8 +3240,13 @@ root and issuing %s.
|
||||||
if ifile_abs:
|
if ifile_abs:
|
||||||
shutil.copymode(ifile_abs, dst_tmp)
|
shutil.copymode(ifile_abs, dst_tmp)
|
||||||
mesonlib.replace_if_different(ofile_abs, dst_tmp)
|
mesonlib.replace_if_different(ofile_abs, dst_tmp)
|
||||||
|
elif 'copy' in kwargs:
|
||||||
|
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)
|
||||||
else:
|
else:
|
||||||
raise InterpreterException('Configure_file must have either "configuration" or "command".')
|
# Not reachable
|
||||||
|
raise AssertionError
|
||||||
# If the input is a source file, add it to the list of files that we
|
# 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
|
# need to reconfigure on when they change. FIXME: Do the same for
|
||||||
# files() objects in the command: kwarg.
|
# files() objects in the command: kwarg.
|
||||||
|
|
|
@ -1827,7 +1827,7 @@ int main(int argc, char **argv) {
|
||||||
r'meson.build:6: WARNING: a warning of some sort',
|
r'meson.build:6: WARNING: a warning of some sort',
|
||||||
r'sub' + os.path.sep + r'meson.build:4: WARNING: subdir warning',
|
r'sub' + os.path.sep + r'meson.build:4: WARNING: subdir warning',
|
||||||
r'meson.build:7: WARNING: Module unstable-simd has no backwards or forwards compatibility and might not exist in future releases.',
|
r'meson.build:7: WARNING: Module unstable-simd has no backwards or forwards compatibility and might not exist in future releases.',
|
||||||
r"meson.build:10: WARNING: The variable(s) 'MISSING' in the input file conf.in are not present in the given configuration data.",
|
r"meson.build:11: WARNING: The variable(s) 'MISSING' in the input file conf.in are not present in the given configuration data.",
|
||||||
r'meson.build:1: WARNING: Passed invalid keyword argument "invalid".',
|
r'meson.build:1: WARNING: Passed invalid keyword argument "invalid".',
|
||||||
]:
|
]:
|
||||||
self.assertRegex(out, re.escape(expected))
|
self.assertRegex(out, re.escape(expected))
|
||||||
|
|
|
@ -4,8 +4,8 @@ subdir('subdir')
|
||||||
|
|
||||||
configure_file(input : 'subdir/someinput.in',
|
configure_file(input : 'subdir/someinput.in',
|
||||||
output : 'outputhere',
|
output : 'outputhere',
|
||||||
configuration : configuration_data())
|
copy: true)
|
||||||
|
|
||||||
configure_file(input : cfile1,
|
configure_file(input : cfile1,
|
||||||
output : '@BASENAME@',
|
output : '@BASENAME@',
|
||||||
configuration : configuration_data())
|
copy: true)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
configure_file(input : 'someinput.in',
|
configure_file(input : 'someinput.in',
|
||||||
output : 'outputsubdir',
|
output : 'outputsubdir',
|
||||||
install : false,
|
install : false,
|
||||||
configuration : configuration_data())
|
copy: true)
|
||||||
|
|
||||||
py3 = import('python3').find_python()
|
py3 = import('python3').find_python()
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,12 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
assert(os.path.exists(sys.argv[1]))
|
if len(sys.argv) == 2:
|
||||||
|
assert(os.path.exists(sys.argv[1]))
|
||||||
|
elif len(sys.argv) == 3:
|
||||||
|
f1 = open(sys.argv[1], 'rb').read()
|
||||||
|
f2 = open(sys.argv[2], 'rb').read()
|
||||||
|
if f1 != f2:
|
||||||
|
raise RuntimeError('{!r} != {!r}'.format(f1, f2))
|
||||||
|
else:
|
||||||
|
raise AssertionError
|
||||||
|
|
Binary file not shown.
|
@ -35,21 +35,27 @@ ofile = '@0@/config2.h'.format(meson.current_build_dir())
|
||||||
|
|
||||||
check_file = find_program('check_file.py')
|
check_file = find_program('check_file.py')
|
||||||
# Configure in source root with command and absolute paths
|
# Configure in source root with command and absolute paths
|
||||||
configure_file(input : 'dummy.dat',
|
outf = configure_file(input : 'dummy.dat',
|
||||||
output : 'config2.h',
|
output : 'config2.h',
|
||||||
command : [genprog, scriptfile, ifile, ofile],
|
command : [genprog, scriptfile, ifile, ofile],
|
||||||
install_dir : 'share/appdir')
|
install_dir : 'share/appdir')
|
||||||
run_command(check_file, join_paths(meson.current_build_dir(), 'config2.h'))
|
ret = run_command(check_file, outf)
|
||||||
|
if ret.returncode() != 0
|
||||||
|
error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
|
||||||
|
endif
|
||||||
|
|
||||||
# Same again as before, but an input file should not be required in
|
# Same again as before, but an input file should not be required in
|
||||||
# this case where we use a command/script to generate the output file.
|
# this case where we use a command/script to generate the output file.
|
||||||
genscript2b = '@0@/generator-without-input-file.py'.format(meson.current_source_dir())
|
genscript2b = '@0@/generator-without-input-file.py'.format(meson.current_source_dir())
|
||||||
ofile2b = '@0@/config2b.h'.format(meson.current_build_dir())
|
ofile2b = '@0@/config2b.h'.format(meson.current_build_dir())
|
||||||
configure_file(
|
outf = configure_file(
|
||||||
output : 'config2b.h',
|
output : 'config2b.h',
|
||||||
command : [genprog, genscript2b, ofile2b],
|
command : [genprog, genscript2b, ofile2b],
|
||||||
install_dir : 'share/appdir')
|
install_dir : 'share/appdir')
|
||||||
run_command(check_file, join_paths(meson.current_build_dir(), 'config2b.h'))
|
ret = run_command(check_file, outf)
|
||||||
|
if ret.returncode() != 0
|
||||||
|
error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
|
||||||
|
endif
|
||||||
|
|
||||||
found_script = find_program('generator.py')
|
found_script = find_program('generator.py')
|
||||||
# More configure_file tests in here
|
# More configure_file tests in here
|
||||||
|
@ -149,3 +155,22 @@ configure_file(
|
||||||
configuration : conf7
|
configuration : conf7
|
||||||
)
|
)
|
||||||
test('test7', executable('prog7', 'prog7.c'))
|
test('test7', executable('prog7', 'prog7.c'))
|
||||||
|
|
||||||
|
# Test empty configuration data object on invalid utf8 file
|
||||||
|
inf = 'invalid-utf8.bin.in'
|
||||||
|
outf = configure_file(input : inf,
|
||||||
|
output : 'invalid-utf8.bin',
|
||||||
|
configuration : configuration_data())
|
||||||
|
ret = run_command(check_file, inf, outf)
|
||||||
|
if ret.returncode() != 0
|
||||||
|
error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Test copy of a binary file
|
||||||
|
outf = configure_file(input : inf,
|
||||||
|
output : 'somebinary.bin',
|
||||||
|
copy : true)
|
||||||
|
ret = run_command(check_file, inf, outf)
|
||||||
|
if ret.returncode() != 0
|
||||||
|
error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
|
||||||
|
endif
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
# because there is no structure in the build dir.
|
# because there is no structure in the build dir.
|
||||||
genlib = configure_file(input : '../lib.c',
|
genlib = configure_file(input : '../lib.c',
|
||||||
output : 'genlib.c',
|
output : 'genlib.c',
|
||||||
configuration : configuration_data())
|
copy: true)
|
||||||
shared_library('genlib', genlib,
|
shared_library('genlib', genlib,
|
||||||
install : false)
|
install : false)
|
||||||
|
|
|
@ -12,7 +12,7 @@ endif
|
||||||
|
|
||||||
compiler = configure_file(input : 'mycompiler.py',
|
compiler = configure_file(input : 'mycompiler.py',
|
||||||
output : 'mycompiler2.py',
|
output : 'mycompiler2.py',
|
||||||
configuration : configuration_data())
|
copy: true)
|
||||||
|
|
||||||
custom_target('thing2',
|
custom_target('thing2',
|
||||||
output : 'final2.dat',
|
output : 'final2.dat',
|
||||||
|
|
|
@ -2,4 +2,4 @@ project('outdir path', 'c')
|
||||||
|
|
||||||
configure_file(input : 'foo.in',
|
configure_file(input : 'foo.in',
|
||||||
output : 'subdir/foo',
|
output : 'subdir/foo',
|
||||||
configuration : configuration_data())
|
copy: true)
|
||||||
|
|
|
@ -7,4 +7,5 @@ warning('a warning of some sort')
|
||||||
import('unstable-simd')
|
import('unstable-simd')
|
||||||
|
|
||||||
conf_data = configuration_data()
|
conf_data = configuration_data()
|
||||||
|
conf_data.set('NOTMISSING', 1)
|
||||||
configure_file(input: 'conf.in' , output: 'conf', configuration: conf_data)
|
configure_file(input: 'conf.in' , output: 'conf', configuration: conf_data)
|
||||||
|
|
Loading…
Reference in New Issue