A-A-P home page | A-A-P Recipe Executive | |
Prev | Tutorial | Next |
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.
(Almost) anywhere you have a value, such as a text string, you can use a Python expression instead. For instance, you could use a Python expression to retrieve the value of an environment variable for use in a recipe, or use an expression to compute some strange value.
Expressions are written between backticks (` `) and must be valid Python expressions. Some examples:
1 myhome = `os.environ.get("HOME")` 2 label = `"L"+str(17*22)`
The first example line shows how to retrieve an environment variable
by using Python's built-in os.environ
module.
The second shows how you can use Python to compute something
within an Aap recipe. It doesn't do anything useful, but it
uses Python to compute the value L374
,
and then Aap assigns that value to the variable label
.
Note | |
---|---|
Using environment variables is probably not portable. |
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.
1 @if OSTYPE == "posix": 2 INCLUDE += -I/usr/local/include 3 @else: 4 INCLUDE += -Ic:/vc/include 5 6 all: 7 :print INCLUDE is "$INCLUDE"
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
INCLUDE is "-I/usr/local/include"
%
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
INCLUDE is "-Ic:/vc/include"
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": INCLUDE += -I/usr/local/include LDFLAGS += -L/usr/local @else: INCLUDE += -Ic:/vc/include LDFLAGS += -Lc:/vc/lib
In Aap commands a variable without a scope is searched for in other scopes. Unfortunately, this does not happen for variables used in Python. To search other scopes you need to prepend "_no." before the variable name. Changing the above example to print the result from Python:
@if OSTYPE == "posix": INCLUDE += -I/usr/local/include @else: INCLUDE += -Ic:/vc/include all: @print 'INCLUDE is "%s"' % _no.INCLUDE
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. You only put a dollar before a variable name in
the argument of an Aap command. Not in Python code and not on the left hand
side of an assignment.
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
%
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.
In many places a Python expression can be used. For example, the
glob()
function can be used to expand wildcards:
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.
Using glob() is dangerous | |
---|---|
It is actually a bit dangerous to get the list of source files with the
|
Why use glob()
when you can use wildcards directly?
The difference is that the expansion with glob()
takes
place immediately, thus $Source will get the expanded value. When using
wildcards directly the expansion is done when using the variable, but that
depends on where it is used. For example, the
:print command does not do
wildcard expansion:
pattern = *.c expanded = `glob(pattern)` all: :print pattern $pattern expands into $expanded
When "foo.c" and "bar.c" exist, the output will be:
% aap
pattern *.c expands into foo.c bar.c
%
The following example turns the list of source files into a list of header files:
Source = `glob("*.c")` Header = `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 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".
The User manual Chapter 21, Using Python has more information. Documentation about Python can be found on its web site: http://www.python.org/doc/