Chapter 6. Task encapsulation using task generators

Table of Contents

Explicit rules for simple transformations (Make-like)
Implicit processing based on file name or extension
Custom processing by task generator methods
Task generator method execution

Although task instances may be created directly, they act like global variables in the scripts, and they may lead to the creation of spaghetti code. The containers named task generators are used for creating the tasks and keeping track of them.

Explicit rules for simple transformations (Make-like)

For simple transformations, a make-like scheme enables the creation of tasks by means of task generators. The task is created lazily, for example only if waf is called from a subdirectory of the project containing the declaration.

Simple rules

The following examples illustrate how to perform simple rule-based transformations, the attribute rule is mandatory, but the input or output files are optional:

	bld.new_task_gen( 1
		source='wscript',
		target='test.k1',
		rule='cp ${SRC} ${TGT}'
	)

	bld.new_task_gen( 2
		source='wscript',
		rule='echo ${SRC}'
	)

	bld.new_task_gen( 3
		target='test.k3',
		rule='echo ${PREFIX} > ${TGT}',
	)

	bld.new_task_gen( 4
		rule='echo 1337'
	)
		

1

A basic example with an input and an output. The task is run whenever the input or the rule change

2

The task will run whenever the input or the rule change, but there is no output

3

Creates a task with no input, the output is regenerated whenever the PREFIX variable changes

4

Creates a task without inputs our outputs, it is run whenever the rule text changes

Advanced features

The next examples illustrate various attributes which may be used to alter task execution.

	bld.new_task_gen( 1
		rule="echo 'task always run'",
		always=True
	)

	bld.new_task_gen( 2
		source = 'wscript',
		target = 'test.k',
		rule = './create.py && mv ${TGT[0].abspath()} ${TGT[0].abspath(env)}',
		cwd = bld.path.abspath(),
		before = 'test.k1'
	)

	def run(self):
		print('hi there')

	bld.new_task_gen( 3
		name = 'hi',
		rule = run
	)

	bld.new_task_gen( 4
		name = 'svnversion',
		target = 'ver.h',
		rule = 'svnversion > ${TGT[0].abspath(env)}',
		cwd = bld.path.abspath(),
		always = True,
		on_results = True
	)

	bld.new_task_gen(
		name = 'copy_svnversion',
		after = 'svnversion',
		source = 'ver.h',
		target = 'ver2.h',
		rule = 'cp ${SRC} ${TGT}'
	)
			

1

Make a task which is always run (attribute always)

2

Demonstrates how to add an ordering constraint (attribute before) to execute the rule before the one that produces test.k1. It also demonstrates how to set the directory from which the command is run (attribute cwd)

3

Rules may be given as functions. In this case the task has no input or output files

4

the dependant task copy_svnversion is executed when the actual output of svnversion changes (attribute on_results)

By binding the rule to the actual declaration, this system limits code reuse. For this reason, it is recommended for solving very specific problems in which a library would not make sense. The creation of lots of small rules may also impact performance negatively.