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

  Part of the A-A-P recipe executive: Common Attributes

  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>
  Attributes can be added to an item with the
  <link linkend="cmd-attr">:attr</link> command and by using them
in a dependency or rule.  Note that an assignment does not directly associate
the attribute with a node.  This only happens when the variable is used in an
<link linkend="cmd-attr">:attr</link> command or a dependency.
</para>

<para>
The form for an attribute is:

<literallayout>        {name = value} </literallayout>
</para>

<para>
"value" is expanded like other items, with the addition that "}" cannot appear
outside of quotes.
</para>

<para>
This form is also possible and uses the default value of 1:
</para>

<literallayout>        {name} </literallayout>

<para>
Examples:
</para>

<programlisting>
        bar : thatfile {check = $MYCHECK}
        foo {virtual} : somefile
</programlisting>

<para>
The "virtual" attribute is used for targets that don't exist (as file or
directory) but are used for selecting the dependency to be built.  These
targets have the "virtual" attribute set by default:

<table frame="none" id="virtual-targets">
<title>Virtual Targets</title>
<tgroup cols="2">
  <colspec colwidth="150"/>
<thead>
  <row>
  <entry>Target</entry>
  <entry>Commonly used for</entry>
  </row>
</thead>
<tbody>
   <row>
        <entry>all</entry>
        <entry>build the default targets</entry>
      </row><row>
        <entry>clean</entry>
        <entry>remove generated files that are not distributed
                        (added automatically)</entry>
                        </row><row>
        <entry>cleanmore</entry>
        <entry>remove all generated files (added automatically)</entry>
      </row><row>
        <entry>cleanALL</entry>
        <entry>remove all generated files, AAPDIR and build-*
                        directories below the toplevel recipe</entry>
      </row><row>
      <entry>&nbsp;</entry><entry>&nbsp;</entry>
      </row><row>

        <entry>test</entry>
        <entry>run tests</entry>
      </row><row>
        <entry>check</entry>
        <entry>same as "test"</entry>
      </row><row>
        <entry>install</entry>
        <entry>build and install for use (added automatically)</entry>
      </row><row>
        <entry>uninstall</entry>
        <entry>uninstall for use (added automatically)</entry>
      </row><row>
        <entry>tryout</entry>
        <entry>build and install for trying out</entry>
      </row><row>
      <entry>&nbsp;</entry><entry>&nbsp;</entry>
      </row><row>

        <entry>reference </entry>
        <entry>generate or update the cross-reference database</entry>
      </row><row>
      <entry>&nbsp;</entry><entry>&nbsp;</entry>
      </row><row>

        <entry>fetch</entry>
        <entry>obtain the latest version of each file</entry>
      </row><row>
        <entry>update</entry>
        <entry>fetch and build the default targets</entry>
      </row><row>
      <entry>&nbsp;</entry><entry>&nbsp;</entry>
      </row><row>

        <entry>checkout</entry>
        <entry>checkout (and lock) from version control system</entry>
      </row><row>
        <entry>commit</entry>
        <entry>commit changes to VCS without unlocking</entry>
      </row><row>
        <entry>checkin</entry>
        <entry>checkin and unlock to VCS</entry>
      </row><row>
        <entry>unlock</entry>
        <entry>unlock files from a VCS</entry>
      </row><row>
        <entry>add</entry>
        <entry>add new files to VCS</entry>
      </row><row>
        <entry>remove</entry>
        <entry>remove deleted files from VCS</entry>
      </row><row>
        <entry>revise</entry>
        <entry>like checkin + remove</entry>
      </row><row>
        <entry>tag</entry>
        <entry>add a tag to the current version</entry>
      </row><row>
      <entry>&nbsp;</entry><entry>&nbsp;</entry>
      </row><row>

        <entry>prepare</entry>
        <entry>prepare for publishing (generated docs but no exe) </entry>
      </row><row>
        <entry>publish</entry>
        <entry>distribute all files for the current version</entry>
      </row><row>
      <entry>&nbsp;</entry><entry>&nbsp;</entry>
      </row><row>

        <entry>finally</entry>
        <entry>always executed last (using "aap finally" is uncommon)</entry>
      </row>
      </tbody>
    </tgroup>
    </table>
</para>

<para>
The targets marked with "(added automatically)" will be added by Aap if they
are not present.  This is done for the toplevel and each child recipe.
</para>

<para>
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.
</para>

<para>
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.
</para>

<para>
The "comment" attribute can be used for targets that are to be specified at
the command line.  "aap comment" will show them.
</para>

<para>
<literallayout>        % <userinput>aap comment</userinput>
        target "all": build everything
        target "foo": link the program </literallayout>
</para>


<bridgehead>Sticky Attributes</bridgehead>

<para>
When attributes are used in a rule or dependency, most of them are only used
for that dependency.  But some attributes are "sticky": Once used for an item
they are used everywhere for that item.  Sticky attributes are:

