Chapter 23. Interface Flags

Table of Contents

23.1. Interface Flags Conceptual Overview
23.2. Using Interface Flags
23.3. Private Interface Example

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.

23.1. Interface Flags Conceptual Overview

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