9.5. Traits

In abuild, it is possible to assign certain traits to a build
item. Traits are a very powerful feature of abuild. This
material is somewhat more complicated than anything introduced up
to this point, so don't worry if you have to read this section
more than once.

Traits are used for two main purposes. Throughout this material,
we will refer back to the two purposes. We will also provide
clarifying examples later in the chapter.

The first purpose of traits is creation of semantically defined
groups of build items. In this case, a trait corresponding to
the grouping criteria would be applied to a build item directly.
For example, all build items that can be deployed could be
assigned the deployable trait.

A second purpose of traits is to create specific relationships
among build items. These relationships may or may not correspond
to dependencies among build items. These traits may be applied
to a build item by itself or in reference to other build items.
For example, the tester trait may be applied
to a general system test build item by itself and may be applied
to every test suite build item with a reference to the specific
item being tested.

Traits are used to assist in the construction of build sets. In
particular, you can narrow a build set by removing all items that
don't have all of a specified list of traits. You can also
expand a build set to add any build items that relate to any
items already in the set by referring to them through all of a
specified list of traits. This makes it possible to say things
like “run the deploy target for every
build item that has the deployable
trait,” or “run the test target
for every item that tests my local build item or anything it
depends on.”

Since traits are visible in abuild's --dump-data
output (see Appendix F, --dump-data Format), they are available
to scripts or front ends to abuild. They may also be used for
purely informational purposes such as specifying the
classification level of a build item or applying a uniform label
to all build items that belong to some group. Trait names are
subject to the same constraints as build item names: they are
case-sensitive and may consist of mixed case alphanumeric
characters, numbers, underscores, dashes, and periods. Unlike
with build items, the period does not have any semantic meaning
when used in a trait name.

Starting with abuild 1.1.6, a build item that uses either the
GNU Make backend or the Groovy backend (but not the deprecated
xml-based ant backend) may also get access to the list of traits
that are declared in its Abuild.conf file.
For the GNU Make backend, the variable
ABUILD_TRAITS contains a list of traits
separated by spaces. For the Groovy backend, the variable
abuild.traits contains a groovy list of traits
represented as strings. In both cases, any information about
referent build items is excluded; only the list of declared
traits is provided. Possible uses for this information would
include having a custom rule check to make sure a given trait is
specified before providing a particular target, having it give an
error if a particular trait is not defined, or even having it
change behavior on the basis of a trait.

9.5.1. Declaring Traits

Any named build item may include a traits
key that lists one or more of the traits that are supported in
its build tree. The list of traits supported in a build tree is
given as the value of the supported-traits
key in the root build item's Abuild.conf.
The list of supported traits is inherited through tree
dependencies, so any trait declared as valid in any trees your
tree depends on are also available. The set of traits that can
be specified on the command line is the union of all traits
allowed by all known trees.

Traits listed in the traits key can be made
referent to other build items by listing the other build items
in an -item option. For example, the following
Abuild.conf fragment declares that the
potato.test build item is deployable,
unclassified, and a tester for the
potato.lib and
potato.bin build items:

9.5.2. Specifying Traits at Build Time

To modify the build set or clean set based on traits, use the
--only-with-traits and
--related-by-traits command-line options to
abuild. These options must be combined with the specification
of a build set. They correspond to the two purposes of traits
discussed above.

To build all build items that have all of a specified list of
traits, run abuild
--build=set --only-with-traits
trait[,trait,...].
This is particularly useful when semantically grouped build
items share a common custom target. For example, if all the
deployable build items had a special deploy
target, you could run the deploy target for
all deployable items in the local build tree with the command

abuild --build=local --only-with-traits deployable deploy

If multiple traits are specified at once, only build items with
all of the specified traits are included.

Once a build set has been constructed, you may want to add
additional items to the set based on traits. Specifically, you
may want to add all items related by a trait to items already in
the build set. To expand a build set in this way, run
abuild --build=set
--related-by-traits
trait[,trait,...]
For example, if you wanted to run the test
target for all build items that are declared as testers (using
the tester trait) of your build item or any
of its dependencies, you could run the command

abuild --build=current --related-by-traits=tester test

As above, if multiple traits are specified at once, only build
items that are related by all of the specified traits are
included. Note that the same trait may be used referent to
another build item or in isolation. The
--related-by-traits option only applies to
traits used in reference to other build items. For example, if
a build item had the tester trait not
referent to any build item, it would not be picked up by the
above command. The --only-with-traits option
picks up all build items that have the named traits either in
isolation or referent to other build items.

It is also possible to combine these options. In that case, the
build set is first restricted using
--only-with-traits and then expanded using the
--related-by-traits as shown in examples below.
The order of the arguments has no effect on this behavior.

Ordinarily, when a specific target is specified as an argument
to abuild (as in abuild test or
abuild deploy rather than just
abuild), abuild runs that target for every
item initially in the build set (before dependency expansion).
When the build set is expanded or restricted based on traits,
any explicitly specified targets are run only for build items
that have the specified traits. This is important because it
enables you to use traits to group build items that define
specific custom targets.

If --related-by-traits and
--only-with-traits are both specified, any
explicit targets are applied only to traits named in
--related-by-traits as the effect of that
option is applied last. All other build items are built with
the all target. Note that the
--apply-targets-to-deps option will cause any
explicit targets to be applied to all build items, as always.
Later in this chapter, we review the exact rules that abuild
uses to decide which targets to apply to which build items.

The --list-traits flag provides information
about which traits can be used on the command line. To see more
detailed information about which traits were made available in
which build trees, you can examine the output of abuild
--dump-data (see Appendix F, --dump-data Format).

9.5.3. Example Trait Invocations

Run the deploy target for all items at or
below the current directory that have the
deployable trait, and run the
all target for all items that they depend
on.

abuild --build=current --related-by-traits
tester test

Build the current build item and all of its dependencies with
the all target, and run the
test target for any build items that
declared themselves as a tester for any of those items. Any
additional dependencies of the testers would also be built
with the all target.

abuild --build=local --only-with-traits
deployable,tester deploy test

Run both the deploy and the
test targets for any build items in the
local build tree (the current build item's tree excluding its
tree dependencies) that have both the
deployable and the
tester traits either specified alone or
in reference to other build items. Run the
all target for their dependencies.

Run the all target for all items that have
the requires-hw trait as well as any of
their dependencies, and run the hwtest
target for all items that test any of them. Additional
dependencies of the testers would also be built with the
all target.