<table frame="none">
  <title>Sticky attributes</title>
  <tgroup cols="2">
    <colspec colwidth="100"/>
    <tbody>
      <row>
        <entry>virtual</entry>
        <entry>virtual target, not a file</entry>
      </row>
      <row>
        <entry>remember</entry>
        <entry>virtual target that is remembered</entry>
      </row>
      <row>
        <entry>directory</entry>
        <entry>item is a directory</entry>
      </row>
      <row>
        <entry>filetype</entry>
        <entry>type of file</entry>
      </row>
      <row>
        <entry>constant</entry>
        <entry>file contents never changes</entry>
      </row>
      <row>
        <entry>fetch</entry>
        <entry>list of locations where to fetch from (first
                                one that works is used)</entry>
      </row>
      <row>
        <entry>commit</entry>
        <entry>list of locations for VCS</entry>
      </row>
      <row>
        <entry>publish</entry>
        <entry>list of locations to publish to (they are all used)</entry>
      </row>
      <row>
        <entry>force</entry>
        <entry>rebuild a target always</entry>
      </row>
      <row>
        <entry>depdir</entry>
        <entry>directory to put an automatically generated
        dependency file in; when omitted $BDIR is used</entry>
      </row>
      <row>
        <entry>var_BDIR</entry>
        <entry>directory to put the related object or
        generated file in; when omitted $BDIR is used</entry>
      </row>
      <row>
        <entry>signfile</entry>
        <entry>file used to store signatures for this target</entry>
      </row>
    </tbody>
  </tgroup>
</table>

</para>


<bridgehead id="check-attribute">The check attribute</bridgehead>

<para>
The check attribute is used to specify what kind of signature is used for an
item.
</para>

<para>
The default check for a file that was changed is an md5 checksum.  Each time a
recipe is executed the checksums for the relevant items are computed and
stored in the file "AAPDIR/sign".  The next time the recipe is executed the
current and the old checksums are compared.  When they are different, the
build commands are executed.  This means that when you put back an old version
of a file, rebuilding will take place even though the timestamp of the source
might be older than the target.
</para>

<para>
Another check can be specified with {check = name}, where "name" is the kind
of check.  Example:
</para>

<programlisting>
        foo.txt : foo.db {check = time}
                :sys db_extract $source >$target
</programlisting>

<para>
The default check is "md5".  This is specified with the $DEFAULTCHECK
variable.  You can set this variable to "time" or "newer" to use timestamps
instead of md5 signatures.  The value of $DEFAULTCHECK is used when a node
does not have a "check" attribute.
</para>

<para>
<table frame="none">
  <title>supported check attribute values</title>
  <tgroup cols="2">
    <colspec colwidth="100"/>
    <tbody>
      <row>
        <entry>time</entry>
        <entry>Build the target when the timestamp of the source
                        differs from the last time the target was
                        built.</entry>
      </row>
      <row>
        <entry>newer</entry>
        <entry>Build the target if its timestamp is older than the
                        timestamp of the source.  This is what the good old
                        "make" program uses.</entry>
      </row>
      <row>
        <entry>md5</entry>
        <entry>Build the target if the md5 checksum of the source
                        differs from the last time the target was built.
                        This is the default.</entry>
      </row>
      <row>
        <entry>c_md5</entry>
        <entry>Like "md5", but ignore changes in comments and amount
                        of white space.  Appropriate for C programs. Slows
                        down computations considerably.</entry>
      </row>
      <row>
        <entry>none</entry>
        <entry>Don't check time or contents, only existence.  Used
                        for directories.</entry>
      </row>
    </tbody>
  </tgroup>
</table>
</para>

<para>
When mixing "newer" with other methods, the build rules are executed if the
target is older than the source with the "newer" check, or when one of the
signatures for the other items differs.
</para>

<para>
The "AAPDIR/sign" file is normally stored in the directory of the target.  This
means it will be found even when using several recipes that produce the same
target.  But for targets that get installed in system directories (use an
absolute path), virtual targets and remote targets this is avoided.  For these
targets the "AAPDIR/sign" file is stored in the directory of the recipe that
specifies how to build the target.
</para>

<para>
To overrule the directory where the "sign" file is written, use the attribute
{signdirectory = name} for the target.
To overrule the file where the signatures are written, use the attribute
{signfile = name} for the target.  "name" cannot end in "sign".
</para>


<bridgehead>Handling Circular Dependencies</bridgehead>

<para>
Two attributes can be used to handle circular dependencies:
  <informaltable frame='none'>
    <tgroup cols='2'>
      <colspec colwidth="100"/>
      <tbody>
        <row>
        <entry>update</entry>
        <entry>Can be set to "no" to avoid updating a source that a
                        target depends on.</entry>
        </row>
        <row>
        <entry>recursive</entry>
        <entry>Can be set to a number, which indicates the maximum
                        recursive depth allowed.</entry>
        </row>
      </tbody>
    </tgroup>
  </informaltable>
</para>

<para>
The use can best be illustrated with an example:
</para>

<programlisting>
      :attr {recursive = 3} index file.out

      index: file.out {update = no}
              # Get the current checksum for the index file.
              @sum = get_md5("index")

              # Generate the new index file from the output file.
              :system wc file.out >$target

              # Update the output file if the index file changed.
              @if sum != get_md5("index"):
                :update file.out

      file.out: file.in index {update = no}
              # Make sure index exists.
              @if not os.path.exists("index"):
                :print empty > index

              # Generate the output file.
              :cat $source >! $target

              # Need to generate the index file again.
              :update index

      all: file.out
</programlisting>

<para>
The goal is to produce the file "file.out".  It is created from "test.in" and
"index".  The "index" is created from "file.out", which includes the "index"
file, thus a circular dependency exists.  The idea is to repeat generating
"file.out" until it no longer changes.
</para>

<para>
The "recursive" attribute is set to 3 for "index" and "file.out".  This allows
rebuilding "file.out" three times before giving up.
</para>

<para>
In the first dependency the "{update = no}" attribute is used to avoid
updating "file.out".  The build commands first update the "index" file before
using
<link linkend="cmd-update">:update</link> to update "file.out".  But this is
only done when the index file has changed.  That is where the circular
dependency stops: When the
generated index file no longer changes.
</para>

<para>
In the second dependency a similar thing is done: The "index" file is not
updated before executing the build commands but as part of the build commands.
</para>
