The code that goes into a make rule implementation file,
preplugin.mk
, or
plugin.mk
file is regular GNU
Make code. There are certain practices that you
should follow when writing GNU Make
code for use within abuild. A good way to learn about writing
rules for abuild is to study existing rules. Here we will
briefly list some things that rules authors must keep in mind:
If you are about to write some rules, consider carefully
whether they should be local rules for a specific build item
(accessed with the LOCAL_RULES
variable),
exported rules provided by a build item (accessed with the
RULES
variable), or whether they should be
made globally accessible by being included in a plugin. The
last case will be rare and should only be used for
functionality that really should work “out of the
box” in a particular build tree. Plugin rules and build
item rules must appear in the
rules/
directory or the target-type
rules/all
directory
within the providing build item. Local rules can appear
anywhere, and the location must be named in the
LOCAL_RULES
variable in
Abuild.mk
. It is also possible to create
global make code that is loaded from a plugin directory:
abuild will load any preplugin.mk
and
plugin.mk
files defined in plugins in the
order in which the plugins are declared. Remember that
preplugin.mk
is loaded before
Abuild.mk
, and
plugin.mk
is loaded after
Abuild.mk
. This makes it possible for a
plugin to provide some initial variable settings for the user
in preplugin.mk
, have the user do
something with or modify those values in
Abuild.mk
, and then use the result that
operation in plugin.mk
.
Abuild invokes make with the --warn-undefined-variables flag. This means that your users will see warnings if you assume that an undefined variable has the empty string as a value. If it is your intention to have an undefined variable default to the empty string, then you should include
VARIABLE
?=
in your rules, where VARIABLE
is the name
of the variable you are setting. You can always provide
default values for variables in this fashion if the intention
is to allow users to override those values in their own
Abuild.mk
files.
Note that Abuild.mk
files are included
before rules files. This is necessary because the
Abuild.mk
file contains information about
which rules are to be included. If your rules are providing
values that users will use in their
Abuild.mk
files, you should recognize
that your users will need to avoid referencing those variables
in assignment statements that use :=
instead of =
since the
Rules.mk
variables will not yet be
defined when Abuild.mk
is read.
Alternatively, you can make use of the
preplugin.mk
functionality for rules
supplied by plugins.
You should always provide a help file for your rules. The
help file is called
,
and lives in the same directory as the rule implementation.
For an example and discussion of this, see Chapter 22, Build Item Rules and Automatically Generated Code and Chapter 8, Help System.
rulename
-help.txt
If your rules require certain variables to be set, check for
those variables and given an error if they are not defined.
For an example of this, see Section 22.2, “Code Generator Example for Make”. The
ccxx.mk
rules in the abuild sources
(Appendix I, The ccxx.mk
File) provide a somewhat more
elaborate example of doing this since they actually generate
dynamically in terms of other values the list of variables
that should be defined.
All rules should provide an all:: target. Note that abuild never invokes a user-supplied clean target, so providing a clean target is not useful. [61] Although you can add additional targets in your rules files, think carefully before doing so. Having too many custom targets will make a source tree hard to build and maintain. If you are adding functionality that should be done as part of every build, consider making it part of the all:: target.
If you are adding support for a new test driver, you should
make sure that your test driver is invoked from the
check, test, and
test-only targets. You must also ensure
that both the check and
test targets depend on the
all target but that the
test-only target does not depend on the
all target. Abuild internally provides
this construct for these targets that don't do anything, so if
your test support only operates conditionally upon the
presence of test files, you don't have to worry about
conditionally defining empty targets. For an example, see
make/qtest-support.mk
in the abuild
distribution.
Sometimes it may be useful to provide debugging targets for your
users that provide some information about the state as your
rules see it. The ccxx
rules provide a
ccxx_debug target for this purpose.
Always remember that any targets you define in your rules files
are run from the output subdirectory. The variable
$(SRCDIR)
points to the directory that
contains the actual Abuild.mk
file and
therefore presumably the source files. Abuild sets the
VPATH
variable to this as well, but you may
have to explicitly run your actions with arguments that point
back to the source directory (e.g., -I
$(SRCDIR)
). If make finds a target's prerequisite
using VPATH
, the full relative path to the
prerequisite will be accurately reflected in
$<
and $^
, which will
be sufficient for many cases.
In order to have your rules behave properly with the
--verbose and --silent
flags, you should avoid putting
@
in front of commands that the user should
see in verbose mode, and you should have all your rules print
short, simple descriptive messages about what they are doing.
These rules should be printed using
@$(PRINT)
. The PRINT
variable is usually set to echo, but it is
set to @:
when abuild is running in
silent mode. Note that we put an @
sign at
the beginning of the @$(PRINT)
command so
that the user will not see the echo command itself (in
addition to what is being echoed) being echoed when they are
running in verbose mode.
There are some convenience functions provided by abuild's
GNU Make code. The best way to learn is to read existing
rules. If you are going to be writing a lot of
make code for abuild, it will be
in your interest to familiarize yourself with the code in
make/global.mk
in the abuild
distribution.
[61] In abuild 1.0, user-supplied clean targets were run when abuild was invoked from inside an output directory, but this turned out not to be particularly useful or reliable. The practice of having clean targets simply remove output directories seems to have emerged as a best practice in the community anyway.