This defines the recipe syntax (more or less). NOTE: this may still change quite a bit.
Table 26-1. Notation
| | | separates alternatives |
| () | grouping a sequence of items or alternatives |
| [] | optional items (also does grouping) |
| "" | contains literal text; """ is one double quote |
| ... | indicates the preceding item or group can be repeated |
| EOL | an end-of-line, optionally preceded by a comment |
| INDENT | an amount of white space, at least one space |
| INDENT2 | an amount of white space, at least one space more than INDENT |
A comment starts with "#" and continues until the end-of-line. It may appear in many places.
White space may be inserted in between items. It is often ignored, but does have a meaning in a few places.
Line continuation is done with a backslash immediately before an end-of-line. It's not needed for an assignment and other commands that don't have a build_block: the item continues if the following line has more indent than the first line.
For items that have a build_block, the start of the build block is the line with the smallest indent that is larger than the indent of the line that started the command. The lines before this are continuation lines. Example:
mytarget : source1 source2 # continuation line :print $source # first build line of build block |
| aapfile | ::= | ( [ aap_item ] EOL ) ... |
| aap_item | ::= | dependency | rule | variant | otherfile | build_command |
| dependency | ::= | targets ":" [ dependencies ] [ EOL build_block ] |
| targets | ::= | item_list |
| dependencies | ::= | item_list |
| build_block | ::= | INDENT build_command [ EOL [ INDENT build_command ] ] ... |
| rule | ::= | ":rule" pattern ... ":" pattern ... [ EOL build_block ] |
| variant | ::= | ":variant" name ( EOL variant_item ) ... |
| variant_item | ::= | INDENT varvalue EOL INDENT2 build_block |
| otherfile | ::= | includefile | childfile |
| includefile | ::= | ":include" item_list |
| childfile | ::= | ":child" item_list |
| build_command | ::= | assignment | script_item | generic_command | message |
| assignment | ::= | assign_set | assign_append | assign_cond |
| assign_set | ::= | name "=" item_list |
| assign_append | ::= | name "+=" item_list |
| assign_cond | ::= | name "?=" item_list |
| script_item | ::= | script_line | script_block |
| script_line | ::= | "@" script_command |
| script_block | ::= | ":python" EOL ( script_command EOL ) ... ":end" |
| generic_command | ::= | ":" command_name [ command_argument ] |
| message | ::= | info_msg | error_msg |
| info_msg | ::= | ":print" expression ... |
| error_msg | ::= | ":error" expression ... |
| # A list can contain white-separated items and Python style expressions. | ||
| item_list | ::= | item [ white_space item ] ... |
| item | ::= | ( simple_item | "(" item_list ")" ) [ attribute ... ] |
| simple_item | ::= | ( expression | non_white_item ) ... |
| attribute | ::= | "{" name [ "=" expression ] "}" |
| expression | ::= | string_expr | python_expr |
| string_expr | ::= | """ text """ | "'" text "'" |
| python_expr | ::= | "`" python-expression "`" |
| non_white_item | ::= | non-white-text | "$" [ "(" ] name [ ")" ] |
A backslash at the end of the line is used for line continuation.
- Can't have white space after it!
- Also for comments.
- Also for Python commands; A leading @ char and white space before it is
removed.
- Lines are joined before inspecting indents.
# comment \
continued comment
@ python command \
@ continued python command \
still continued
When lines are joined because a command continues with a line with more indent,
the line break and leading white space of the next line are replaced with a
sinble space. An exception is when the line ends in "$br": The $br is removed,
the line break is inserted in the text and leading white space of the next line
is removed.
VARIABLES:
When concatenating variables and using rc-style expansion, the attributes of
the last variable overrule the identical attributes of a previous one.
v1 = foo {check = 1}
v2 = bar {check = 2}
vv = $*v1$v2
-> vv = foobar{check = 1}{check = 2}
When using rc-style expansion, quotes will not be kept as they are, but
removed and re-inserted where used or necessary. Example:
foo: "file 1.c" foo.c
:print "dir/$*source"
Results in: "dir/file 1.c" "dir/foo.c"
Be careful with using "$\" and quotes, you may not always get what you wanted.
To get one item out of a variable that is a list of items, use an index number
in square brackets. Parenthesis or curly braces must be used around the
variable name and the index. The first item is indexed with zero. Example:
BAR = beer coffee cola
:print $(BAR[0])
beer
BAR_ONE = $(BAR[2])
:print $BAR_ONE
cola
Using an index for which no item exists gives an empty result. When $MESSAGE
includes "warning" a message is printed about this.
Normally using $VAR gets what you want. A-A-P will use the kind of quoting
expected and add attributes when needed. However, when you want something
else, this can be specified:
$var depends on where it's used
$?var when the variable is not set or defined use an empty string
instead of generating an error
$-var without attributes (may collapse white space)
$+var with attributes
$*var use rc-style expansion (may collapse white space)
$=var no quotes or backslashes
$'var aap quoted (using ' and/or " where required, no backslashes)
$"var quoted with " (doubled for a literal ")
$\var special characters escaped with a backslash
$!var depends on the shell, either like $'var or $"var
In most places $var is expanded as $+'var (with attributes, using ' and " for
quoting). The exceptions are:
:sys $-!var no attributes, shell quoting
$n in $(v[$n]) $-=var no attributes, no quoting
:del $-'var no attributes, normal quoting
The quoted variables don't handle the backslash as a special character. This
is useful for MS-Windows file names. Example:
prog : "dir\file 1.c"
:print $'source
Results in: "dir\file 1.c"
ASSIGNMENT:
overview:
var = value assign
var += value append (assign if not set yet)
var ?= value only assign when not set yet
var $= value evaluate when used
var $+= value append, evaluate when used
var $?= value only when not set, evaluate when used
Assignment with "+=" or "$+=" appends the argument as a separate item. This
is actually done by inserting a space. But when the variable wasn't set yet
it works like a normal assignment:
VAR += something
is equal to:
@if globals().has_key("VAR"):
@ VAR = VAR + " " + "something"
@else:
@ VAR = "something"
Assignment with "?=" only does the assignment when the variable wasn't set
yet. A variable that was set to an empty string also counts as being set.
Thus when using "aap VAR=" the empty value overrules the value set with "?=".
VAR ?= something
is equal to:
@if not globals().has_key("VAR"):
VAR = something
When using "$=", "$+=" or "$?=" variables in the argument are not evaluated at
the time of assignment, but this is done when the variable is used.
VAR = 1
TT $= $VAR
VAR = 2
:print $TT
prints "2".
When first setting a variable with "$=" and later appending with "+=" the
evaluation is done before the new value is appended:
VAR = 1
TT $= $VAR
TT += 2
VAR = 3
:print $TT
prints "1 2"
Note that evaluating a python expressions in `` is not postponed.
BLOCK ASSIGNMENT
The normal assignment command uses a single line of text. When broken into
several lines they are joined together, just like with other commands. $br can
be used to insert a line break. Example:
foo = first line$br
second line$br
third line $br
The block assignment keeps the line breaks as they are. The same example but
using a block assignment:
foo << EOF
first line
second line
third line
EOF
The generic format is:
{var} << {term}
line1
...
{term}
{term} can be any string without white space. The block ends when {term} is
found in a line by itself, optionally preceded by white space and followed by
white space and a comment.
The amount of indent to be removed from all the lines is set by the first
line. When the first line should start with white space use $empty.
All the variations of the assignment command can be used:
var << term assign
var +<< term append (assign if not set yet)
var ?<< term only assign when not set yet
var $<< term evaluate when used
var $+<< term append, evaluate when used
var $?<< term only when not set, evaluate when used
ATTRIBUTES
Items can be given attributes. The form is:
{name = value}
"value" is expanded like other items, with the addition that "}" cannot appear
outside of quotes.
This form is also possible and uses the default value of 1:
{name}
Examples:
bar : thatfile {check = $MYCHECK}
foo {virtual} : somefile
The "virtual" attribute is used for targets that don't exist (as file or
directory) but are used for selecting the dependency to be build. These
targets have the "virtual" attribute set by default:
TARGET COMMONLY USED FOR
all build the default targets
clean remove intermediate build files
distclean remove all generated files
test run tests
check same as "test"
install build and install for use
tryout build and install for trying out
reference generate or update the cross-reference database
fetch obtain the latest version of each file
update fetch and build the default targets
checkout checkout (and lock) from version control system
commit commit changes to VCS without unlocking
checkin checkin and unlock to VCS
unlock unlock files from a VCS
add add new files to VCS
remove remove deleted files from VCS
revise like checkin + remove
tag add a tag to the current version
prepare prepare for publishing (generated docs but no exe)
publish distribute all files for the current version
finally always executed last (using "aap finally" is uncommon)
These specific targets may have multiple build commands. They are all
executed to update the virtual target. Normally there is up to one target in
each (child) recipe.
Note that virtual targets are not related to a specific directory. Make sure
no other item in this recipe or any child recipe has the same name as the
virtual target to avoid confusion. Specifically using a directory "test"
while there also is a virtual target "test". Name the directory "testdir"
to avoid confusion.
The "comment" attribute can be used for targets that are to be specified at
the command line. "aap comment" will show them.
% aap comment
target "all": build everything
target "foo": link the program
EXECUTING COMMANDS
A dependency and a rule can have a list of commands. For these commands the
following variables are available:
$source The list of input files as a string.
$source_list The list of input files as a Python list.
$source_dl Only for use in Python commands: A list of
dictionaries, each input item is one entry.
$depend The list of dependencies (source files plus virtual
dependencies) as a string.
$depend_list The list of dependencies (source files plus virtual
dependencies) as a Python list.
$depend_dl Only for use in Python commands: A list of
dictionaries, each dependency item is one entry.
$target The list of output files as a string.
$target_list The list of output files as a Python list.
$target_dl Only for use in Python commands: A list of
dictionaries, each output item is one entry.
$buildtarget The name of the target for which the commands are
executed. It is one of the items in $target.
$match For a rule: the string that matched with %
Example:
doit {virtual}:
:print building $target
prog : "main file.c" doit
:print building $target from $source
Results in:
building doit{virtual=1}
building prog from "main file.c"
Note that quoting of expanded $var depends on the command used.
The Python lists $source_list and $target_list can be used to loop over each
item. Example:
$OUT : foo.txt
@for item in target_list:
:print $source > $item
Note the difference between $source and $depend: $source only contains real
files, $depend also contains virtual dependencies.
The list of dictionaires can be used to access the attributes of each item.
Each dictionary has an entry "name", which is the (file) name of the item.
Other entries are attributes. Example:
prog : file.c {check = md5}
@print sourcelist[0]["name"], sourcelist[0]["check"]
Results in: file.c md5
RATIONALE
In an assignment and other places a Python expression can be used in
backticks. Expanding this is done before expanding $VAR items, because this
allows the possibility to use the Python expression to result in the name of a
variable. Example:
foovaridx = 5
FOO = $SRC`foovaridx`
Equal to:
FOO = $SRC5
In the result of the Python expression $ characters are doubled, to avoid it
being interpreted as the start of a variable reference. Otherwise Python
expressions with arbitrary results would always have to be filtered explicitly.
Variables can still be obtained without using the $, although none of the
modifiers like $+ and $* are available. Example:
FOO = foo/`glob("*.tmp")`
May result in:
FOO = foo/one.tmp two.tmp
Note that "foo/" is only prepended to the whole result, not each
white-separated item. If you do want rc-style expansion, use two commands:
TT = `glob("*.tmp")`
FOO = foo/$*TT
Result:
FOO = foo/one.tmp foo/two.tmp
Watch out for unexpected results when rc-style expansion is done for $*VAR.
Example:
VAR = one two
FOO = $*VAR/`glob("*.tmp")`
Would result in:
FOO = one/one.tmp two/one.tmp two.tmp
because the `` part is expanded first, thus the assignment is executed like:
FOO = $*VAR/one.tmp two.tmp
The backticks for a Python expression are also recognized inside quotes,
because this makes the rule for doubling backticks consistent. Example:
FOO = "this``file" that``file
Doubling the backtick to avoid it being recognized as a Python expression
makes it impossible to have an empty Python expression. There appears to be
no reason to use an empty Python expression.
|