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:

this: potato.test
traits: deployable tester -item=potato.lib -item=potato.bin unclassified

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).

For more detailed information about how build sets are constructed with respect to traits, please see Section 33.5, “Construction of the Build Set”.

9.5.3. Example Trait Invocations

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

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.

abuild --build=all --only-with-traits requires-hw --related-by-traits tester hwtest

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.