<!--  vim: set sw=2 sts=2 et ft=docbk:

  Part of the A-A-P recipe executive: Tutorial - filetypes and actions

  Copyright (C) 2002-2003 Stichting NLnet Labs
  Permission to copy and use this file is specified in the file COPYING.
  If this file is missing you can find it here: http://www.a-a-p.org/COPYING

-->

<para>
A-A-P can recognize what the type of a file is, either by looking at the file
name or by inspecting the contents of the file.  The filetype can then be
used to decide how to perform an action with the file.
</para>

<bridgehead>A New Type of File</bridgehead>

<para>
Suppose you are using the "foo" programming language and want to use A-A-P to
compile your programs.  Once this is has been setup you can compile
"hello.foo" into the "hello" program with a simple recipe:
</para>

<programlisting>
    :program hello : hello.foo
</programlisting>

<para>
You need to explain &Aap; how to deal with "foo" files.  This is done with
a recipe:
</para>

<programlisting>
    :filetype
        suffix foo foo

    :action compile foo
        :sys foocomp $?FOOFLAGS $source -o $target

    :route  foo object
        compile
</programlisting>

<para>
For Unix, write this recipe as "/usr/local/share/aap/startup/foo.aap" or
"~/.aap/startup/foo.aap".  The recipes in these "startup" directories are
always read when &Aap; starts up.
</para>

<para>
Now try it out, using the simple recipe at the top as "main.aap":
</para>

<literallayout>    % <userinput>aap</userinput>
    Aap: foocomp hello.foo -o build-FreeBSD4_5_RELEASE/hello.o
    Aap: cc -L/usr/local/lib -g -O2 -o hello build-FreeBSD4_5_RELEASE/hello.o
    % </literallayout>

<para>
The "foo.aap" recipe does three things:
<orderedlist>
<listitem><para>
The <computeroutput>:filetype</computeroutput> command is used to tell A-A-P to recognize
your "hello.foo" file as being a "foo" file.
</para></listitem>
<listitem><para>
The <computeroutput>:action</computeroutput> command is used to specify how the "foocomp"
compiler is used to compile a "foo" program into an object file.
The user can set the FOOFLAGS variable to options he wants to use.
The convention is that the option variable is in uppercase, starts with the
filetype and ends in "FLAGS".
</para></listitem>
<listitem><para>
The <computeroutput>:route</computeroutput> command is used to specify which actions are to
be used to turn a "foo" file into an "object" file.
</para></listitem>
</orderedlist>
</para>

<bridgehead>Defining a Filetype by Suffix</bridgehead>

<para>
The <computeroutput>:filetype</computeroutput> command is followed by the line "suffix foo
foo".  The first word "suffix" means that recognizing is done by the suffix of
the file name (the suffix is what comes after the last dot in the name).
The second word is the suffix and the third word is the type.  Quite often the
type is equal to the suffix, but not always.  Here are a few more examples of
lines used with <computeroutput>:filetype</computeroutput>:
</para>

<programlisting>
    :filetype
        suffix fooh foo
        suffix bash sh
</programlisting>

<para>
It is also possible to recognize a file by matching the name with a pattern,
checking the contents of the file or using a Python script.  See the user
manual.
</para>

<bridgehead>Defining a Compile Action</bridgehead>

<para>
The lower half of "foo.aap" specifies the compile action for the "foo"
filetype:
</para>

<programlisting>
    :action compile foo
        :sys foocomp $source -o $target
</programlisting>

<para>
The <computeroutput>:action</computeroutput> command has two arguments.  The first one
specifies the kind of action that is being defined.  In this case "compile".
This action is used to make an object file from a source file.  The second
argument specifies the type of source file this action is used for, in this
case "foo".
</para>

<para>
Below the <computeroutput>:action</computeroutput> line the build commands are specified. In
this case just one, there could be more.
The <computeroutput>:sys</computeroutput> command invokes an exteral program, "foocomp", and
passes the arguments.  In an action <computeroutput>$source</computeroutput> is expanded to
the source of the action and <computeroutput>$target</computeroutput> to the target.  These
are obtained from the <computeroutput>:do</computeroutput> command that invokes the action.
Example:
</para>

<programlisting>
    :do compile {target = `src2obj("main.foo")`} main.foo
</programlisting>

<para>
This <computeroutput>:do</computeroutput> command invokes the compile action, specified with
its first argument.  The target is specified as an attribute to the action,
the source is the following argument "main.foo".
When executing the <computeroutput>:do</computeroutput> command the filetype of "main.foo"
is detected to be "foo", resulting in the compile action for "foo" to be
invoked.  In the build command of the action
<computeroutput>$source</computeroutput> and <computeroutput>$target</computeroutput> are replaced,
resulting in:
</para>

<programlisting>
    :sys foocomp main.foo -o `src2obj("main.foo")`
</programlisting>

<para>
Note that in many cases <computeroutput>$target</computeroutput> is passed implicitly from a
dependency and does not appear in the <computeroutput>:do</computeroutput> command argument.
</para>


<bridgehead>Another Use of Filetypes</bridgehead>

<para>
When building a program you often want to include the date and time when it
was built.  A simple way of doing this is creating a source file "version.c"
that contains the timestamp.  This file needs to be compiled every time your
program is built.  Here is an example how this can be done:
</para>

<programlisting>
1   :program prog : main.c work.c
2
3   :attr prog {filetype = myprog}
4
5   :action build myprog object
6        version_obj = `src2obj("version.c")`
7        :do compile {target = $version_obj} version.c
8        :do build {filetype = program} $source $version_obj
</programlisting>

<para>
The target "prog" is explicitly given a different filetype in line 3.  The
default filetype for a program is "program", here it is set to "myprog".  This
allows us to specify a different build action for "prog".
</para>

<para>
Write the recipe as "main.aap" (without the line numbers) and execute it with
<userinput>aap</userinput>.  The first time all the files will be compiled and linked
together.  Executing <userinput>aap</userinput> again will do nothing.  Thus the
timestamp used in "version.c" will not be updated if the files were not
changed.  If you now make a change in "main.c" and run <userinput>aap</userinput> you
will see that both "main.c" and "version.c" are compiled.
</para>

<para>
The <computeroutput>:action</computeroutput> command in line 5 has three arguments.  The
first one "build" is the kind of action, like before.  The second argument
"myprog" specifies the target filetype, the third one "object" the source
filetype.  Thus the template is:
<literallayout>    <computeroutput>:action</computeroutput>  kind-of-action  target-filetype  source-filetype
</literallayout>
This order may seem a bit strange.  Remember that putting the target left of
the source also happens in a dependency and an assignment.
</para>

<para>
There are three commands for the build action, lines 6 to 8.  The first one
assigns the name of the object file for "version.c" to
<literal>version_obj</literal>.  "version.c" was not included in the
<literal>:program</literal> command at
the top, it is compiled here explicitly in line 7.  This is what makes sure
"version.c" is compiled each time "prog" is built.  The other source files
will be compiled with the default rules for <literal>:command</literal>.
</para>

<para>
Finally the <computeroutput>:do build</computeroutput> command in line 8 invokes the build
action to link all the object files together.  Note that the filetype for the
build action is explicitly defined to "program".  This is required for this
<computeroutput>:do</computeroutput> command to use the default action for a program target.
Otherwise the action would invoke itself, since the filetype for $target is
"myprog".
</para>

<para>
For more information about customizing filetype detection and actions see
<xref linkend="user-filetype"/>.
</para>
