home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
dirs
/
northc_384.lzh
/
NorthC
/
NorthC2.LZH
/
bin
/
make.doc
< prev
next >
Wrap
Text File
|
1990-09-04
|
11KB
|
303 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 divide 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 which files you have changed since the last
build and 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, 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 'C'
source 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" must
be separated by blank lines. If we now change the file "fubar.h" then 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 summarise, 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 '\' character 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 special item
"always", for example by adding the item
date.o : always
to the Makefile. "always" 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 preferred 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 -q -g -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".
If you want to use the "top" optimiser you should add an item
.c.o:
NorthC -Ot:$*.s $*.c
top t:$*.s t:$*.s1
a68k -g -q -O$*.o t:$*.s
delete t:$*.s t:$*.s1
into you makefile.
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 dependencies, 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.