Rules
MakeQuick
defines a few rules itself and has knowledge about automake-defined
rules, so that e.g. rules for compiling C sources are not emitted again. The
rules feature in
MakeQuick
is the reason this project was actually started. The
syntax is basically the same as GNU Make pattern rules with some extensions, but
the way they are expanded makes them much more useful.
%.o: %.c { $(CC) $< -o $@ }
The above example is a simple rule to build object files from C sources. The rule is instantiated for each match, so that the resulting Makefile has only explicit rules.
Rules are matched on the graph, rather than on the file system. When a rule matches a file in the graph, an edge from that file to the new file is created. Other rules can then match this new file.
Rules defined in a program block implicitly depend on that program and
$(THIS)
expands to the program location with
$(EXEEXT)
appended. Thus, in
this case, the
$(THIS)
variable used in rules is expanded to
$(builddir)/msgcat$(EXEEXT)
program msgcat { %.c: %.msg { $(THIS) -c $< $@ } }
Rules inside programs are always considered for match, but are disabled in the resulting Makefile, if the program was conditional and disabled at configure time.
Pattern matching
The introductory example is already a pattern rule. Patterns in
MakeQuick
are
slightly more advanced than in GNU Make. There is a set of rules defining which
pattern is matched. Simply speaking, the most special pattern is matched.
%.c: %.y { ... } src/%.c: src/%.y { ... }
In the above example, the second rule is matched for all
.y
files under
src/
. All other
.y
files are matched by the first rule.
Code continuations
Rules can span multiple lines, just like variables.
%.c: %.y { echo This is the first line bison -y -o $@ $< echo This is the third line }
Special variables in rules
- $<
This variable expands to the first dependency. It does not exist, if the target does not have any dependencies or the only dependency is
$(THIS)
. - $@
This variable expands to the target. It does not exist, if the rule has multiple targets.
- $*
The string matched by
%
in a pattern rule. It only exists in pattern rules. - $1 ... $n
The
n
th dependency. Only dependencies listed on the rule itself are considered. Dependencies in external dependency declarations are not considered. - $-1 ... $-n
The
n
th dependency, counting from the last. Thus,$-1
is the last dependency. - $0
An alias for
$(THIS)
. Neither$0
nor$(THIS)
exist in global rules.
Target-specific variables
For a generic rule, it is often useful to let targets define an additional set
of flags for the tool. The variable syntax
$[VAR]
roughly expands to
$(AM_VAR) $(VAR) $($(target)_VAR)
, where
$(target)
is the
program
or
library
the target file is being built for.
%.c: %.y { $(YACC) $[YFLAGS] -o $@ $< } program myparser { sources { src/parser.y } }
The pattern rule in the above example might be expanded to roughly the following make code:
src/parser.c: src/parser.y $(MKDIR_P) src/ $(YACC) $(AM_YFLAGS) $(YFLAGS) $(myparser_YFLAGS) -o src/parser.c \ `test -f 'src/parser.y' || echo '$(srcdir)/'`src/parser.y
The
test
makes sure that vpath builds work correctly. The first line will
make the target directory, if it does not yet exist.
$(TARGET)
The special variable
$(TARGET)
will expand to the library or program name.
Not only that, but you can also access its declarations using the syntax
described in
variables.
%.c: %.cx { $(CPP) -DTARGET='"$(TARGET)"' -DLIBRARIES='"$(TARGET.link : library)"' $< -o $@ } program myprog { sources { main.cx } link { mylib1 -lm } }
In the above example,
$(TARGET.link : library)
will be expanded to
mylib1
.
Output in $(builddir)
You may want to output the resulting files directly into the
$(builddir)
,
instead of a subdirectory. For this use case, the
%%
pattern may be used.
%%.c: %%.y { $(YACC) $[YFLAGS] -o $@ $< }
The
%%
pattern on the left will match exactly one path segment, i.e. without
any path separators (
/
). A
%%
on the right matches any number of path
segments before matching the final path segment, i.e. the file, which was
matched by the
%%
on the left. The above example might be expanded to:
parser.c: src/parser.y $(YACC) $(AM_YFLAGS) $(YFLAGS) $(myparser_YFLAGS) -o parser.c \ `test -f 'src/parser.y' || echo '$(srcdir)/'`src/parser.y
As you can see, a
mkdir
is no longer necessary and the output is now in the
current directory.
Silencing rules
Similar to
make
, lines of a recipe may be silenced by prepending them with
@
.
MakeQuick
extends this to automake
silent-rules
.
%.c: %.y { @echo Calling bison @(YACC)bison $< -o $@ }
The
@(NAME)
syntax emits an
$(AM_V_GEN)
-like variable that prints
YACC
and the target (
$@
) in the
silent-rules
style. Calling
make V=1
will
print the actual command instead of the single-line message.
External rules
If
MakeQuick
is not flexible enough for the use case, external rules may be
imported using the
extern
keyword. You may optionally add rule stubs
declaring patterns or explicit graph edges that may be assumed as being
implemented. Note that these rules are not special and more exact rules can
still be matched.
extern 'lex-rules.am' %.c: %.l extern 'yacc-rules.am' { %.c: %.y ; %.h: %.y ; } extern 'more-rules.am'
Replacing automake rules
The power gained with the introduction of these pattern rules can be used to replace large parts of automake. E.g. a simplified automake rule for building object files from C sources can be written as follows:
%%.o: %%.c { @(CC)$(CC) $[CPPFLAGS] $[CFLAGS] -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< }
Automake still provides many useful tools, such as its
distcheck
and
parallel-tests
facilities. These tools are the reason
MakeQuick
targets automake
and not make, directly.
Also note that it's not useful to actually rewrite the automake rules, as the
resulting Makefile will not be any shorter. Automake may do optimisations at a
lower level than
MakeQuick
, so it is not advisable to override many of its rules.