The function build indicates the start of the actual construction of the software, it is used for two main purposes:
The function build may reference build functions in wscript present in sub folders, for example:
. `-- wscript |-- src | `-- wscript
The top-level wscript may indicate there is a build function to execute in src/wscript using:
def build(bld): bld.add_subdirs('src')
The wscript files that are not on the top-level often contain a large build function, with no additional configuration or command-line options. In this case the file only contain one method and the indentation is an annoyance. For this reason, the wscript_build files contain the body of a build function defined in a wscript file. A folder may only contain either a wscript or a wscript_build but not both.
The process of building a piece of software require the transformation of source code (input) into the result (output). Since the source code is usually split in various files, the construction of the result requires the processing of each of the files. Several new concepts derive from this:
In a more general scope, the input necessary for a build may come from arbitrary data instead of files (database, commands to execute). The concepts of input, output and transformation and the transformation constraints (in parallel, in sequence) remain identical.
In Waf, the operation of transforming data is performed by tasks, which are instances of the class TaskBase (in the Waf library). The tasks in the following example illustrate the declaration of Tasks from the base class. The task instances must be located in a build context (the function build) to be taken into account in the build phase, and to obtain the reference on the source and build folders:
srcdir = '.' blddir = 'build' def set_options(opt): pass def configure(conf): pass import Task class task_test_a(Task.TaskBase): pass class task_test_b(Task.TaskBase): after = 'task_test_a' def build(bld): tb = task_test_b() ta = task_test_a()
The execution trace will be the following:
$ waf configure Configuration finished successfully (00:00:00); project is now ready to build. $ waf [0/2] task_test_a [1/2] task_test_b Compilation finished successfully (00:00:00)
In practice, when lots of tasks are declared one by one, scripts tend to become complicated, and contain a lot of redundant code. Special objects named task generators are provided to facilitate the creation of several tasks at once. In the following example, a task generator is used to create the compilation and link tasks needed by a c++ project.
srcdir = '.' blddir = 'build' def configure(conf): conf.check_tool('gcc') def build(bld): bld.new_task_gen(features='cc cprogram', source='main.c test.c', target='myapp')
This example provides a modified configure function, which is the topic of the next section. The task generator system and the default generators will be reviewed in detail in Chapter 6, Task encapsulation using task generators.