Table of Contents
In this chapter, we will examine interface flags. Both interface flags and standard abuild interface conditionals allow us to cause a particular interface variable assignment to be evaluated only under a specific condition. When such assignments are implemented inside normal abuild interface conditional blocks, all depending build items will see the results of such assignments in the same way (as would be typical of any variable assignment system). With interface flags, it is possible to have different build items see the effects of different assignments to certain variables, a concept we describe in greater depth below. This is an unusual capability, but it is very useful for implementing private interfaces. In this chapter, we will explore interface flags in enough detail to see how to use them to implement private interfaces, which is their primary use.
If there were a contest to select the most unusual feature of abuild, interface flags would probably be the strongest contender for the prize. This section presents a conceptual overview that should be good enough to enable you to make use of interface flags to implement private interfaces. We provide a private interface example at the end of this chapter. In order to provide a conceptual overview of how interface flags work, we will present a partial but accurate explanation of how they work, and we will focus our attention on list variables only. To understand interface flags in full detail, see Section 33.7, “Implementation of the Abuild Interface System”.
Every build item in abuild, whether it has an
Abuild.interface
file or not, has an
abuild interface. The abuild interface for a build item is
the union of all the interfaces of all its dependencies, taken in
dependency order, along with its own
Abuild.interface
, if any. To understand
what we mean by the “union” of abuild interfaces,
you have to know a little bit about how abuild stores
interfaces.
Recall that abuild interface files contain a series of variable
declarations and assignments, and that variables may be declared
in one file and assigned to in other files. In particular, it is
standard operating procedure for numerous
Abuild.interface
files to all assign to the
same list variables (INCLUDES
,
LIBDIRS
, LIBS
,
abuild.classpath
, etc.). As abuild reads
interface files and encounters multiple assignments to the same
list variable, it doesn't actually update some internal notion of
that variable's value as you might suspect. Rather than storing
the values of variables in a build item's interface, abuild
actually retains a list of all the assignments to a given
variable throughout all the relevant
Abuild.interface
files. This enables
abuild to compute the values of variables when they are needed.
When we say that an abuild interface is the union of the
interfaces of its dependencies, what we really mean is that the
value of each interface variable comes from the union of all
assignments to those variables across all the dependencies'
interface files.
There are two different times when abuild computes the value of
an interface variable. The first is when that variable is
expanded in an Abuild.interface
file using
the $(VARIABLE)
syntax. The second is when
abuild generates the dynamic output file as introduced in Section 17.1, “Abuild Interface Functionality Overview”. In each
case, abuild computes the value of a variable by looking at all
the assignments it knows about at that time and combining them
together based on whether the list variable is an
append list or a prepend list. Either
way, since abuild has a history of all assignments to the
variable, it has everything it needs to compute the value of the
variable.
Now this is where flags come in. As we saw in Section 17.2, “Abuild.interface Syntactic Details”, it is
possible to associate a given variable assignment with an
interface flag. When a variable assignment is associated with an
interface flag, abuild simply stores this fact in the list of
assignments to the variable. When it is time to compute a value
for the variable, abuild filters out all assignments that are
associated with a flag that isn't set. Consider the following
example. Suppose the variable VAR1
is
declared as an append list of strings,
and that you have the following assignments to
VAR1
:
VAR1 = one flag flag1 VAR1 = two VAR1 = three
If you evaluate this sequence of assignments with the
flag1 flag set, the value of
VAR1
would be one two
three
. If you evaluate this list of assignments
without the flag1 flag
set, the value of VAR1
would just be
one three
.
Here is a subtle but important point. You don't really have to
understand it to make use of private interfaces, but if you can
understand it, you will be well on your way to grasping how
interface flags really work. This handling of interface flags
means that the value of a variable is based on the collection of
flags that are set when its value is
computed. As we already noted, there are two
instances in which abuild computes the values of variables:
when it encounters a variable expansion while reading
Abuild.interface
files, and when it creates
dynamic output files. Interface flags are only set when creating
dynamic output files. At the time that
Abuild.interfaces
are being read, flags
haven't been set yet. If this worked any other way, it would not
be possible for multiple build items to see different values for
certain variables, and that is the whole reason for being of
interface flags. We defer further discussion of this point to
Section 33.7, “Implementation of the Abuild Interface System”.