Using Python

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

# Chapter 6. Using Python

In various places in the recipe Python commands and expressions can be used. Python is a powerful and portable scripting language. In most recipes you will only use a few Python items. But where needed you can do just about anything with it.

## Conditionals

When a recipe needs to work both on Unix and on MS-Windows you quickly run into the problem that the compiler does not use the same arguments. Here is an example how you can handle that.

          @if OSTYPE == "posix":
              CPPFLAGS += -DFAST
          @else:
              CPPFLAGS += /DFAST

          all:
              :print CPPFLAGS is "$CPPFLAGS"

The first and third line start with the "@" character. This means a Python command follows. The other lines are normal recipe lines. You can see how these two kinds of lines can be mixed.

The first line is a simple "if" statement. The `OSTYPE` variable is compared with the string "posix". If they compare equal, the next line is executed. When the `OSTYPE` variable has a different value the line below `@else:` is executed. Executing this recipe on Unix:

% `aap`
CPPFLAGS is "-I/usr/local/include -DFAST"
%

`OSTYPE` has the value "posix" only on Unix and Unix-like systems. Executing the recipe on MS-Windows, where `OSTYPE` has the value "mswin":

C:> `aap`
CPPFLAGS is "/IC:\VC\include /DFAST"
C:>

Note that the Python conditional commands end in a colon. Don't forget to add it, you will get an error message! The indent is used to form blocks, thus you must take care to align the "@if" and "@else" lines.

You can include more lines in a block, without the need for extra characters, such as { } in C:

          @if OSTYPE == "posix":
              CPPFLAGS += -DFAST
              LDFLAGS += -L/usr/local
          @else:
              CFLAGS += /DFAST

## Loops

Python has a "for" loop that is very flexible. In a recipe it is often used to go over a list of items. Example:

    1      @for name in [ "solaris", "hpux", "linux", "freebsd" ]:
    2          fname = README_$name
    3          @if os.path.exists(fname):
    4              FILES += $fname
    5      all:
    6          :print $FILES

The first line contains a list of strings. A Python list uses square brackets. The lines 2 to 4 are executed with the `name` variable set to each value in the list, thus four times. The indent of line 5 is equal to the `@for` line, this indicates the "for" loop has ended.

Note how the `name` and `fname` variables are used without a dollar in the Python code. This might be a bit confusing at first. Try to remember that you only put a dollar before a variable name in the argument of a recipe command.

In line 2 the `fname` variable is set to "README_" plus the value of `name`. The `os.path.exists()` function in line 3 tests if a file exists. Assuming all four files exist, this is the result of executing this recipe:

% `aap`
README_solaris README_hpux README_linux README_freebsd
%

## Python Block

When the number of Python lines gets longer, the "@" characters become annoying. It is easier to put the lines in a block. Example:

        :python
            FILES = ''
            for name in [ "solaris", "hpux", "linux", "freebsd" ]:
                fname = "README_" + name
                if os.path.exists(fname):
                    if FILES:
                        FILES = FILES + ' '
                    FILES = FILES + fname
        all:
            :print $FILES

This does the same thing as the above recipe, but now using Python commands. As usual, the `:python` block ends where the indent is equal to or less than that of the `:python` line.

When using the `:python` command, make sure you get the assignments right. Up to the "=" character the Python assignment is the same as the recipe assignment, but what comes after it is different.

## Expressions

In many places a Python expression can be used. We have already seen the use of the `glob()` function:

       SOURCE = `glob("*.c")`

Python users know that the `glob()` function returns a list of items. Aap automatically converts the list to a string, because all Aap variables are strings. A space is inserted in between the items and quotes are added around items that contain a space.

The following example turns the list of source files into a list of header files:

        SOURCE = `glob("*.c")`
        HEADER = `aap_sufreplace(".c", ".h", SOURCE)`
        all:
            :print SOURCE is "$SOURCE"
            :print HEADER is "$HEADER"

Running Aap in a directory with "main.c" and "version.c"?

% `aap`
SOURCE is "version.c main.c"
HEADER is "version.h main.h"
%

The "aap_sufreplace()" function takes three arguments. The first argument is the suffix which is to be replaced. The middle argument is the replacement suffix. The last argument is the name of a variable that is a list of names, or a Python expression. In this example each name in `SOURCE` ending in ".c" will be changed to end in ".h".

## Further Reading

Documentation about Python can be found on its web site: http://www.python.org/doc/

Prev | Contents | Next
Building Variants | Up | Version Control with CVS