Rod Byrne Department of Computer Science rod@cs.mun.ca
October 3, 1996
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.
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
.
.
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.
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.
#include "a.h"
#include <stdio.h>
f() { }
#include <ctype.h>
#include "a.h"
#include "b.h"
main()
{
f();
}
# 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
Make works by:
# 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
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!
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)
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 ....
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
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 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 [ -f makefile ] [ option ] ... target ...