The syntax in Jmake.rules is not elegant at all, but: - It is easy to parse (like sendmail.cf or troff files). - The rules are not supposed to change very often. - It is simple enough to be mastered in five minutes. :-) Here is a small description: o To deal with various cpp implementations: Final @!\ means: end of line, next line starts at the left margin. Final @@\ means: end of line, next line is to be indented by one tab. The conversion occurs during Pass1. o Symbol definitions >SYMBOL: defines the symbol (Pass 1). ?SYMBOL:: keeps iff SYMBOL is defined (Pass 2). %SYMBOL:: keeps iff SYMBOL is not defined (Pass 2). The ?SYM can be nested (logical AND), as in: ?SYMBOL:%TOKEN:text /* Keeps text if SYMBOL and not TOKEN */ To implement a logical OR, see below. o Commands Commands can be passed to 'jmake'. They start with a leading '|'. Available commands are: |suffix : adds to the .SUFFIXES: list in the makefile (Pass 1 & 2). |rule:: adds to the building rule section (Pass 1 & 2). |rule: : same as before, with a leading tab. |skip: skips text until a line starting with '-skip' is found (Pass 2). |expand : expand lines until '-expand' with (Pass 2). |once : text up to '-once' appears only the first time (Pass 1). Thus, a way to implement a logical OR could be: /* Implements SYMBOL or not TOKEN */ ?SYMBOL:text /* Keeps text if SYMBOL */ %SYMBOL:|skip %TOKEN:text /* Keeps text if not TOKEN */ -skip Actually, this is ugly, because the text has to appear twice. Fortunately, I did not use it. :-) The '|' commands cannot be nested. In particular, due to the simple implementation of '|skip', it is impossible to put '|skip' inside a skipped part. However, a '|once' section may have '|skip' sections. But actually, as you have surely already guessed, the best way to implement a logical OR is to use De Morgan's Law: not (p or q) <=> not p and not q /* Implements SYMBOL or not TOKEN (attempt #2) */ %SYMBOL:?TOKEN:|skip text /* If SYMBOL or not TOKEN */ -skip Who said they don't care ? ;-) o Expansion Expansion is done with the 'expand' command. It has been provided to avoid some cumbersome writings in makefiles when you have to repeat some silly lines that only differ in file names, for instance. Let's look at an example first: |expand a!foo bar! b!yes no! !a:: echo !a, !b -expand Then two rules will be printed, and the values of (a,b) for the first will be (foo, yes), for the second (bar, no). Substitution is controled by the '!' character. If the word to be substituted is part of another one, detach with the ^^ construct as in: !b^^c. It is possible to use Makefile macros in the , and they will be expanded by jmake. If this is not what you want, escape the first '$' sign (this is a Makefile escape, i.e. you must double the '$', not precede it with a backslash). A // stands for the null substitution value. Here is another example which shows how the macro Expand can be used. It is defined in Jmake.rules as: #define Expand(rule, pattern) @!\ |expand pattern @!\ rule @!\ -expand So we can write in the Jmakefile: |skip A = foo bar -skip #define Rule @!\ $(DIR)/!a^^.o: !a^^.o @@\ $(CC) -c !a^^.c @@\ $(MV) !a^^.o $(DIR) Expand(Rule, a!$(A)!) which will generate in Makefile.SH: $(DIR)/foo.o: foo.o $(CC) -c foo.c $(MV) foo.o $(DIR) $(DIR)/bar.o: bar.o $(CC) -c bar.c $(MV) bar.o $$(DIR) The 'A' declaration has been surrounded by skip, so that it does not appear in the generated Makefile.SH, but it will be taken into account by jmake for the substitution in the pattern. The number of expansions is determined by the number of possible values for the _first_ parameter. If other parameters have less substitution values, they will get void ones. It is possible to add a regular expression at the end of '-expand'. This regular expression will be removed from the final set of expansion at the end of each line. It is also possible to do substitutions in the expanded item, by using the syntax (if 'f' is the expanded variable) !f:

= where

and are two regular expressions (without spaces). The pattern

will be replaced by pattern (only the first occurrence will be replaced). Finally, you may refer in the expanded section to variables whose value is computed via another expansion, which makes it easy to define generic Jmakefiles. Example: SRC = foo.c bar.c OBJ = \ |expand f!$(SRC)! !f:\.c=\.o \ -expand \\ INC = \ |expand f!$(OBJ)! !f:\.o=\.h \ -expand \\ which will generate in Makefile.SH: SRC = foo.c bar.c OBJ = \ foo.o \ bar.o INC = \ foo.h \ bar.h Do not forget to protect special characters in your regular expressions such as backslash, point, etc... o Once The once command is tagged with a name. The first time the name appears, the once construct is ignored and the text up to '-once' will be copied in the generated Makefile.SH. However, future occurences of the same name will be ignored (once will behave like skip). Example: |once this_is_a_name -once o Initializations +: Puts the whole line in the initialization section (Pass 1 & 2). ++SYMBOL : Adds to the SYMBOL macro (Pass 1 and 2). o User-defined variables CFLAGS: added flags to C compiler DPFLAGS: cpp flags to be added to mkdep for dependency LDFLAGS: flags/libraries to be added at linking stage