Common Attributes

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

# Chapter 28. Common Attributes

This is the first paragraph of Common Attributes.

For the "virtual" and "comment" see Chapter 26.

    Attributes can be added to a node with the ":attr" 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
    ":attr" command or dependency.

    STICKY ATTRIBUTES

    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:
    	virtual			virtual target, not a file
    	remember		virtual target that is remembered
    	directory		item is a directory
    	filetype		type of file
    	constant		file contents never changes
    	fetch			list of locations where to fetch from (first
    				one that works is used)
    	commit			list of locations for VCS
    	publish			list of locations to publish to (they are all
    				used)
    	force			rebuild a target always
    	depdir			directory to put an automatically generated
    				dependency file in; when omitted $BDIR is used
    	signfile		file used to store signatures for this target

    SIGNATURES: the check attribute

    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 "aap/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.

    Another check can be specified with {check = name}.  Example:

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

    Other types of signatures supported:

    	time		Build the target when the timestamp of the source
    			differs from the last time the target was build.

    	newer		Build the target if its timestamp is older than the
    			timestamp of the source.  This is what the good old
    			"make" program uses.

    	md5		Build the target if the md5 checksum of the source
    			differs from the last time the target was build.
    			This is the default.

    	c_md5		Like "md5", but ignore changes in comments and amount
    			of white space.  Appropriate for C programs. Slows
    			down computations considerably.

    	none		Don't check time or contents, only existence.  Used
    			for directories.

    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.

    The "aap/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 "aap/sign" file is stored in the directory of the recipe that
    specifies how to build the target.

    To overrule the directory where "AAP/sign" 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".

    CIRCULAR DEPENDENCIES

    Two attributes can be used to handle circular dependencies:

    	update		Can be set to "no" to avoid updating a source that a
    			target depends on.
    	recursive	Can be set to a number, which indicates the maximum
    			recursive depth allowed.

    The use can best be illustrated with an example:

    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
          :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
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    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.

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

    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 ":update" 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.

    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.

Prev | Contents | Next
A-A-P Commands | Up | Common Variables