wscript file headers

2011-07-03 13:52:00 +0200

A few users have asked why the wscript files usually include the following header if they are not meant to be executed directly:

#! /usr/bin/env python
# encoding: utf-8

Several benefits have been observed over the time, and it appears that this header is a best practice:

  • Most text editors - especially on unix-like systems - will read the first line beginning by #! to apply proper syntax highlighting. Your text editor may well display the file properly, but others may not.
  • If the wscript files are ever meant to be executed, then:
    1. The process will not hang when called as ./wscript (the 'import' program takes screenshots)
    2. The /usr/bin/env will redirect the interpreter to the adequate python executable (python can be installed in /usr/local or /opt for example)
  • The encoding declaration will prevent special characters such as €, é or í from causing errors

When a wscript file is created for the first time, it may have to be reloaded to force the text editor to take the file type into account. In Vim at least, a mapping can be added to save the hassle of re-opening the file:

au BufNewFile,BufRead wscript* set filetype=python

Running Waf on different Python interpreters

2011-05-22 13:47:00 +0200

IronPython 2.7 now provides a subprocess module, and the good news is that Waf will be able to run on it. The changes are only in Waf head for now, they will be available in Waf 1.6.5 once a remaining issue is resolved (the logging module behaves differently on IronPython).


A few of you may be curious to know how well Waf performs on different python interpreters. Different propjects may have different requirements, so the tests are always biased in one way or another. Among all the tests considered so far, the genbench script provides a good balance between project size, process execution, regexps and parsing. The numbers collected represent the best run in in five executions:
./genbench.py /tmp/build 50 100 15 5
cd /tmp/build
waf clean; time waf build -p -j3

On Windows XP, the IronPython runtime is fairly close to the Pypy one. And Pypy 1.5 did not complete normally (file descriptor leak).

Windows XP
cPython 2.7 IronPython 2.7 Pypy 1.5
1m54 2m14 2m05

IronPython requires .NET 4, and it would not run on Linux using Mono 2.10.2. It is no surprize that the test completes faster as spawning new processes (fork) is slower on Windows. Pypy 1.5 could not even complete normally once in about 10 runs.

Linux
python 2.6.5 python 3.2 jython 2.5.2
1m41 1m41 5m30

For the moment, the best interpreter remains cPython for both portability and performance.

Debugging tools

2011-04-30 12:29:00 +0200

Trying to trace or to debug a build almost always incurs a performance penalty. The most important tool is included by default but only enabled when calling waf with the verbose option (waf -v). Others are present in the waflib/extras folder and are not included by default. They can be added to the waf file or downloaded by calling "waf update --files=parallel_debug,why"

The module "why" provides some more output to help understanding why files are being compiled. It requires a fresh recompilation though, and inflates the cache files significantly as it stores some data between the builds. The output will display the task signatures and the reason of the execution:

12:26:20 /comp/waf/demos/c> ./waf build --zones=task
Waf: Entering directory `/disk/comp/waf/demos/c/build'
12:26:21 task -> Task must run : c3490b5e8498da72aef5a9f645d72276 39da3e173d11cdbb273cda14856dbb6a
12:26:21 task -> * Source file or manual dependency : 3d3fde4f5fc0124efdba8e94e1d216f8 5e4ef70cc1618412ef9975baab0157c1
[12/15] c: program/main.c -> build/program/main.c.1.o
Waf: Leaving directory `/disk/comp/waf/demos/c/build'
'build' finished successfully (0.089s)

For performance debugging, the module parallel_debug creates pictures representing when tasks are executed during the build. The diagrams show how well the build can be distributed, and therefore how fast the build can be. Generating the diagrams incurs a minor performance penalty, which is the reason why this tool is not included by default in the waf file.

It has been updated recently to improve the layout, now tooltips are present in the svg output file. Follow the links to consult the diagrams of the Samba 4 developer build for 2 processors and for 8 processors.

Colors in cmd

2011-04-30 09:37:00 +0200

The cmd window looks terrible compared to rxvt/xterm ones, and unlike others, cmd is unable to interpret ANSI escape codes. The module ansiterm has been been bringing happy colors in cmd and other consoles since 2008. It wraps sys.stdout/sys.stderr in an object which intercepts the escape codes to provide the coloring by using a few functions from the windll module.


The progress bar, which was broken for a long time, is even displayed properly (waf 1.6.4):




The display in msys it also known to work in waf 1.6:


Right now, the progress bar cannot display the very last characters on Windows Vista (issue 931). The platform-specific and underdocumented functions from the module windll make it very difficult to understand and fix the problems though
windll.kernel32.FillConsoleOutputCharacterA

New python projects resembling ansiterm.py have appeared recently, here are for example:

* Colorama
* Colorconsole

Both also split the small amount of code into several files, which make the re-use only more difficult, and neither seems to support clearing single lines, which is mandatory for displaying progress bars properly.

Python 3.2, and the build system kit

2011-01-08 17:50:00 +0100

The new "concurrent.futures" module from Python 3.2 will now make it even easier to execute tasks concurrently. We never miss an opportunity to remove some code so we had to try it, some functionality being similar to the contents of the Runner module.

First, we could not remove a much code as we hoped: fewer than 20 lines, most of the code being in the synchronization and the exception handling anyway. Then we met a surprising performance degradation linked to the creation of circular references.

Finally, the Python executor appeared to increase the builds by a few seconds on our build benchmarks, so we finally gave up.

The executor API looks good though, and many developers will be tempted to try to create new python-based build systems from it. Executing tasks represents only a very small part of what one expects in a build system though:

  • A system for handling commands and command-line options
  • A system of (task) order and dependencies
  • A handler for exceptions and user errors
  • A usable system (a very difficult problem)
  • An extension system for new programming languages
  • A portable system (not limited to Python 3.2)
  • Adequate performance (it is so easy to over synchronize or to write bad algorithms)

Developers seem to underestimate the amount of work required to make a system work for more than one or two projects (Waf has had nearly 11000 revisions in 6 years). Specialized and incomplete build scripts are still popping up. Just to name a few python-based ones:

The fragmentation seems unavoidable, and the situation is probably going to be similar to that of operating systems or programming languages, with a few big players and tons of niche projects.

If it must happen, then let it happen properly, at least. Starting in version 1.6.2, the Waf framework features a new build system kit which enables the creation of new build systems. By re-using the tested and maintained components from the Waf framework, much more time can be spent on more interesting problems such as creating an intuitive XML/YAML/JSON schema (if you believe that IDEs should edit your scripts) or creating a domain-specific programming language (make-like, cmake-like, ... ?), or extracting commands and dependencies to create derivated files (Makefiles, Visual studio, ...)

The few examples illustrate the possibilities offered by the Waf framework:

  • overview: Create a file using the Waf components to perform simple builds that do not use wscript files
  • parser: Add a parser for a domain-specific language, and create a file able to build targets from specific files
  • noscript: Create a file able to build targets without using a script file, finding the source files from header dependencies
  • nostate: Create a make-like build system that does not use build files (timestamps only)
  • makefile_dumper: Use the Waf API to dump the build decription into a makefile
Have a look and think of the kittens before trying to start a build system from scratch.