The UNIX Make Utility

Rod Byrne Department of Computer Science rod@cs.mun.ca

October 3, 1996

Motivation for make

You have a software system composes of the following files:

   abs_syn.h       heap.h           module.h        symbol.h
   attribute.c     lex_interface.h  print.c         tststmt.c
   attribute.h     lg3sim.c         rnl.c           tststmt.h
   bind_stmt.c     lg3sim.h         sim_env.c       var.c
   expr.c          logic3.y         sim_env.h       var.h
   flex.c          main.c           stmts.c
   heap.c          module.c         symbol.c

These files include C++ source, YACC source, and LEX source files. Your job is to run the necessary commands to produce an executable program.


Some of the commands

g++  -O -g -c O2 -o logic3.o logic3.c
g++  -Wall -g -O2  -c flex.c -o flex.o
g++  -Wall -g -O2  -c print.c -o print.o
g++  -Wall -g -O2  -c stmts.c -o stmts.o
g++  -Wall -g -O2  -c expr.c -o expr.o
g++  -Wall -g -O2  -c symbol.c -o symbol.o
g++  -Wall -g -O2  -c var.c -o var.o
g++  -Wall -g -O2  -c main.c -o main.o
g++  -Wall -g -O2  -c lg3sim.c -o lg3sim.o
g++  -Wall -g -O2  -c module.c -o module.o
       .
       .


Use shell scripts

One way to solve the problem is to place all the commands into a shell script and run the script each time you make a change and need a new version of the executable.


A simple example

Your software system is composed of four files. These files are: a.c, a.h, b.c, and b.h. The files a.c and b.c must be compiled together to produce the system. One possible set of commands to create the system is:

gcc -c a.c
gcc -c b.c
gcc -o ab a.o b.o

You also know that a.c has to be recompiled if a.h or a.c change, and b.c has to be recompiled if b.h, b.c and a.h change. If either a.o or b.o change, then the system has to be re-linked.


a.c and b.c

#include "a.h"
#include <stdio.h>

f() { }

#include <ctype.h>
#include "a.h"
#include "b.h"

main()
{
      f();
}


A Makefile

# comments  start with a '#'
# a dependency is given by target: dependency list

ab: a.o b.o
        gcc -o ab a.o b.o
# NOTE: all the commands must be preceded by a TAB

a.o: a.h a.c
        gcc -c a.c

b.o: b.c b.h a.h
        gcc -c b.c


How make works

Make works by:

  1. finding the target in the description file,
  2. recursively applying make to all the dependencies,
  3. checking that all the target's dependencies exist and have a modification date early then the target,
  4. if a dependency has a later modification date, then the targets's commands are executed,


Using Macros

# makefiles can contain macros
CC = gcc
CFLAGS = -O

ab: a.o b.o
        $(CC) $(CFLAGS) -o ab a.o b.o
        @ echo "It's done!"

a.o: a.h a.c
        ${CC} ${CFLAGS} -c a.c

b.o: b.c b.h a.h
        $(CC) $(CFLAGS) -c b.c


Running Make

The make command can be executed by typing: make. Running make with no arguments results in make searching for the files makefile and then Makefile. The first file it finds will be its script file.

Assuming ab, a.o, and b.o do not exist.

% make 
gcc  -O  -c a.c
gcc  -O  -c b.c
gcc -o ab a.o b.o
Is done!


Using make for LaTeX

make.ps: make.dvi
       dvips -t landscape make.dvi

make.dvi: make.tex
       latex make.tex

print:
       ljps -Pcsgljet make.ps

clean:
       rm -f make.dvi make.ps make.aux make.log


Short cuts in make

CC = gcc 
CFLAGS = -O 
OBJS = a.o b.o

# The $@ is expanded to the targets name.
ab: $(OBJS)
       $(CC) $(OBJS) -o $@
       @ echo "Is done!"

a.o: a.h a.c
b.o: b.c b.h a.h

clean:
       rm -f ab $(OBJS)


Makedepend

CC = gcc 
CFLAGS = -O 

SRCS = a.c b.c
OBJS = $(SRCS:.c=.o)

ab: $(OBJS)
       $(CC) $(OBJS) -o $@

depend:
       makedepend -f Makefile $(SRCS)
# DO NOT DELETE THIS LINE -- make depend depends on it.
a.o: a.h /usr/include/stdio.h
b.o: /usr/include/ctype.h  a.h b.h


Archives

Sometimes it is convenient to collect a bunch of files and store them in one file called an archive. The Unix command, ar, is an archive program. Its general usage is:

ar [crxvt] archive-name file1 file2 ....

c
creates a new archive
r
replaces the named files in the archive
x
extracts the named files in the archive
t
list the table of contents
v
verbose, tells you what it is doing


Object Modules Archives

The most common type of file stored in an archive is an object module. Software is often grouped into libraries (e.g., libX, libc ....). The following command creates a library containing the object modules a.o and b.o.

ar rc lib.a a.o b.o

Most of the linkers under Unix understand object module libraries.

gcc m.c lib.a


Make and archive libraries

Since archives are so common, make has a special syntax to deal with them.

LIB = lib.a(a.o) lib.a(b.o)
lib.a: $(LIB)

lib.a(a.o): a.c a.h
       $(CC) $(CFLAGS) -c a.c
       ar rv lib.a a.o; rm a.o

lib.a(b.o): b.c b.h a.h
       $(CC) $(CFLAGS) -c b.c
       ar rv lib.a b.o; rm b.o


A GNU make extension

# a more compact library makefile
CC = gcc 
CFLAGS = -O 
SRCS= a.c b.c

OBJS = $(SRCS:.c=.o)
LIB  = $(OBJS:%.o=lib.a(%.o))

lib.a : $(LIB)
       rm -f $?


Make Command Line Options

make [ -f makefile ] [ option ] ...  target ...

-n
just prints the commands with out executing them
-i
ignore all errors returned from commands
-s
silent mode, do not print the commands
-p
print the database of rules



Rodrigue Byrne
Thu Oct 3 17:10:14 NDT 1996