mfg - simple template-based makefile generator
mfg is a fairly simple (template-driven) makefile generator. It tries to `guess' (from its configuration file) all necessary steps to create the specified target-file from the given set of source-files. It will then create a makefile performing these steps using one of the provided template files. It can also be used on an already created makefile to update the file name lists or dependencies. Read the section Template Files below for a list of provided makefile templates and information on how to write your own.
mfg is not intended to be a replacement for automake (in fact, mfg is older than automake). automake is a rather complex tool for creating equally complex makefiles, while mfg is intended for small projects where the full functionality of automake is not required and `human readable' makefiles are more important.
mfg currently supports the following options:
.
'. The name of the default configuration file is `config
'.
prog
', which can be used for building a C or C++ program.
Note that this template file will only be used if a makefile is created for the first time (i.e. the output file does not exist). If the output file already exists, it will be used as the template for the new makefile instead and this option has no effect.
-I
option is present, the directories are
scanned in left-to-right order.
Makefile
', unless the file `makefile
' in the current
directory exists, in which case `makefile
' is used in preference, as
does make(1). If this file already exists, it will also be used as the
template file, regardless of any -f
option (`update mode').
mfg has no built-in magic about the types of files referenced in the generated makefiles. All information about the list of known file types, and which files can be created by applying makefile rules, is defined in its configuration file (which is read automatically on program startup).
The format of such a configuration file is structurally similar to that of a makefile, the exact meaning of the contents is radically different, however. You may split a long line by inserting a backslash followed by a newline, as usual. A configuration file may contain three kinds of things:
#
' at the beginning of a line starts a comment, it and the rest of
the line are ignored. This is similar to make(1), but only recognized at
the beginning of a line. It may be preceded by whitespace.
Completely empty lines (or lines containing nothing but whitespace) are also regarded as comments and discarded likewise.
NAME = [ VALUE ... ]
where NAME must be a valid variable name for make(1), and VALUE is a list of words (separated by whitespace) that is subject to a special file name expansion:
Each word that contains the character `%
' (exactly one of them) is
replaced by the (possibly empty) list of file names this pattern matches
in the dependency tree of the makefile under construction. The `%
' can
match any non-empty substring, while other characters match only themselves
(just like the patterns in implicit rules of newer versions of make(1)).
Note that this list of matching file names has nothing to do with actual
directory contents!
For example, an assignment of the form:
CLASSES = %.class
will be replaced in the output with a line that assigns to the variable
`CLASSES
' the list of all Java class files that can be produced by
applying rules from the configuration (see below) to file names in the
dependency tree. Precede the `%
' with a backslash to suppress its
special meaning.
%
' wildcard character. mfg does not need to know how this
transformation is actually done (this is specified in a concrete makefile
template as a standard implicit rule for make(1)), it just needs to know
that it is possible - and which files it would produce - in order to
calculate the dependencies correctly.
Such a transformation rule looks like an `inverse implicit make rule':
SOURCE : [ RESULT ... ] [ ; FLAGS ] [<tab> ( SHELL-COMMAND | MARK, FROM, TO ) ] [<tab> ... ] (lots of these)
This tells mfg that from a file matching SOURCE it is possible to create all files listed as RESULT using corresponding makefile rules. For the simple case of C source code, such a rule would be as simple as:
%.c : %.o
Note that in the case of RESULT, the `%
' character is replaced with
the text that `%
' has matched in the SOURCE file name of this rule.
The FLAGS and the text on the following lines may be used to automatically determine additional file dependencies that cannot be deduced from the file names alone. In this case, mfg can do one of two things:
It can run an external program to calculate the list of dependencies.
While this is in many cases the optimal (or even only) solution, is has
a serious drawback: how to do this is often very platform dependent.
To use this method, put a shell command line as a string into the
dependency part of the transformation rule. The command can use the
environment variable `$source
' to obtain the source file name and
must output the list of additional dependency files, one file name per
line. In the case of C source code and the GNU C compiler, this might
work:
%.c : %.o "gcc -MM $source | tr -s ': \t\n\\\\' '\n' | tail +3"
As you can see, the program accepts the usual C-style escape character sequences inside quoted strings.
Alternatively, mfg can try to calculate the list of additional dependencies itself, using a simple internal algorithm that depends on the given FLAGS and the strings MARK, FROM and TO from the dependency part of the transformation rule. It will search the source file for occurrences of the string MARK and try to fetch text on the same line that is enclosed within FROM and TO. Again, in the case of C source code:
%.c : %.o "#include", "\"", "\""
FLAGS is a string of exactly 10 characters (actually, it is an array of character flags), with the following meaning:
Pos. 1 = string quote character of this language Pos. 2 = alternative string quote character Pos. 3 = alternative string quote character 2 Pos. 4 = escape character inside quotes Pos. 5+6 = start characters of comment to end of line Pos. 7+8 = start characters of multi-line comment Pos. 9+10 = end characters of multi-line comment
All undefined item positions in the flags array need to be filled with the `_' character, e.g. you would write:
"'_\///**/ (for C++) "'____(**) (for Modula-2)
A typical configuration file for mfg (for C, C++, Objective-C and Java source code) might look like this:
HEADERS = %.h SOURCES = %.c %.cc %.m %.java CLASSES = %.class OBJECTS = %.o
%.c: %.o ; "'_\__/**/ "#include", "\"", "\""
%.cc: %.o ; "'_\///**/ "#include", "\"", "\""
%.m: %.o ; "'_\///**/ "#include", "\"", "\"" "#import", "\"", "\""
%.java: %.class
For each different type of makefile that mfg can create for you, it needs to have a `template' file (basically a makefile fragment) that contains targets, implicit rules and variable definitions specific to this particular project type. A template for a `C library' makefile may define rules to compile C source code files, while a template for a `LaTeX document' makefile may instead provide rules to process LaTeX input into various output formats.
A template file for mfg is in fact nothing more that just a makefile
fragment (inserted verbatim into the generated output), that may use
all the variables defined in the configuration file as well as the two
special variables `TARGET
' and `CLEAN
'. `TARGET
' is the name of
the target file given on the command line when mfg was run to create
the makefile. `CLEAN
' is the list of intermediate files that can be
recreated by applying one or more makefile rules. Typical examples for
this include linker object files or a DVI typesetting file.
A simple template for Java might look similar to this:
CLASSPATH = . JAVA = java -classpath $(CLASSPATH) JAVAC = javac -classpath $(CLASSPATH) JAVADOC = javadoc -classpath $(CLASSPATH) JFLAGS = -g# -O
.SUFFIXES: .java .class .java.class: $(JAVAC) $(JFLAGS) $<
$(TARGET): $(CLASSES)
clean: $(RM) $(CLEAN)
Finally, here is a list of all template files currently included in the standard distribution of mfg:
gsconfig
' configuration file
gsconfig
' configuration file
mfg foobar *.[ch]
Creates a makefile to build the target foobar
from all C source and
header files in the current directory.
mfg recognizes these environment variables, if set:
~/.mfg:/usr/share/mfg:.
', but this can be changed at compilation time)
.:include:../include
'
The configuration file syntax for defining the rules used for automatic dependency calculation is currently very clumsy and should be changed. It is not much more than a quick hack to provide a built-in mechanism for dependency calculation that is platform independent (i.e. does not rely on external programs).
mfg version 1 was the result of my laziness in doing programming
assignments during the summer of 1993. It has been completely rewritten
for version 2 in 1995. The original design was inspired by the mmm(1)
tool for creating makefiles in Ulm's Modula-2 System m2c.
make(1), autoconf(1), automake(1), libtool(1)
Elmar Ludwig < elmar@informatik.uni-osnabrueck.de >