Building Variants

A-A-P home page | A-A-P Recipe Executive
--- | ---
Prev |  | Next

# Chapter 5. Building Variants

A-A-P provides a way to build two variants of the same application. You just need to specify what is different about them. A-A-P will then take care of putting the resulting files in a different directory, so that you don't have to recompile everything when you toggle between two variants.

## One Choice

Quite often you want to compile an application for release with maximal optimizing. But the optimizer confuses the debugger, thus when stepping through the program to locate a problem, you want to recompile without optimizing. Here is an example:

    1    SOURCE = main.c version.c gui.c
    2
    3    :variant BUILD
    4        release
    5            CFLAGS = -O4
    6            TARGET = myprog
    7        debug
    8            CFLAGS = -g
    9            TARGET = myprogd

Write this recipe as "main.aap" and run Aap without arguments. This will build "myprog" and use a directory for the object files that ends in "-release". The release variant is the first one mentioned, that makes it the default choice.

The first argument for the `:variant` command is `BUILD`. This is the name of the variable that specifies what variant will be selected. The names of the alternatives are specified with a bit more indent in lines 4 and 7. For each alternative two commands are given, again with more indent. Note that the indent not only makes it easy for you to see the parts of the `:variant` command, they are essential for Aap to recognize them.

To select the "debug" variant the `BUILD` variable must be set to "debug". A convenient way to do this is by specifying this on the command line:

% `aap BUILD=debug`

This will build the "myprogd" program, using "-g" instead of "-O4" for `CFLAGS`. The object files are stored in a directory ending in "-debug". Once you finished debugging and fixed the problem in, for example, "gui.c", running Aap to build the release variant will only compile the modified file. There is no need to compile all the C files, because the object files for the "release" variant are still in the "-release" directory.

## Two Choices

You can extend the `BUILD` variant with more items, for example "profile". This is useful for alternatives that exclude each other. Another possibility is to add a second `:variant` command. Let us extend the example with a selection of the user interface type.

    1    SOURCE = main.c version.c gui.c
    2
    3    :variant BUILD
    4        release
    5            CFLAGS = -O4
    6            TARGET = myprog
    7        debug
    8            CFLAGS = -g
    9            TARGET = myprogd
    10
    11   GUI ?= motif
    12   :variant GUI
    13       console
    14       motif
    15            SOURCE += motif.c
    16       gtk
    17            SOURCE += gtk.c
    18
    19   CFLAGS += -DGUI=$GUI

The `:variant` command in line 12 uses the `GUI` variable to select one of "console", "motif" or "gtk". Together with the earlier `:variant` command this offers six alternatives: "release" with "console", "debug" with "console", "release" with "motif", etc. To build "debug" with "gtk" use this command:

% `aap BUILD=debug GUI=gtk`

In line 11 an optional assignment "?=" is used. This assignment is skipped if the `GUI` variable already has a value. Thus if `GUI` was given a value on the command line, as in the example above, it will keep this value. Otherwise it will get the value "motif".

In line 15, 17 and 19 the append assignment "+=" is used. This appends the argument to an existing variable. A space is inserted if the value was not empty. For the variant "release" with "motif" the result of line 19 is that `CFLAGS` becomes "-O4 -DGUI=motif".

The "motif" and "gtk" variants each add a source file in line 15 and 17. For the console version no extra file is needed. The object files for each combination of variants end up in a different directory. Ultimately you get object files in each of the six directories ("SYS" stands for the platform being used):

directory | contains files
--- | ---
build-SYS-release-console | main, version, gui
build-SYS-debug-console | main, version, gui
build-SYS-release-motif | main, version, gui, motif
build-SYS-debug-motif | main, version, gui, motif
build-SYS-release-gtk | main, version, gui, gtk
build-SYS-debug-gtk | main, version, gui, gtk

## Compile only when needed

We happen to know that the main.c file does not depend on the GUI used. With the recipe above it will nevertheless be compiled again for every GUI version. Although this is a small thing in this example, in a bigger project it becomes more important to skip compilation when it is not needed. Here is the modified recipe:

    1    SOURCE = main.c version.c gui.c
    2
    3    :variant BUILD
    4        release
    5            CFLAGS = -O4
    6            TARGET = myprog
    7        debug
    8            CFLAGS = -g
    9            TARGET = myprogd
    10
    11   :attr {var_CFLAGS = $CFLAGS} {var_BDIR = $BDIR} main.c
    12
    13   GUI ?= motif
    14   :variant GUI
    15       console
    16       motif
    17            SOURCE += motif.c
    18       gtk
    19            SOURCE += gtk.c
    20
    21   CFLAGS += -DGUI=$GUI

The only new line is line 11. The "main.c" file is given two extra attributes: `var_CFLAGS` and `var_BDIR`. What happens is that when "main.c" is being build, Aap will check for attributes of this source file that start with "var_". The values will be used to set variables with the following name to the value of the attribute. Thus `CFLAGS` gets the value of `var_CFLAGS`. This means that the variable is overruled by the attribute while building "main.c".

The `var_BDIR` attribute is set to "$BDIR" before the second `:variant` command. It does not yet have the selected GUI appended there. The list of directories used is now:

directory | contains files
--- | ---
build-SYS-release | main
build-SYS-debug | main
build-SYS-release-console | version, gui
build-SYS-debug-console | version, gui
build-SYS-release-motif | version, gui, motif
build-SYS-debug-motif | version, gui, motif
build-SYS-release-gtk | version, gui, gtk
build-SYS-debug-gtk | version, gui, gtk

Prev | Contents | Next
Distributing a Program | Up | Using Python