home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d03xx
/
d0353.lha
/
NorthC
/
NorthC2.LZH
/
bin
/
make.doc
< prev
next >
Wrap
Text File
|
1990-05-01
|
10KB
|
300 lines
(c) 1990 S.Hawtin.
Permission is granted to copy this file and make provided that:
1) Neither are used for commercial gain
2) This notice is included in all copies
3) Altered copies are marked as such.
4) Each copy of make is accompanied by a copy of this file.
No liability is accepted for the contents of the file.
make.doc within make
MAKE
make [-fmakefile][-?][target]
Maintain an up-to-date version of a program. The options have the
following meanings
-f<makefile>
Take the description from the file <makefile> rather than "Makefile".
-?
Print out the commands that would be executed but do not perform them.
target
Construct the file <target> rather than the first item in the makefile.
The make command keeps programs up to date, it does this by reading a file
that describes how to construct a target program and executing all the
commands required to update the program.
When using 'C' and other compiled languages it is normal to split the source
code for a program into many files, this allows you to split the code into
logical chunks. Most compiled languages allow you to recompile each source
file independently to produce an "object" file, the user then combines all the
object files to produce the actual program with a "linker". Whenever you
alter a source file it must be recompiled and the resulting "object" file must
be relinked into the executable program, it can be difficult to remember what
set of tools need to be run on which programs. The "make" program works out
which commands need to be executed to bring a program up to date and executes
them.
An example will explain what the program does better, assume you have a
program called "jim" that combines three source files, "foo.c", "bar.c" and
"baz.asm". To use "make" in its simplest form you should create a file
called "Makefile" containing the lines
jim : foo.o bar.o baz.o
blink with $*.blink
this tells the "make" program that "jim" depends on the object files "foo.o",
"bar.o" and "baz.o", and can be created by the CLI command
"blink with jim.blink". You must now construct the file "jim.blink" that the
"blink" command requires, this is done by the CLI command
make $*.blink
the "$*" construct will be explained later.
Once the "Makefile" and "jim.blink" files have been created you can use the
"make" program to construct "jim", just type the command
make
and it will call all the commands to make "jim". Now if you change the file
"foo.c" and then type the "make" command it will only issue the commands
required to bring the program up to date, the program will not bother to
recompile "bar.c" or "baz.asm".
So every time you change a set of the source files you just type "make" and
all the necessary compilations will be done. This is well and good, assuming
we are only going to edit the ".c" and ".asm" files. If however if you change
an include file you want "make" to recompile all the files that include it.
We get make to do this by adding some extra lines into the "Makefile". If the
new "Makefile" contains
jim : foo.o bar.o baz.o
blink with $*.blink
foo.o: fubar.h foo.h
bar.o : fubar.h
then every time "fubar.h" is altered "make" will recompile both "foo.c" and
"bar.c". Notice that the three items "jim", "foo.o" and "bar.o" are
seperated by blank lines. If we now change the file "fubar.h" the "make"
command will recompile both "foo.c" and "bar.c".
By default the "make" program always tries to construct the first item in
the "Makefile", this is why you must put the line
foo.o: fubar.h
after
jim : foo.o bar.o baz.o
if it was put in before then the "make" program would just make "foo.o" and
not "jim". You can get "make" to construct a particular item by telling it
which target item you want to update, for example to make "bar.o" just type
the command
make bar.o
we have already seen this being used when we created the "jim.blink" file.
So, to summerise, each item in the "Makefile" starts with a file name, then
after the ':' a list of items that this item depends on, the following lines,
up to the first blank line, tell "make" the commands required to construct the
item. Each item can appear on the left hand side as many times as you want
so long as you only specify the commands to create it once.
You can of course add comments into the "Makefile", any line that starts
with a '#' is treated as a comment.
One problem you might come across is having too many dependencies to fit on
a single line, the '\' charater tells "make" that the dependencies are
continued on the next line, so for example
jim: foo.o \
bar.o \
baz.o
blink with $*.blink
is the same as the original entry for "jim". The '\' character must
be the last character on the line.
Sometimes you want to "make" an item every time you construct the program,
for example if you have a file "date.c" that consists of
#include <stdio.h>
print_date()
{/* Print the date the program was last compiled */
printf("This version was compiled on %s\n",__DATE__);
}
then even though the actual text of the source file does not change you want
to recompile it whenever the program is compiled. You can force "make" to
always recompile this program by appending the item
date.o : always
to the Makefile. "always" is a special item in "Makefile"s, it is considered
to be newer than everything else. The "__DATE__" macro is an ANSI C
extension that returns a string containing the compilation date.
Although the "make" program knows how to convert a ".c" program into a ".o"
program you can override this by adding an item such as
foo.o: foo.c
NorthC -I:incl/ foo.c
A68k foo.s
Delete foo.s
whenever "foo.c" is changed the given commands will be executed to create
"foo.o" rather than the normal commands.
If you have a prefered way to convert ".c" files into ".o" files you could
type this in after every ".o" file, however "make" will also allow you to
define a "default" way to convert between the files, if you add the item
.c.o:
NorthC -I:incl/ $*.c
A68K $*.s
Delete $*.s
to the "Makefile" this item tells "make" to construct ".o" files from ".c"
files by calling the commands
NorthC -I:incl/ $*.c
A68K $*.s
Delete $*.s
The sequence "$*" is replaced by the base file name. The base file name
consists of the name up to the final '.', so for example the base name
of "jim.2.c" is "jim.2".
"make" will always add some default items to the end of the "Makefile",
if they do not clash with existing entries, the current default items are
.c.o:
NorthC -Ot:$*.s $*.c
A68K -O$*.o t:$*.s
Delete t:$*.s
.s.o:
A68K $*.s
.asm.o:
A68K $*.asm
this tells the "make" program how to compile 'C' programs and assemble ".asm"
and ".s" files.
You can use the default mechanism to create files with any extension of up
to four letters, for example
.uil.uid:
Delete $*.uid
Motif:Uil/uil -o $*.uid $*.uil
tells "make" that each time it finds a reference to a file such as "jim.uid"
it should construct the file with the commands
Delete jim.uid
Motif:Uil/uil -o jim.uid jim.uil
whenever the "jim.uil" file is altered.
You can split your "Makefile" into multiple files. When you want to read a
file, for example "make.depends", just include the command
$<make.depends>
in "Makefile". Make will read the file "make.depends" at that point.
If you wish to read a file other than "Makefile" when you call "make" add
the "-f" option, for example to read the dependencies from "jim.make"
make -fjim.make
will make the first item in the file "jim.make".
How Make Works
You don't actually have to read this bit but it might help if you cannot
get make to do something complicated.
The "make" command works by creating a dependency tree, for example the
sequence
jim: foo.o bar.o baz.o
blink with $*.blink
foo.o: fubar.h foo.h
bar.o: fubar.h
will create a dependency tree
jim
/ | \
/ | \
/ | \
/ | \
foo.o bar.o baz.o
| \ /
| fubar.h
|
foo.h
"make" then scans this tree to find items that have no create command
sequence defined. Any item that we have not yet been told how to make will
either be a source file, for example "foo.h" or we will have to find out how
to make it from the defaults list. So make will now scan the tree, when it
comes to "foo.o" it discovers that it has a method for creating ".o" files
from ".c" files, and a ".c" file exists, so it adds the default ".c.o" create
method to "foo.o" and adds "foo.c" to its dependencies. When it comes to the
file "bar.o" because it cannot find "bar.c" it looks further down the list of
defaults and finds that a "bar.asm" file exists. Once the tree has been
scanned it looks like
jim
/ | \
/ | \
/ | \
/ | \
foo.o bar.o baz.o
/ | \ / \ |
foo.c | fubar.h \ baz.asm
| \
foo.h bar.c
"make" then goes over this tree to see if any item is older than one of its
depenedencies, when it finds such an item it adds the commands for creating
this item to an intermediate file in the "t:" directory.
Once it has gone over the tree it calls the AmigaDOS command "execute" to
run the created command file, I have to call this function because I want
"make" to stop as soon as one of the commands fails. I cannot find out how to
determine the return code of a called program, if anyone out there can tell
me how to do this please get in touch.
The last thing the program does is to delete the command file it created
in the "t:" directory.