In order to determine whether a target needs to be updated,
amake
monitors and records files accessed, commands
executed, programs executed, shared libraries opened, and
environment-variable values. The need for files-accessed
dependencies should be obvious. Commands-executed
dependencies eliminate the need for a target to depend on
its makefile. Programs-executed and shared-libraries-opened
dependencies are important when tools are being modified.
Environment-variable-value dependencies are like
commands-executed dependencies, but are also important when
a target is built by different users, because such values
can affect tool execution.
There are several ad-hoc methods of approximating
files-accessed dependencies See Automatic Prerequisites. For example, source files can be scanned for
syntactic evidence of access (e.g., #include
directives) or a tool can log accessed files (e.g.,
gcc -MMD
). These methods are not really automatic.
amake
detects files-accessed and programs-executed
dependencies via the shared-library libaccess
.
libaccess
contains wrapper functions for the C
standard library functions that access or execute
files. Indirectly, the wrappers inform amake
of each
file access or execution.
Automatic-dependency analysis can lead to
surprises. Perhaps, the biggest surprise is that the
automatic makefile variables ^
and <
can
evaluate to filenames that do not occur in the makefile. The
filter
and filter-out
functions can help solve
these problems.
The difference between a command-executed dependency and a program-executed dependency is that the command may be a complex sequence of shell builtins interspersed with regular program executions. A command is a character string. A program is a version of a file (i.e., with a timestamp or checksum).
amake
records a target's commands-executed, and
environment-variable-value dependencies in a .cmd
file, which is an executable shell script. Its name is the
target's name, with a .cmd
suffix. You can execute
the script to update the target.
The file also contains a comment identifying the name and line number of the makefile containing the rule containing the commands. This information is very valuable for debugging makefiles.
The content of a .cmd
file can be ignored by setting
the ACCESS_CMD
makefile variable. This is useful when
a target can be built in more than one way. A better
solution is to change the makefile to build each target in
only one way.
The ACCESS_CMD
variable is useful, for example, when
porting the Linux-kernel's build process from make
to
amake
. By design, its top-level makefiles build a
target in a subdirectory by changing to that subdirectory
and re-executing make
. Its sub-level makefiles build
the same target by, typically, executing the compiler.The
ACCESS_CMD
variable prevents amake
from always
rebuilding such a target.
amake
records a target's files-accessed,
programs-executed, and shared-libraries-opened dependencies
in a .dep
file, which is a simple makefile. Its name
is the target's name, with a .dep
suffix.
A .dep
file can also contain makefile-variable
definitions that record the checksum and/or
last-modification time of each dependency.
A sibling is a file that is created, as a side effect, while
creating a target. More precisely, a sibling is a
file/directory that is accessed and changed between the time
amake
begins executing a target's commands and when
amake
is done updating the target. The names of a
target's siblings are stored in its .sib
file, the
name of which is the target's name, with a .sib
suffix.
If the target cache is enabled, siblings are cached, along with targets.
SHELL=/bin/bash ACCESS_ENABLE:=1 foo: wc /etc/hosts > $ sinclude *.dep
This is the resulting foo.dep
:
foo: /etc/hosts foo: /usr/bin/wc
This is the resulting foo.cmd
:
#!/bin/bash -x # GNUmakefile:5 export PATH=/home/buff/amake/bin:/usr/bin:/bin export LD_LIBRARY_PATH=/home/buff/amake/lib32:/home/buff/amake/lib64 wc /etc/hosts > foo