10.6. Task Branch Example

In this example, we'll demonstrate a task branch. Suppose our task branch makes changes to project but not to common. We can set up a new build tree in which to do our work. We would populate this build tree with whatever parts of project we wanted to modify. We have set up this build tree in doc/example/general/task/project. Additionally, we have set this build tree's backing area to ../../reference/project so that it would resolve any missing build items or externals to that location:

general/task/project/Abuild.backing

../../reference/project

Note that, although we used a relative path for our backing area in this example, we would ordinarily set our backing area to an absolute path. We use a relative path here only so that the examples can remain independent of the location of doc/example. Our task branch also includes the derived project. Since we are not making modifications to any build items in common, we don't have to create a build tree at task/common, even though our root Abuild.conf lists ../common as an external:

general/task/project/Abuild.conf

external-dirs: ../common
child-dirs: main lib

Since that relative path exists as a valid build tree relative to our backing area, abuild will just use ../common relative to the backing area (../../reference/project/../common, which is ../../reference/common) to resolve the external. For a diagram of the task branch build trees, see Figure 10.4, “Build Trees in general/task.

Figure 10.4. Build Trees in general/task

Build Trees in general/task

The derived build tree in the task branch declares the project build tree as an external. The project build tree in the task branch declares the common build tree as an external, but since the common build tree isn't shadowed in the task branch, that external is resolved to the reference tree instead. The derived and project build trees in the task branch both back to their corresponding build trees in reference.


As always, for this example to work properly, our backing area must be fully built. If you are following along, to make sure this is the case, you should run abuild --build=all in reference/derived. Next run abuild --build=all no-op in task/project. This generates the following output:

example.task-project-no-op.out

abuild: project-lib.src (abuild-<native>): no-op
abuild: project-lib.test (abuild-<native>): no-op
abuild: project-main.src (abuild-<native>): no-op

This includes only items in our task branch. No items in our backing area are included because abuild never attempts to build or modify build items in backing areas.

If you study include/ProjectLib.hpp and src/ProjectLib.cpp in task/project/lib in comparison to their counterparts in reference/project/lib, you'll notice that the only change we made in this task branch is the addition of an optional parameter to ProjectLib's constructor. We also updated the test suite to pass a different argument to ProjectLib. This new value comes from a new build item we added: project-lib.extra. To add the new build item, we created task/project/lib/extra/Abuild.conf: and also added the extra directory in task/project/lib/Abuild.conf:

general/task/project/lib/extra/Abuild.conf

this: project-lib.extra
platform-types: native
parent-dir: ..

general/task/project/lib/Abuild.conf

this: project-lib
parent-dir: ..
child-dirs: src test extra
deps: project-lib.src

We didn't modify anything under task/project/main at all, but we included it in our task branch so we could run its test suite. Remember that abuild won't try to build the copy of project-main there, and even if it did, that copy of project-main would not see our local copy of project-lib: it would see the copy in its own local build tree, which we have shadowed. This is an example of a shadowed dependency as described in Section 10.4, “Integrity Checks”. This is the output we see when running abuild --build=all check from task/project:

example.task-project-check.out

abuild: project-lib.src (abuild-<native>): check
make: Entering directory `--topdir--/general/task/project/lib/src/abuild\
\-<native>'
Compiling ../ProjectLib.cpp as C++
Creating project-lib library
make: Leaving directory `--topdir--/general/task/project/lib/src/abuild-\
\<native>'
abuild: project-lib.test (abuild-<native>): check
make: Entering directory `--topdir--/general/task/project/lib/test/abuil\
\d-<native>'
Compiling ../main.cpp as C++
Creating lib_test executable

*********************************
STARTING TESTS on ---timestamp---
*********************************


Running ../qtest/lib.test
lib  1 (test lib class)                                        ... PASSED

Overall test suite                                             ... PASSED

TESTS COMPLETE.  Summary:

Total tests: 1
Passes: 1
Failures: 0
Unexpected Passes: 0
Expected Failures: 0
Missing Tests: 0
Extra Tests: 0

make: Leaving directory `--topdir--/general/task/project/lib/test/abuild\
\-<native>'
abuild: project-main.src (abuild-<native>): check
make: Entering directory `--topdir--/general/task/project/main/src/abuil\
\d-<native>'
Compiling ../main.cpp as C++
Creating main executable

*********************************
STARTING TESTS on ---timestamp---
*********************************


Running ../qtest/main.test
main  1 (testing project-main)                                 ... PASSED

Overall test suite                                             ... PASSED

TESTS COMPLETE.  Summary:

Total tests: 1
Passes: 1
Failures: 0
Unexpected Passes: 0
Expected Failures: 0
Missing Tests: 0
Extra Tests: 0

make: Leaving directory `--topdir--/general/task/project/main/src/abuild\
\-<native>'

As with the no-op build, we only see output relating to local build items, not to build items in our backing areas as they are assumed to be already built.