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

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.