Experiments with using waf to build Samba
As I mentioned previously, I've been experimenting with using waf for Samba builds. So far it looks very promising. The waf maintainer is being extremely helpful.
I've added 'wscript' waf rules for libreplace, tevent, tdb, talloc and ldb. Configure, build, install all work. The build in source4 partly works.
I've set it up so builds appear in bin/ (so if building in source4/lib/ldb then you get source4/lib/ldb/bin/ldbadd for example). This keeps the current workflow we use in Samba development.
rpath is used so the binaries can be run directly (so no stuffing about with LD_LIBRARY_PATH etc for gdb, valgrind and other testing)
all built files (object, libs, binaries) are in bin. The source tree is never modified. If you do "rm -rf bin" then you're back to a pristine tree.
I've also written a script to auto-convert our existing config.mk files for Samba4 to wscript_build scripts. This would allow us to run the two build systems in parallel with very little pain, as you run one script to re-generate all the waf build scripts.
The full Samba4 build is not working yet. I still have quite a bit to do on the rules for pidl, asn1, errtable etc, plus rules for how we will handle library dependencies.
waf is certainly fast. It uses full content hashing for dependencies, but so far that hasn't been a problem. It also has a 'wafcache' which is a ccache like system, but that applies to all builds, so it will safely cache pidl, asn1, libraries, configure checks etc.
The main thing I've learned from trying this is that the build rules for Samba4 are very complex, and do not lend themselves to a simple representation. We have 485 build targets in the Samba4 tree (ie. subsystems, modules, binaries, libraries etc).
Getting the code
You need to do a git checkout of the waf-wip branch like this:
git clone git://git.samba.org/tridge/samba.git samba-waf cd samba-waf git checkout -b waf-wip origin/waf-wip
To update your checkout when something has changed, run this:
cd samba-waf git pull --rebase
Trying it out
This is highly experimental at the moment, but if you do want to give it a go then try this:
- setup your PATH to point at the buildtools/ directory in the root of the Samba sources
- don't install waf on your system, instead use the one in buildtools/. This ensures we are all always using the same version.
- to enable the wafcache (which speeds things up a lot), do this:
export WAFCACHE=$HOME/.wafcache mkdir -p $WAFCACHE
- now try one of the trees that have been converted to waf. For example, to try the tdb tree do this:
cd lib/tdb waf configure --enable-developer --prefix=$HOME/testprefix waf
- If you are installing to a place that is not in your system library path, then you might like to use --enable-rpath
waf configure --enable-developer --prefix=$HOME/testprefix --enable-rpath
- that will configure tdb and build the binaries in lib/tdb/bin/. To install them use:
- The other trees that have been converted are lib/replace, lib/talloc, lib/tevent and source4/lib/ldb
The current waf-wip branch can partly build Samba4. This is still very experimental, but if you want to try it, then try this:
cd samba-waf/source4 waf configure --enable-developer waf -v # this will fail waf -v --target=samba # this should work
The double waf command is needed because of bugs in the current wafsamba rules. This won't be needed once the full Samba4 build is working.
Try "waf --help" for help on using waf. Try "waf configure --help" for the equivalent of "./configure --help". I haven't added all of our Samba configuration options yet, but I've put in a few (such as --enable-developer). See lib/replace/wscript for how these are added.
You may also find "waf -v" useful for seeing the build commands. Or use "waf -v clean build" to clean and build a tree, with the commands shown. Use "waf -p" to show a progress bar on the build.
This command illustrates the use of multiple build directories:
waf configure --enable-developer -b devbuild
It ends up creating the binaries in devbuild instead of the default of bin/.
If you want to debug why something isn't working, then you can either increase the verbosity of waf with something like "waf -vvv", or you can enable tracing of a particular phase of the build. For example, you could trace the build dependencies like this:
waf -v --zone=deps
It is sometimes useful to disable the wafcache when debugging. use the --nocache option for that:
waf -v --nocache clean build
How it works
Each project within Samba (tdb, ldb, talloc etc) gets a wscript file. That file can depend on other project wscript files. I've kept the wscript files for each project simple by using a 'waf tool' called 'wafsamba.py', which is an add-on for waf that sets up the waf configuration and build commands to follow the same sorts of conventions that we have in the existing Samba4 build system.
If you want to have a look at how this was done, then look in buildtools/wafsamba/. You will notice that I've put a lot of paranoia checking in there, as I've found that the exiting config.mk files for the bulk of Samba4 contain some 'interesting' features, such as dependency loops and missing dependencies.
The waf build rules are very simple, and easy to modify. For example:
- the rules for building tdb are here lib/tdb/wscript
- the rules for ldb are here source4/lib/ldb/wscript
- the rules for libreplace, which include most of our configure checks, are here lib/replace/wscript
- the 'wafsamba' waf tool which allows us to describe samba build rules succinctly are here buildtools/wafsamba/wafsamba.py
Adding new commands
In Samba we are used to a number of non-standard make targets, such as 'make quicktest'. We can add the same targets using waf. Even better, when you add a new target in waf it shows up in 'waf --help'. To give an example, I've added a selftest/wscript here source4/selftest/wscript. As you can see, it adds a 'test' and 'quicktest' target. Now if we run 'waf --help' we get this:
Main commands (example: ./waf build -j4) clean : removes the build files configure: configures the project dist : makes a tarball for redistributing the sources distcheck: checks if the sources compile (tarball from 'dist') distclean: removes the build directory install : installs the build files quicktest: Run the quick test suite test : Run the full test suite uninstall: removes the installed files
The commands themselves are arbitrary python. The simplest first approach will be to call our existing perl based testsuite. Then if we wish to convert it to python later we can.
waf itself is documented in a online book here: http://freehackers.org/~tnagy/wafbook/single.html
The build rules I've added for Samba would also need to be documented if we adopt waf, probably by annotating wafsamba.py.
Converting libreplace, talloc, ldb etc was easy. The hard bit comes when trying to do a full Samba4 build. If you want to see what I've doing for that, have a look in buildtools/mktowscript/. That contains an extremely hackish perl script that converts our existing .mk files to wscript_build files.
You can see an example auto-generated waf build file for the dsdb/ subsystem of Samba4 here source4/dsdb/wscript_build
I think the resulting auto-generated file compares quite favourably to the original config.mk that it was generated from source4/dsdb/config.mk
There is a lot more work to do before we can build Samba3 and Samba4 fully with waf, but this should give you some idea of the approach I am taking.
A short list of work items, not complete!
make waf builds works from subdirectories
You could be able to "cd source4/client" and run waf
fix 'waf test'
full testsuite needed
speedup null build
a null build (waf build when build is already complete) takes about 6 seconds. It needs to be less than 1 second. I know how to fix this, and hope to get to it soon