modules: fs: accept build targets as fs.copyfile() source

Allow CustomTarget, CustomTargetIndex, and BuildTarget as the first
argument to fs.copyfile(), so that build artifacts can be copied
without resorting to a manual custom_target.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André LureauandClaude Opus 4.6 authored and Paolo Bonzini committed 2026-04-23 18:15:14 +02:00
1 parent c5618e3f50
commit 74faddbb44
4 files changed
+38 -7

No files matched your search

+3 -1
View File
@@ -259,7 +259,9 @@ returns:
Copy a file from the source directory to the build directory at build time.
Has the following positional arguments:
- src `File | str`: the file to copy
- src `File | str | build_tgt | custom_tgt | custom_idx`: the file to copy.
*Since 1.12.0* build targets, custom targets, and custom target indices are
also accepted.
Has the following optional arguments:
- dest `str`: the name of the output file. If unset will be the basename of
@@ -0,0 +1,5 @@
## `fs.copyfile()` now accepts build targets as input
`fs.copyfile()` now accepts `build_tgt`, `custom_tgt`, and `custom_idx`
as the source argument, in addition to `File` and `str`. This makes it
possible to copy build artifacts without resorting to a `custom_target`.
+17 -6
View File
@@ -280,7 +280,7 @@ class FSModule(ExtensionModule):
return data
@FeatureNew('fs.copyfile', '0.64.0')
@typed_pos_args('fs.copyfile', (File, str), optargs=[str])
@typed_pos_args('fs.copyfile', (File, str, CustomTarget, CustomTargetIndex, BuildTarget), optargs=[str])
@typed_kwargs(
'fs.copyfile',
INSTALL_KW,
@@ -289,17 +289,28 @@ class FSModule(ExtensionModule):
KwargInfo('install_dir', (str, NoneType)),
BUILD_SUBDIR_KW.evolve(since='1.12.0'),
)
def copyfile(self, state: ModuleState, args: T.Tuple[FileOrString, T.Optional[str]],
def copyfile(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes], T.Optional[str]],
kwargs: CopyKw) -> ModuleReturnValue:
"""Copy a file into the build directory at build time."""
if kwargs['install'] and not kwargs['install_dir']:
raise InvalidArguments('"install_dir" must be specified when "install" is true')
src = self.interpreter.source_strings_to_files([args[0]])[0]
src: T.Union[File, BuildTarget, CustomTarget, CustomTargetIndex]
if isinstance(args[0], (CustomTarget, CustomTargetIndex, BuildTarget)):
FeatureNew.single_use('fs.copyfile with build_tgt, custom_tgt, and custom_idx', '1.12.0', state.subproject, location=state.current_node)
if isinstance(args[0], CustomTarget) and len(args[0].get_outputs()) > 1:
raise InvalidArguments(
f'custom_target {args[0].name!r} has more than one output! '
f'Use `{args[0].name}[<n>]` to select the output to copy.')
src = args[0]
default_name = src.get_filename()
else:
src = self.interpreter.source_strings_to_files([args[0]])[0]
# The input is allowed to have path separators, but the output may not,
# so use the basename for the default case
default_name = os.path.basename(src.fname)
# The input is allowed to have path separators, but the output may not,
# so use the basename for the default case
dest = args[1] if args[1] else os.path.basename(src.fname)
dest = args[1] if args[1] else default_name
if has_path_sep(dest):
raise InvalidArguments('Destination path may not have path separators')
@@ -7,6 +7,9 @@ fs = import('fs')
f = files('meson.build')
btgt = executable('btgt', 'btgt.c')
ctgt = fs.copyfile('ctgt.txt')
ctgt_copy = fs.copyfile(ctgt, 'ctgt_copy.txt')
ctgt_idx_copy = fs.copyfile(ctgt[0], 'ctgt_idx_copy.txt')
btgt_copy = fs.copyfile(btgt, 'btgt_copy')
assert(fs.exists('meson.build'), 'Existing file reported as missing.')
assert(not fs.exists('nonexisting'), 'Nonexisting file was found.')
@@ -199,3 +202,13 @@ subproject('subbie')
testcase expect_error('File notfound does not exist.')
fs.read('notfound')
endtestcase
multi_out = custom_target('multi_out',
output: ['a.txt', 'b.txt'],
command: [find_program('cp'), '@INPUT@', '@OUTPUT@'],
input: 'meson.build',
)
testcase expect_error('custom_target \'multi_out\' has more than one output! Use `multi_out[<n>]` to select the output to copy.')
fs.copyfile(multi_out)
endtestcase