diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 546643192..5f2de3bdb 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1298,6 +1298,29 @@ class CustomTarget(Target): deps.append(c) return deps + def flatten_command(self, cmd): + if not isinstance(cmd, list): + cmd = [cmd] + final_cmd = [] + for c in cmd: + if hasattr(c, 'held_object'): + c = c.held_object + if isinstance(c, (str, File)): + final_cmd.append(c) + elif isinstance(c, dependencies.ExternalProgram): + if not c.found(): + m = 'Tried to use not-found external program {!r} in "command"' + raise InvalidArguments(m.format(c.name)) + final_cmd += c.get_command() + elif isinstance(c, (BuildTarget, CustomTarget)): + self.dependencies.append(c) + final_cmd.append(c) + elif isinstance(c, list): + final_cmd += self.flatten_command(c) + else: + raise InvalidArguments('Argument {!r} in "command" is invalid'.format(c)) + return final_cmd + def process_kwargs(self, kwargs): super().process_kwargs(kwargs) self.sources = kwargs.get('input', []) @@ -1325,32 +1348,7 @@ class CustomTarget(Target): if os.path.split(depfile)[1] != depfile: raise InvalidArguments('Depfile must be a plain filename without a subdirectory.') self.depfile = depfile - cmd = kwargs['command'] - if not(isinstance(cmd, list)): - cmd = [cmd] - final_cmd = [] - for i, c in enumerate(cmd): - if hasattr(c, 'held_object'): - c = c.held_object - if isinstance(c, (str, File)): - final_cmd.append(c) - elif isinstance(c, dependencies.ExternalProgram): - if not c.found(): - raise InvalidArguments('Tried to use not found external program {!r} in a build rule.'.format(c.name)) - final_cmd += c.get_command() - elif isinstance(c, (BuildTarget, CustomTarget)): - self.dependencies.append(c) - final_cmd.append(c) - elif isinstance(c, list): - # Hackety hack, only supports one level of flattening. Should really - # work to arbtrary depth. - for s in c: - if not isinstance(s, str): - raise InvalidArguments('Array as argument %d contains a non-string.' % i) - final_cmd.append(s) - else: - raise InvalidArguments('Argument %s in "command" is invalid.' % i) - self.command = final_cmd + self.command = self.flatten_command(kwargs['command']) if self.capture: for c in self.command: if isinstance(c, str) and '@OUTPUT@' in c: diff --git a/test cases/common/56 custom target/meson.build b/test cases/common/56 custom target/meson.build index fd59fbd80..2e6f69cf9 100644 --- a/test cases/common/56 custom target/meson.build +++ b/test cases/common/56 custom target/meson.build @@ -8,11 +8,13 @@ endif # Note that this will not add a dependency to the compiler executable. # Code will not be rebuilt if it changes. comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py') +# Test that files() in command: works. The compiler just discards it. +useless = files('installed_files.txt') mytarget = custom_target('bindat', output : 'data.dat', input : 'data_source.txt', -command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@'], +command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@', useless], install : true, install_dir : 'subdir' ) diff --git a/test cases/common/56 custom target/my_compiler.py b/test cases/common/56 custom target/my_compiler.py index 4ba2da64e..f46d23a91 100755 --- a/test cases/common/56 custom target/my_compiler.py +++ b/test cases/common/56 custom target/my_compiler.py @@ -1,16 +1,21 @@ #!/usr/bin/env python3 +import os import sys +assert(os.path.exists(sys.argv[3])) + +args = sys.argv[:-1] + if __name__ == '__main__': - if len(sys.argv) != 3 or not sys.argv[1].startswith('--input') or \ - not sys.argv[2].startswith('--output'): - print(sys.argv[0], '--input=input_file --output=output_file') + if len(args) != 3 or not args[1].startswith('--input') or \ + not args[2].startswith('--output'): + print(args[0], '--input=input_file --output=output_file') sys.exit(1) - with open(sys.argv[1].split('=')[1]) as f: + with open(args[1].split('=')[1]) as f: ifile = f.read() if ifile != 'This is a text only input file.\n': print('Malformed input') sys.exit(1) - with open(sys.argv[2].split('=')[1], 'w') as ofile: + with open(args[2].split('=')[1], 'w') as ofile: ofile.write('This is a binary output file.\n')