jmake - a generic makefile builder
jmake [ cpp options ]
Jmake builds a makefile out of a rather high level description held in
a Jmakefile file. The generated file is a Makefile.SH rather than a
simple makefile, which means it is ready to be used in conjonction with
metaconfig. In particular, parameters such as "where to install
executables" will be automatically determined by Configure and only the
needed parameters will be taken into account.
To use jmake you have to write a Jmakefile first, which describes the
way things are to be built. Your Jmakefile will be included inside a
generic template through the C pre-processor. This means you may use
the usual C /**/ comments, but not the shell # comments. The C
comments will not appear in the generated Makefile.SH but lines
starting with ;# will finally appear as shell comments. If you have to
write the string /* in the generated Makefile.SH then you have to
escape it (otherwise jmake will think of it as the start of a C
comment). Simply put a # in front of the *, as in /#*.
You have a set of macros at your disposal, and all these macros are
listed in the Index file, along with the piece of code they will expand
to. Usually, a Jmakefile is fairly small and thus easier to maintain
than a huge Makefile. Some internal powerful commands allow you to
write portable makefiles easily, without having to spend many efforts,
because someone else already did the job for you :-).
When you want to generate your makefile, you usually do not run jmake
but use the jmkmf script which is a wrapper and will invoke jmake with
the correct options.
All the knowledge of jmake is held in two files: the template
Jmake.tmpl and the macro definition file Jmake.rules. The first file
includes the second, along with the Jmakefile. It is sometimes
necessary to know how things works to be able to correctly use all the
features provided. For instance, you may have to write your own rules
for a specific project. Although you cannot overwrite the predefined
rules, you can extent the Jmake.rules file or simply add your macros in
your Jmakefile. You may also use #include statements when you want to
share these macros and do not want to duplicate the code.
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:
1) 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.
There should always be one of @!\ or @@\ at the end of each
line. The only exception is for macros that are to be used as
part of a rule body (e.g. RemoveTargetProgram). In that case,
the first line (which holds the #define) should end with a
single backslash.
2) Symbol definitions:
* >SYMBOL: defines the symbol.
* ?SYMBOL:<text>: keeps <text> iff SYMBOL is defined.
* %SYMBOL:<text>: keeps <text> iff SYMBOL is not defined.
The ?SYM can be nested (logical AND), as in:
?SYMBOL:%TOKEN:text
which will keep text if SYMBOL is defined and TOKEN undefined.
To implement a logical OR, see below.
3) Makefile target tests:
* ?target?:<text>: keeps <test> iff target is defined.
* %target%:<text>: keeps <test> iff target is not defined.
A makefile target is defined as a standalone target, for
instance the depend.local target, which would be defined
as:
depend.local:
Also note that it is only valid for targets defined so
far in the generated makefile. It is not a predicate
that can be used to test for targets that will eventually
be defined later on in the generation.
4) Commands:
Commands can be passed to jmake. They start with a leading '|'.
Available commands are:
* |suffix <sx>: adds <sx> to the .SUFFIXES: list in the
makefile.
* |rule:<text>: adds <text> to the building rule section.
* |rule: <text>: same as before, with a leading tab.
* |skip: skips text until a line starting with '-skip' is
found.
* |subst: begins section where lines will be subject to
variable substitution, until '-subst' is found. This
means that when the Makefile.SH is run, all instances of
$var within the subst section will be substituted by the
shell.
* |shell: emits section until matching '-shell' as-is in
the generated Makefile.SH. This can be useful to prepare
|case sections. It is not allowed to nest shell
sections.
* |case: this command must be followed by a shell variable
name (without its leading '$' sign) and a case-style
pattern, for instance the string "var in f*". It will
generate the corresponding "case" test in the Makefile.SH
on the "$var" value and only if this test is true will
the section until the matching '-case' be generated in
the Makefile when Makefile.SH is run. It is possible to
nest case sections freely.
* |expand <pattern>: expand lines until '-expand' with
<pattern>. A complete example is shown below.
* |once <symbol>: text up to '-once' appears only the first
time.
The '|' commands cannot be nested, unless otherwise noted. 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. It is allowed to nest |case
sections at will.
Here is a way to implement a logical OR:
/* 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 that construct. :-)
Indeed, 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 didn't care about logic? ;-)
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 <pattern>, 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.
The ^^^ construct behaves like ^^, i.e. it is stripped out, but
it also removes any following white space after the ^^^. If you
prepend something to a macro argument, and that macro argument
was written with spaces before it, then this will let you
concatenate something right before that argument's final 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:<p>=<q> where <p>
and <q> are two regular expressions (without spaces). The
pattern <p> will be replaced by the pattern <q> (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...
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 occurrences of the same name will be ignored (once will
behave like skip).
Example:
|once this_is_a_name
<text>
-once
The shell command can be used to generate a shell fragment in
the Makefile.SH. For instance, the following section in the
Jmakefile:
|shell
case "$d_usegtk1" in
define) glib=1; gtk=1;;
esac
-shell
will cause the generation of the enclosed fragment in the
Makefile.SH to compute the values of the glib and gtk variables
based on the configuration variable d_usegtk1 set by running
Configure.
In turn, this can be used in subsequent case sections to
activate parts of the Makefile only when building for GTK1 using
glib-1.x:
|case glib in 1
display:
echo "Building for glib-1.x"
-case
This section will generate something like this in the
Makefile.SH:
!NO!SUBS!
case "$glib" in
1)
$spitshell >>Makefile <<'!NO!SUBS!'
display:
echo "Building for glib-1.x"
!NO!SUBS!
;;
esac
$spitshell >>Makefile <<'!NO!SUBS!'
And when running Makefile.SH, the "display" rule above will only
appear when building for glib-1.x. The form of the final
Makefile can therefore depend on the configuration options
chosen when Configure was run.
5) Initializations:
* +<line>: Puts the whole line in the initialization
section.
* ++SYMBOL <value>: Adds <value> to the SYMBOL macro.
6) User-defined variables:
The user may define CFLAGS, LDFLAGS or DPFLAGS as additional
flags to be used in C compilation, linking phase or depend
target. It is thus possible to add some extra flags such as -I
or libraries for Makefiles in specific sub-directories.
Raphael Manfredi <[email protected]>
Jmakefile High level description of Makefile.SH Jmake.rules File holding the macro definitions Jmake.tmpl Template used to mould Makefile.SH
On systems whose cpp reduces multiple tabs and spaces to a single space, jmake attempts to put back any necessary tabs (which make expects in front of rules) but does not properly formats the body of the rule itself. There is a bootstraping problem when creating the first Makefile.SH, because you cannot run it through a shell until there is a decent Configure script, but you can't run metaconfig before there is a Makefile.SH or some needed symbols will not be defined.
jmkmf(1), metaconfig(1). ram JMAKE(1)
Personal Opportunity - Free software gives you access to billions of dollars of software at no cost. Use this software for your business, personal use or to develop a profitable skill. Access to source code provides access to a level of capabilities/information that companies protect though copyrights. Open source is a core component of the Internet and it is available to you. Leverage the billions of dollars in resources and capabilities to build a career, establish a business or change the world. The potential is endless for those who understand the opportunity.
Business Opportunity - Goldman Sachs, IBM and countless large corporations are leveraging open source to reduce costs, develop products and increase their bottom lines. Learn what these companies know about open source and how open source can give you the advantage.
Free Software provides computer programs and capabilities at no cost but more importantly, it provides the freedom to run, edit, contribute to, and share the software. The importance of free software is a matter of access, not price. Software at no cost is a benefit but ownership rights to the software and source code is far more significant.
Free Office Software - The Libre Office suite provides top desktop productivity tools for free. This includes, a word processor, spreadsheet, presentation engine, drawing and flowcharting, database and math applications. Libre Office is available for Linux or Windows.
The Free Books Library is a collection of thousands of the most popular public domain books in an online readable format. The collection includes great classical literature and more recent works where the U.S. copyright has expired. These books are yours to read and use without restrictions.
Source Code - Want to change a program or know how it works? Open Source provides the source code for its programs so that anyone can use, modify or learn how to write those programs themselves. Visit the GNU source code repositories to download the source.
Study at Harvard, Stanford or MIT - Open edX provides free online courses from Harvard, MIT, Columbia, UC Berkeley and other top Universities. Hundreds of courses for almost all major subjects and course levels. Open edx also offers some paid courses and selected certifications.
Linux Manual Pages - A man or manual page is a form of software documentation found on Linux/Unix operating systems. Topics covered include computer programs (including library and system calls), formal standards and conventions, and even abstract concepts.