myke - my make program; maintain, update, and regenerate groups of programs
myke [-deikmnpqrstuvENR] [-D level] [-S shell] [-f makefile]... [-j jobs] [--] [macro-name=string]... [target]...
Myke is a program used to maintain groups of files which depend upon one another. Supplied with a description of how the files are related and the actions implied by those relationships, myke will undertake to re-establish the relationships after the files have changed.
malloc_debug() routine if myke
was compiled with the -DEBUG option on a Sun.
On other systems the low two bits are ignored.
Bit 2 causes myke to dump core in certain error
conditions which would otherwise cause it
merely to exit with an error status.
If any of the higher bits are set,
extremely verbose debugging information is emitted.
This option implies the -d option.
Note that this option does not imply the -p option.
When myke tries to bring a system up to date, it requires information about the system. This information is stored in Makefiles. The basic component of a Makefile is a dependency, which is a set of lines of the form:
I<target>: I<prerequisites>
I<actions...>
This asserts that target is made by performing the shell script recounted as actions, but only after the prerequisites have been brought up to date in a similar fashion. Myke looks in three places for this information:
Dependencies consist of three parts, a target, a list of prerequisites, and a list of actions to perform when the target is out of date with respect to the prerequisites. After the line with the target and prerequisites, all following lines which begin with a blank character are taken to be actions. These are each performed by a separate shell. More than one target may be named, in which case it is as though the entire dependency had been written out for each target.
Macros are variables containing expressions which evaluate to strings. A line of the form
macro-name = value
defines a macro. A macro name may be any identifier. Where the sequence $(macro-name) is encountered, the named macro will be evaluated, and the resulting string inserted at that point. The syntax ${macro-name} may also be used. Should the macro's name be a single character the notation $x may be used, where x is the macro name. More than one macro may be named, in which case it is as though the entire macro definition had been written out for each macro. In fact, macro-name is a macro expression which should evaluate to a list of macro names.
There are several special macros which may be used. In the list below, those which refer to targets or prerequisites may only be used in actions associated with that target, except for $@ which may be used the the prerequisite list as well.
Macros may also be invoked as $((macro-name)). In this case each word in the macro is enumerated with each word in the expansion of the macro. This is known as a repeating macro. For example, given
x = a b c
y = _
z = f g
w = fred frog$((x))$y$((z))
the value of $w is
fred froga_f froga_g frogb_f frogb_g frogc_f frogc_g
In the above examples, macro-name may also be replaced with ``quoted-string'' or 'quoted-string', in which case the value of the string will be used instead of the value of the macro.
Macros may also be defined as
macro-name(arg[,arg...]) = value
It may then be invoked as $(macro (args...)), and the arguments supplied will be available as macros named after the arguments in the definition. For example, given
macro(arg1,arg2) = $(arg1)x$((arg2))
it:
echo '$(macro (this,and that)) $(macro (a,b))'
the echo action will expand to
echo 'thisxand thisxthat axb'
In addition to the above invocations, the quoted-string or macro-name may be followed by a series of modifier characters to manipulate the value of the macro or string, such as:
$(macro-name F)
which produces the filename part of the value of macro-name. If arguments are supplied as well as modifiers then the arguments must preceed the modifiers. Most modifiers affect each word of the macro individually. Appended to a macro as described above, the modifiers listed below have effect upon the words in the macro as follows:
It should be noted that the S, s, P, and p modifiers do not respect slashes (`/'). To apply them to macros with directory parts one should say something like:
$(thing D)/$(thing FP)
Some preprocessing is done to Makefiles. When reading them, the sequence slosh (`\') followed by a newline is replaced by a single newline and the lines so separated are treated as single lines. For example, one may say:
a_macro = something \
and something else
In actions the preprocessing stops at this point. In other lines the comment character (`#') introduces a comment which extends through to the next newline, and is treated like a blank. For example:
a_macro = something # anything you like \
and something else # likewise
After comments are stripped, lines beginning with colons (`:') are considered to be preprocessor directives. Directives are case-insensitive and may be invoked by any unique prefix. The following directives are recognised:
:ifdef A
I<A-stuff>
:elifdef B
I<B-stuff>
:endif A
is equivalent to
:ifdef A
I<A-stuff>
:else !A
: ifdef B
I<B-stuff>
: endif B
:endif A
If a file is not a full pathname, then if it begins with ./ or ../ it will be searched for relative to the directory in which the file containing the :include directive resides.
Otherwise the environment variable $MYKEPATH is consulted, and file is searched for relative to all the directories named therein. $MYKEPATH is a conventional colon separated list of directory names. Note that any relative pathnames in this list will be relative to the directory in which myke is running, rather than the directory of the file containing the :include directive.
:start, :finish, and :precious need info here.
Simple C-like (or Perl-like) expressions are supported, and are used by the :if and :elif directives. Both strings and integers may be intermixed in expressions, with conversions being implied by operators. The operators include:
Things to note: logical operators return one for true and zero for false; strings can be coerced to integers by adding them to zero - the numeric value is that of the leading numeric portion of the string, or zero if there is none; integers can be coerced to strings by concatenating them with ``''. In view of this, the cleanest way to get a macro's string value is to say
frob
and the cleanest way to get its numeric value is to say
$(frob)
which takes advantage of the macro substitution performed prior to evaluation of the expression.
In addition to invoking a shell, actions may also invoke some built-in functions. An action beginning with a colon is taken to be a pseudo-action. These include:
yacc command.
A line of the form
I<targets> := I<macro-names> = I<value>
defines macros which only apply to the named targets. For example, one may say:
PYR_BIN = /n/otc/bin
SUN_BIN = /n/arrakis/usr/local/bin
Bins = $(PYR_BIN) $(SUN_BIN)
Binaries = $((Bins))/it
$(PYR_BIN)/it := CFLAGS = -Dpyramid -Dthis=that
$(SUN_BIN)/it := CFLAGS = -Dsun -Dthis=the_other
$(Binaries): $(@F).c
$(CC) $(CFLAGS) -o $@ $?
A more general form of dependency is a rule. Any dependency where the target contains a percent sign (`%') is taken to be a rule. The target is taken to be a pattern. The prerequisites are taken to be names derived from the pattern. Any percent in the pattern will match zero or more characters in a target name. In the prerequisites, a percent on its own matches the first percent in the pattern, except as follows: a percent followed by a digit from 1 to 9 matches the first to ninth percents in the pattern respectively; a percent followed by a 0 matches the entire pattern; two consecutive percents are replaced by a single percent.
If the Makefile does not explicitly supply a complete dependency for a target, the set of rules is consulted in an attempt to infer a method of making the target.
The prerequisites of a rule are divided into two groups, the primary and secondary prerequisites. These as separated by a colon, vis
%_y.c: %.y : $("%.y.depend" <?G?)
:lock y.tab.c
yacc $(@PP[_]).y
mv y.tab.c $@
:unlock y.tab.c
The secondary set of prerequisites and its delimiting colon may be missing. Should the rule be chosen then both groups will be taken to be prerequisites. However, only the primary prerequisites are examined when considering a rule. If a rule which matches the target is found, all of the primary derived prerequisites are examined. If they can all be made then the rule is accepted. A prerequisite is considered makable if it already exists, if it has an explicit mentioned dependency in the Makefile, if it has acquired a dependency as a result of an earlier successful inference, or if rules can be successfully inferred to make it. Only after the rule is chosen is the secondary group expanded into a list of names.
For example, the following Makefile uses a rule to infer how to make the intermediate object files.
binary = foo
cfiles = a.c b.c
$(binary): $(cfiles)
:make $((cfiles P)).o # produces a.o b.o
cc -o $@ $>
rm $>
%.o: %.c
cc -c $?
The inference algorithm tries to chose the shallowest inference it can, measuring the length of the longest branch to make the comparison. Other things being equal, rules named earlier in the Makefile supercede rules named later.
It is important to know how macro expressions in rule prerequisites are handled. In the primary group, macro expansion is performed to derive a list of names, which are only then examined for locations to perform percent substitution. In the secondary group, percent substitution is performed first, and macro expansion performed second. It is permitted to use the $@ macro in the secondary prerequisite group.
It is very easy for inference to become exponential with the
number of rules, since rules will chain fairly freely.
This overhead can be greatly reduced through sensible choice of
filename to reflect the processing it will undergo.
For example, the above yacc rule will only be considered for
targets whose names end in _y.c.
This sort of approach to naming can reduce inference time by orders of magnitude.
If the -q option is specified, the -n option is implied. Thus, submakes will still be performed via the $(MAKE) macro. To arrange that meaningful results are obtained from this, successful submakes with the -q option are taken to mean that the submake is also up to date.
Command line definitions are exported to subsequent makes as command line arguments via the $(MAKE) macro. To protect any strings in them, they are placed in single quotes, and any single quotes within them are appropriately escaped. This mechanism is sufficient for Bourne shells and C shells. It may not be sufficient if another shell is specified via a :shell directive.
The names produced by shell globbing are not sorted. This could be changed, but it would cost run time (probably very little) and would also encourage bad habits. I don't think that Makefiles which depend on a generated list of names being sorted are a good thing; such dependencies should be explicit.
The result of shell globbing necessarily depends on the current content of the directories involved. Since macros are expanded at need, a pattern such as *.o will not always evaluate to the same set of names. Writers of Makefiles should keep this in mind when writing actions and dependencies. It is usually better to glob on sources than resultant files. The -p option forces prerequisites of targets to be expanded prior to making anything, and thus may produce different results from simply running the Makefile. It is for this reason that the -D option does not imply the -p option. This effect should also be kept in mind when running Makefiles with the -n option. A macro like *.o may well fail to expand and abort the program because the files have not been made.
PDP archives are only recognised on PDPs, and the portable ones only on others.
It is common for Makefiles to include actions like:
$(sources): $(headers)
:touch $@
in order to arrange that modifications to the header files propagate modification dates through to source files which include them. It is important to remember to include the line
:precious $(sources)
in the Makefile,
lest a source file get removed when an interrupt
is sent while the touch command is running.
While it is conventional to name this program
myke,
the program may also be linked to other names.
This has effects upon the names
myke
uses to invoke various things, as follows:
upon commencing,
myke
examines argv[0],
and extracts the leading identifier from the string equivalent to
$(argv[0])
were it a macro.
It then uses this string as the basic name on which
to model the other names it invokes.
For example, if the string were
fred,
myke would look for a global file
/usr/local/lib/fredrc,
a file named by the variable
$FREDRC,
for local Makefiles named
$FREDFILE
or
Fredfile
or
fredfile
or
$fredfile.
When searching for
:include
files, it would look along the path specified in
$FREDPATH.
Multiple mykes don't know about each other. This can be a killer with nested makes and parallelism.
NULs in Makefiles will truncate input lines.
Support for double colon targets is missing from version 2.
There is no way to imbed a newline in a macro. However, one may be imbedded directly in an action.
The D modifier character produces `.' if applied to a name with no directory part. `.' is just a convention, admittedly almost universal. To be pure about this contingency it should really return the empty string, which is the real name for the current directory, excepting certain broken Unices (which shall remain nameless). However, this has undesirable effects upon the writing of general purpose macros, as the sequence $(X D)/$(X F) where $X is a basename will give /$X, which is obviously wrong. This problem could be resolved if the D modifier returned dirpart/ except for basenames, when it would return the empty string. However, this would break many existing Makefiles, as the construct $(X D)$(X F) would then be required in the general case. It can also be considered more cryptic.
The N modifier can be confused by symbolic links.
Although the N modifier tries to determine such things as the full path of the current working directory and similar information as necessary, if it fails it uses not entirely general substitutes. These can fail. Probably it should fail outright if necessary information cannot be obtained.
On pre-SR10 Apollo systems
archives of object files
do not conform to the ar(5) manual entry,
nor to the <ar.h> include file.
In fact, I have failed entirely to find any documentation of their format.
Archives of non-object files are ok.
Myke does not yet know about all the built-in rules of make. When I get the time I will supply a file to support these. Currently I just support my own needs.
A semi-colon (';') on the dependency line is not treated specially. In make, a semicolon at this point introduces the first action.
Globbing should support the {...,...,...} enumeration ala csh.
Myke will never support the -b option of make.
The 5K exec limit still applies to command lines.
This can (and should) be fixed
by using a temporary file as a script
if the exec() fails with E2BIG.
Inferred targets should also be marked for automatic deletion unless they are mentioned in a :precious directive.
Myke does not know how to touch directories.
Perhaps there should be a way to call a program to test whether two files are out of date with respect to each other. Use of such a facility will also be discouraged when implemented, due to the performance penalty incurred.
If a target is supplied on the command line, a Makefile should not be required.
During parallel execution, concurrent actions intersperse their output.
There should be a way to access any targets supplied on the command line, and possibly to determine what flags have been set in some suitably symbolic manner.
I am not entirely happy with the criteria for recognising repeated references to a file in :require directives. It mostly works, but certain unusual incantations can result in multiple inclusion of the same file. This might be a feature.
C<{/usr/local/etc/mykerc}> global Makefile
C<$MYKERC> personal global Makefile list
C<$MYKEFILE> default local Makefile if set
C<Mykefile> local Makefile if C<$MYKEFILE> not set, or absent
C<mykefile> local Makefile if C<Mykefile> is absent
C<$mykefile> local Makefile if set and C<mykefile> is absent
C<$MYKEPATH> where to look for Makefile B<:include>s
sh(1), touch(1), ar(1)
make(1): the original make utility by S.I.Feldman
mike(1): a much faster and slightly incompatible make utility by Michael Rourke
cake(1): a slower but more versatile make utility by Zoltan Somogyi
mk(1), nmake(1), gmake(1), smake(1), et al: other variously incompatible make utilities
imake(1), makemake(1), mkdep(1), etc: tools for creating Makefiles
mtmk(1): metamake, a tool to obsolete Makefiles by Mike Mowbray
regexp(3): Henry Spencer's V8 compatible regular expression routines
S.I.Feldman: Make - A Program for Maintaining Computer Programs, Software - Practice and Experience, April 1979, pp. 255-265.
G.S.Fowler: A Fourth Generation Make, Proceedings of the 1985 Summer Usenix Conference, pp 159-174.
Z.Somogyi: Cake: a fifth generation version of make, Australian Unix system User Group Newsletter 7:6, April 1987, pp. 22-31.
Cameron Simpson <cs@zip.com.au>