Generated by:
Craftsman

Craftsman Master-Child Build Setup


If you have more than two modules and the modules start depending on one another, it is always a good idea to consider the Master-Child setup. Instead of defining a separate build.xml, with module definitions, library definitions, etc in each module directory, you put all the definitions in one file in the parent directory and have the module build.xml just defer to it.

This is the standard "sub Ant" call or "recursive Make" call that inevitably pops up in a project. In the end, it is easier to maintain for larger projects, as it makes library declarations or module dependencies easier to manage.

An Example (The Foo-Bar App)

Original Setup

Let's say you have a project called "foobar", built from the foo and bar modules. You may have the following in the foobar/foo/build.xml:
    <!-- Libraries common to all modules -->
    <library id="rsh-commons" name="rsh-commons" externaldir="../lib/rsh-commons"/>
    <library id="log4j" name="log4j" externaldir="../lib/log4j"/>
    <library id="junit" name="junit" externaldir="../lib/junit" testlib="true"/>
    
    <!-- define the modules for this package -->
    <craftsmandef>
        <module moduleid="foo">
            <library refid="rsh-commons"/>
            <library refid="log4j"/>
            <library refid="junit"/>
        </module>
    </craftsmandef>

And then you might have something like the following in the foobar/bar/build.xml:

    <!-- Libraries common to all modules -->
    <library id="rsh-commons" name="rsh-commons" externaldir="../lib/rsh-commons"/>
    <library id="log4j" name="log4j" externaldir="../lib/log4j"/>
    <library id="junit" name="junit" externaldir="../lib/junit" testlib="true"/>
    
    <!-- define the modules for this package -->
    <craftsmandef>
        <module moduleid="bar">
            <dependency moduleid="foo" dir="../foo"/>
            <library refid="rsh-commons"/>
            <library refid="log4j"/>
            <library refid="junit"/>
        </module>
    </craftsmandef>

These modules havea dependency, but their build setup is independent of one another. If you change the location of the rsh-commons lib, you have to do it in both files. If you add another library to foo, you have to change both files.

Master-Child Setup

Changing this to a Master-Child is actually pretty easy. Copy the build.xml from foo to foobar. Also make sure you have a bootstrap.xml in the foobar directory that points to the right location for the bootstrap. Then take the contents of foobar/bar/build.xml and add the module def to the new parent build.xml. Your foobar/build.xml now looks like this:

...
    <!-- Libraries common to all modules -->
    <library id="rsh-commons" name="rsh-commons"/>
    <library id="log4j" name="log4j""/>
    <library id="junit" name="junit"testlib="true"/>
    
    <!-- define the modules for this package -->
    <craftsmandef>
        <module moduleid="foo">
            <library refid="rsh-commons"/>
            <library refid="log4j"/>
            <library refid="junit"/>
        </module>
        <module moduleid="bar">
            <dependency moduleid="foo"/>
        </module>
    </craftsmandef>
    ...
Notice you no longer need the "externaldir" attribute for the <library> tags.

With that in place, test the build by going to "foobar" and calling the build:

 /YouHome/src/foobar$ ant clean build 
If the build succeeds, you have the Master setup. Now for the Child.

Download the child-build.xml and put it in your foo module directory.

Create something like the following in the foobar/foo/build.xml:

<project name="foo" default="all">

    <property name="build.module.name" value="${ant.project.name}"/>

    <import file="child-build.xml"/>

</project>
Test the file by switching to the foobar/foo directory and calling "ant clean build". The build should succeed. You can now call clean, build, test, doc, and more based on what is in the child-build.xml file.

If the build succeeds, copy the build.xml and child-build.xml from foobar/foo to foobar/bar. Then change the project name for the foobar/bar/build.xml file from foo to bar. The file will then call the targets for bar.

You can now build the modules individually (from the parent or the child directory) or all the modules (from the parent).