And of course there are a million versions of make with different options and functionalities. As you should realize by now, we try not to use fancy options because they're almost never portable, so this will be a very basic make lecture.
The syntax of make is roughly:
make [ -f makefile ] [ targets ]If you omit the -f, then it will use ./makefile or ./Makefile. If it can't find these, some make's will then look for a SCCS makefile (and I'm not going to cover SCCS, preferring rcs), then for makefile in your home directory, and then a system makefile. So if you type make and you see it doing things that you don't understand, chances are that it's using a bizarre makefile.
I'm sure you've all seen makefiles in the context of C. We'll use that as an example. Go into the directory make1, and look at the makefile. Look at all the source files. This is a simple program that is broken up into three C source files (printname.c, first.c and last.c) and two header files (fn.h and ln.h).
If you type make in the directory, you'll see it constructs printname.UNIX> cd make1 UNIX> ls -l total 6 -rw-r--r-- 1 plank 58 Jul 7 10:19 first.c -rw-r--r-- 1 plank 21 Jul 7 10:26 fn.h -rw-r--r-- 1 plank 57 Jul 7 10:19 last.c -rw-r--r-- 1 plank 22 Jul 7 10:21 ln.h -rw-r--r-- 1 plank 352 Jul 7 10:21 makefile -rw-r--r-- 1 plank 42 Jul 7 10:20 printname.c UNIX> make cc -c printname.c cc -c first.c cc -c last.c cc -o printname printname.o first.o last.o UNIX> ls -l total 33 -rw-r--r-- 1 plank 58 Jul 7 10:19 first.c -rw-r--r-- 1 plank 236 Jul 7 10:28 first.o -rw-r--r-- 1 plank 21 Jul 7 10:26 fn.h -rw-r--r-- 1 plank 57 Jul 7 10:19 last.c -rw-r--r-- 1 plank 244 Jul 7 10:28 last.o -rw-r--r-- 1 plank 22 Jul 7 10:21 ln.h -rw-r--r-- 1 plank 352 Jul 7 10:21 makefile -rwxr-xr-x 1 plank 24576 Jul 7 10:28 printname -rw-r--r-- 1 plank 42 Jul 7 10:20 printname.c -rw-r--r-- 1 plank 168 Jul 7 10:28 printname.o UNIX> printname Jim Plank UNIX>Now, if you modify last.c (say to print out LAST twice), then type make again, it will only recompile what is necessary:
(we will cover ed the next lecture)
UNIX> ed last.c
57
ed: 1,$n
1 #include "ln.h"
2
3 printlast()
4 {
5 printf("%s\n", LAST);
6 }
ed: 5t5
ed: 5s/\\n/ /
ed: 5,6p
printf("%s ", LAST);
printf("%s\n", LAST);
ed: w
80
ed: q
UNIX> make
cc -c last.c
cc -o printname printname.o first.o last.o
UNIX> printname
Jim Plank Plank
UNIX>
If you modify just one header file, then again, make will only recompile
what is necessary. This is extremely convenient and efficient, especially
when you are dealing with long compilation times, and many files.
UNIX> ed fn.h 21 ed: s/Jim/Dikembe char *FIRST = "Dikembe"; ed: w 25 ed: q UNIX> make cc -c first.c cc -o printname printname.o first.o last.o UNIX> printname Dikembe Plank Plank UNIX>Notice that there is a target called clean. This is not a file that gets made, but a way to specify for make to clean up your directory:
UNIX> ed makefile
352
ed: /clean/,/clean/+1p
clean:
rm -f a.out core printname *.o
ed: q
UNIX> make clean
rm -f a.out core printname *.o
UNIX>
If any command that make executes exits with a non-zero value, then make will exit instantly. Make can be used to manage pretty much anything. The commands can be any valid command and are normally executed using sh. A note, if you put @ as the first character after the tab on a command line then make will not echo the command just execute it.
name = stringAnd you use them with the $(name) or ${name} construction.
You may use any shell environment variable like a normal variable in a makefile. Of course you can override the environment variable setting in the makefile if you want.
Look at the makefile in the make3 directory. This does two common things. First, it bundles up all the object files for the executable into a variable called OBJS. Second, it assumes that you have set the environment variable CC to point to your C compiler. Try it out:
UNIX> cd make3 UNIX> setenv CC cc UNIX> make cc -c printname.c cc -c first.c cc -c last.c cc -o printname printname.o first.o last.o UNIX> printname Jim Plank UNIX> make clean rm -f a.out core printname *.o UNIX> setenv CC gcc UNIX> make gcc -c printname.c gcc -c first.c gcc -c last.c gcc -o printname printname.o first.o last.o UNIX> printname Jim Plank UNIX>To get a dollar sign passed to the shell, precede it with a backslash.
Most versions of make have default values for a specific set of variables. However the problem with this is that it assumes that the only version of make you will use is the current one. I would suggest that you follow a habit of always specifying the values for variables in every makefile so that there are no surprises. Some of the variables that are normally set are:
There is nothing magic about these variables but if you try to consistently use the names and always set the values, then others you give the makefile to will find it easier to understand what you are doing. There is one variable that you should NOT override and that is MAKE. You can use this when you want to say change directories and then execute make in that directory using that directories makefile. something like
cd mydir;$(MAKE);cd ..Another thing before we move on. Make can accept various command line arguments. One of those is "-n". This tells make to do everything except actually execute the commands. It checks the dependencies, echos out the commands as though it were executing them but doesn't actually execute them.
.Ds.Ts: commandsThis says that you build a file with suffix .Ts out of a file with a suffix of .Ds using the commands. In the command you may use the variable $* to stand for the part of the name before the suffix.
For example, look at the makefile in the make4 directory. This is very typical of makefiles that you'll see for simple programs:
UNIX> cd make4 UNIX> make cc -O4 -c printname.c cc -O4 -c first.c cc -O4 -c last.c cc -O4 -o printname printname.o first.o last.o UNIX> printname Jim Plank UNIX>Note that it's easy to specify that first.o depends on fn.h while letting the default commands take care of making first.o. While we are discussing SUFFIXES is a good time to bring up a couple of special macros that are defined by most versions of make. These are "$*" and "$@". These two macros are the basename of the of the current target and the name of the current target. They can save you a lot trouble when used with SUFFIX rules as we see here.
.c.o:
$(CC) -o $*.o -g $@
The list of macros allowed in make:
$< - the current dependcy file $@ - the current target file $* - the base name of the current target $? - all dependencies that are newer than the target
UNIX> alias mk make -f /mahogany/homes/plank/makefile UNIX>The first useful thing in there is the line that makes an object file out of a c file:
.c:
$(CC) -o $* -g -D$(ARCH) -I$(INCLUDE) $*.c $(LIBS) -lm
It assumes that the ARCH environment variable is set to reflect
what machine he is on (this was stolen from PVM's archtype command).
Then it makes sure to get include files from his home include directory,
plus object libraries from the correct lib directory. In this way, he
can write a quick C program that uses anything from his fields, dlist, rbtree,
socketfun and dataproc libraries (see CS360 lecture notes for
descriptions of all of these except the dataproc one), then make it with
mk. Also it lets him make quick jgraph files, octal dumps, and
tex-to-postscript files.
The second alias he has is the mkd alias:
UNIX> alias mkd pushd !* ; make all ; popd UNIX> (the pushd and popd commands are for the shell to change directories, see the man page on each)This will cd into the specified directory, execute ``make all'', and then cd back. It's something that can be quite convenient.
Finally, mkmake is a simple shell script that creates a generic makefile for a directory. That makefile assumes that each .c file is a separate program, and creates the commands to make each program. This is pretty simple, but often useful. There are similar utilities on some Unix systems that make fancy makefiles. If you're interested try the man page on makedepend and go from there.