6.4. Simple Build Tree Example

Now that the topic of build items and build trees has been explored in somewhat more depth, let's take a look at a simple but complete build tree. The build tree in doc/example/general/reference/common illustrates many of the concepts described above.

The first file to look at is the Abuild.conf belonging to this tree's root build item:

general/reference/common/Abuild.conf

child-dirs: lib1 lib2 lib3
supported-traits: tester

This is a root build item configuration file. Notice that it lacks a this key, as is often the case with the root build item. This Abuild.conf contains the names of some child directories and also a build tree attribute: supported-traits, which lists the traits that are allowed in the build tree. We will return to the topic of traits in Section 8.3, “Traits”. In the mean time, we will direct our focus to the child build items.

The first child of the root build item of this tree is in the lib1 directory. We examine its Abuild.conf:

general/reference/common/lib1/Abuild.conf

this: common-lib1
parent-dir: ..
child-dirs: src test
deps: common-lib1.src

This build item is called common-lib1. Notice that the name of the build item is not the same as the name of the directory, but it is based on the name of the directory. This is a typical strategy for naming build items. Abuild doesn't care how you name build items as long as they conform to the syntactic restrictions and are unique within a build tree. Coming up with a naming structure that parallels your system's architecture and/or your file system layout is a good way to help ensure that you do not create conflicting build item names.

This build item does not have any build or interface files. It is a pass-through build item. It declares a single dependency: common-lib1.src, and two child directories: src and test.

Next, look at the common-lib1.src build item's Abuild.conf in the common/lib1/src directory:

general/reference/common/lib1/src/Abuild.conf

this: common-lib1.src
platform-types: native
parent-dir: ..

The first thing to notice is this build item's name. It contains a period and is therefore private to the common-lib1 scope. That means that it is not accessible to build items whose names are not also under that scope. In particular, a build item called common-lib2 would not be able to depend directly on common-lib1.src. It would instead depend on common-lib1 and would inherit the dependency on common-lib1.src indirectly.

This build item doesn't list any child directories and, as such, is a leaf in the file system hierarchy. It also happens not to declare any dependencies, so it is also a leaf in the dependency tree, though one does not imply the other. This build item configuration file contains the platform-types key, as is required for all build items that contain build or interface files. In addition to the Abuild.conf file, we have an Abuild.mk file and an Abuild.interface file:

general/reference/common/lib1/src/Abuild.mk

TARGETS_lib := common-lib1
SRCS_lib_common-lib1 := CommonLib1.cpp
RULES := ccxx

general/reference/common/lib1/src/Abuild.interface

INCLUDES = ../include
LIBDIRS = $(ABUILD_OUTPUT_DIR)
LIBS = common-lib1

There is nothing in these files that is fundamentally different from the basic C++ library example shown in Section 3.4, “Building a C++ Library”. We can observe, however, that the INCLUDES variable in Abuild.interface actually points to ../include rather than the current directory. This simply illustrates that abuild doesn't impose any restrictions on how you might want to lay out your build items, though it is recommended that you pick a consistent way and stick with it for any given build tree. We will not study the source and header files in this example here, but you are encouraged to go to the doc/example/general/reference/common directory in your abuild source tree or installation directory to study the files further on your own.

Next, look at the test directory. Here is its Abuild.conf:

general/reference/common/lib1/test/Abuild.conf

this: common-lib1.test
platform-types: native
parent-dir: ..
deps: common-lib1
traits: tester -item=common-lib1.src

Notice that it declares a dependency on common-lib1. Since its name is also private to the common-lib1 scope, it would have been okay for it to declare a dependency directly on common-lib1.src. Declaring its dependency on common-lib1 instead means that this test code is guaranteed to see the same interfaces as would be seen by any outside user of common-lib1. This may be appropriate in some cases and not in others, but it demonstrates that it is okay for a build item that is inside of a particular namespace scope to depend on its parent in the namespace hierarchy. This build item also declares a trait, but we will revisit this when we discuss traits later in the document (see Section 8.3, “Traits”).

In addition to the lib1 directory, we also have lib2 and lib3. These are set up analogously to lib1, so we will not inspect every file. We will draw your attention to one file in particular: observe that the common-lib2.src build item in reference/common/lib2/src declares a dependency on common-lib3:

general/reference/common/lib2/src/Abuild.conf

this: common-lib2.src
platform-types: native
parent-dir: ..
deps: common-lib3

We will return to this build tree later to study build sets, traits, and examples of various ways to run builds.