def do_setup(self): for listeners in self.listeners: listeners(self, 'build', None) if not isinstance(self.inputs, str): raise TypeError('Target.inputs must be str', type(self.inputs)) if not isinstance(self.outputs, str): raise TypeError('Target.outputs must be str', type(self.outputs)) if not isinstance(self.command, str): raise TypeError('Target.command must be str', type(self.command)) super().do_setup() self.command_data = [] inputs = creator.utils.split(self.unit.eval(self.inputs)) inputs = [creator.utils.normpath(f) for f in inputs] outputs = creator.utils.split(self.unit.eval(self.outputs)) outputs = [creator.utils.normpath(f) for f in outputs] context = creator.macro.MutableContext() if self.for_each: if len(inputs) != len(outputs): raise ValueError('input file count must match output file count') for fin, fout in zip(inputs, outputs): context['<'] = raw(fin) context['@'] = raw(fout) command = self.unit.eval(self.command, context) self.command_data.append({ 'inputs': [fin], 'outputs': [fout], 'command': command, }) else: context['<'] = raw(creator.utils.join(inputs)) context['@'] = raw(creator.utils.join(outputs)) command = self.unit.eval(self.command, context) self.command_data.append({ 'inputs': inputs, 'outputs': outputs, 'command': command, })
def build(self, inputs, outputs, command, each=False, stack_depth=0): """ Associated the *inputs* with the *outputs* being built by the specified *\*commands*. All parameters passed to this function must be strings that are automatically and instantly evaluated as macros. The data will be appended to :attr:`command_data` in the form of a dictionary with the following keys: - ``'inputs'``: A list of input files. - ``'outputs'``: A list of output files. - ``'command'``: A command to produce the output files. Args: inputs (str): A listing of the input files. outputs (str): A listing of the output files. command (str): A command to build the outputs from the inputs. The special variables `$<` and `$@` represent the input and output. The variables `$in` and `$out` will automatically be escaped so they will be exported to the ninja rule. each (bool): If True, the files will be built each on its own, but it expects the caller to use the ``$in`` and ``$out`` macros. """ stack_depth += 1 # Invoke the listeners and allow them to modify the input data. # Eg. a plugin could add the header files that are required for # the build to the input files. data = { 'inputs': inputs, 'outputs': outputs, 'command': command, 'auxiliary': [], 'each': each, } del inputs, outputs, command for listener in self.listeners: listener(self, 'build', data) # Evaluate and split the input files into a list. input_files = creator.utils.split(self.unit.eval( data['inputs'], stack_depth=stack_depth)) input_files = [creator.utils.normpath(f) for f in input_files] # Evaluate and split the output files into a list. output_files = creator.utils.split(self.unit.eval( data['outputs'], stack_depth=stack_depth)) output_files = [creator.utils.normpath(f) for f in output_files] context = creator.macro.MutableContext() if each: if len(input_files) != len(output_files): raise ValueError('input file count must match output file count') for fin, fout in zip(input_files, output_files): context['<'] = raw(fin) context['@'] = raw(fout) command = self.unit.eval(data['command'], context, stack_depth=stack_depth) self.command_data.append({ 'inputs': [fin], 'outputs': [fout], 'auxiliary': data['auxiliary'], 'command': command, }) else: context['<'] = raw(creator.utils.join(input_files)) context['@'] = raw(creator.utils.join(output_files)) command = self.unit.eval(data['command'], context, stack_depth=stack_depth) self.command_data.append({ 'inputs': input_files, 'outputs': output_files, 'auxiliary': data['auxiliary'], 'command': command, })