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
tree-name: common child-dirs: lib1 lib2 lib3 supported-traits: tester
This is a root build item configuration file, as you can see by
the presence of the tree-name key. Notice
that it lacks a name 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 9.5, “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
name: common-lib1 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 is a good way to help ensure that you
do not create conflicting build item names. However, you should
avoid creating build item names that slavishly follow your
directory structure since doing so will make it needlessly
difficult for you to move things around. A major feature of
abuild is that nothing cares where a build item is located, so
don't set a trap for yourself in which you have to rename a build
item when you move it!
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
name: common-lib1.src platform-types: native
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. You should also
avoid paths that point into other build items. Instead, depend
on the other item and put the variable there. As a rule, if you
ever have two interface variables or assignments that resolve to
the same path, you are probably doing something wrong: a
significant feature of abuild is that allows you to encapsulate
the location of any given thing in only one place. Instead,
figure out who owns a given file or
directory and export it from that build item's interface. 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
name: common-lib1.test platform-types: native 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 9.5, “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
name: common-lib2.src platform-types: native deps: common-lib3
We will return to this build tree later to study build sets, traits, and examples of various ways to run builds.