Phases Of Compiling
===================

Source -----------> Object --------------v
         Compile             Link       Executable
Source -----------> Object --------------^

I use generic names for the commands, so:
 - compile -o <out> <in> is actually gcc -c -o <out> <in>
 - link -o <out> <in> is actually gcc -o <out> <in>
 
(But options may need to be added to some of the above.)


What is the problem solved by make?
===================================

Say we have to make program out of the source files source1.c
source2.c ... source100.c. How do we do that? 

- First Try: Realizing that the compiler can create object files, 
  create an object file corresponding to each source file and link
  them together. We can automate this using a shell script.

  compile -o object1.o source1.c
  compile -o object2.o source2.c
  ...
  compile -o object100.o source100.c
  link -o program object1.o object2.o ... object100.o

  - Downside: We still need to recompile every piece of source even 
    for a small change.

- Second Try: Only recompile the parts that change, then relink the whole 
  thing. 

  if [ source1.c -nt object1.o ]; then compile -o object1.o source1.o; fi
  if [ source2.c -nt object2.o ]; then compile -o object2.o source2.o; fi
  ...
  link -o program object1.o object2.o ... object100.o

  - This is better. However, we need to write complex rules for each object
    in the chain, and make sure we get those rules right. This may be hard 
    to do.

- Make automates this, and doesn't require massive numbers of shell tests. 
  it also adds a few new things, like figuring out which rules that need
  to be used.

Basic Makefile
==============

all: program

program: object1.o object2.o ... object100.o
	link -o program object1.o object2.o ... object100.o

object1.o: source1.c
	compile -o object1.o source1.c

object2.o: source2.c
	compile -o object2.o source2.c

...

object100.o: source100.c
	compile -o object100.o source100.c

These rules are used to decide which commands need to run. The first
line of the rules contains a list of targets separated by a colon from
a list of dependencies. The rest of the lines of a rule consists of
commands that are run if any of the dependencies are newer than any of
the targets. These commands must be prefixed by a tab character,
spaces won't work.

If any of the commands in a makefile returns an error code, make
immediately stops processing and returns with an error code.

This is a fairly simple makefile. Among it's flaws is that the compile
command is duplicated twice. While that's fine in this simple case, in
complicated makefiles one may want to use pattern rules so that the
commands only need to be written once.

A pattern command uses the % character to indicate text that is the
same in both target and dependency.

%.o: %.c
	compile -o $@ $+

Since we don't know the exact names of the target or dependencies, we
need to use automatic variables to represent them. Some of the
automatic variables we can use are:

- $@: The target of the rule that caused the rule to be run.
- $<: The name of the first dependency.
- $?: All dependencies that are newer than the target.
- $+: All dependencies.
- $*: The stem of the rules. (Ie, if the rule is %.o: %.c, this is
      what matches the %s.

We can also use normal variables. There are two types that differ in
binding. Variables assigned using = are bound at use, those
assigned using := are bound at assignment time. This only matters if
you change the contents of a variable later in runtime.

Variables are used by surrounding the name with a dollar sign
surrounded by parenthesis.

a = 4
foo := $(a)
bar = $(a)
a = 2

# This should echo '4 2'.
all:
	echo $(foo) $(bar)

.PHONY: all

This also introduces the .PHONY target. This is a psuedo-target that
means that it's dependencies should be treated as if their targets
didn't exist, even if they did. 

So, the final version of the makefile will looks something like this:

objects = object1.o object2.o ... object100.o

# Rule 0
all: program

# Rule 1
program: $(objects)
	link -o program $(objects)

# Rule 2
source%.c: object%.o
	compile -o $@ $+

.PHONY: all

Basically, this uses rule 1 to figure out that the program needs to be
built from all of the objects. It then figures out that the objects
can be made from the c sources using rule 2. So, it executes rule 2
for each object/source file pair, then it links them together by
executing rule 1.

The gnu coding standards specifies common targets like 'install' and
'clean'.

For programmers in common languages, automake should be usedin
conjunction with autoconf to generate Makefiles. This gives all sorts
of neat features, like being able to build in other directories
(actually, make can do that using VPATH), and being able to easily
make sources using 'make dist'.


Example Makefile #1
===================

(I use this for some of my programming assignments. At the start of 
running this makefile, v2.ruri and v3.ruri exist as does the 
makefile and the tools, but neither the .jas files nor the 
.ijvm files exist.) 

programs = v2.ijvm v3.ijvm

# Rule 0
all: $(programs)

# Rule 1
%.jas: %.jas
	ijvmasm $@ $+

# Rule 2
%.jas: %.ruri
	ruri < $+ > $@.new
	mv $@.new $@
 
clean:
	-rm $(programs) *.jas

.PHONY: all clean

When make runs, it tries to build v2.ijvm and v3.ijvm. To build
v2.ijvm, it looks for v2.jas, via rule 1. v2.jas normally wouldn't
exist at runtime, but rule 2 tells how to build it from v2.ruri, which
does exist.

Having figure this out, make executes the commands in rule 2, causing
v2.jas to be built. Then it executes rule 1, causing v2.ijvm to be
built. Building v3.ijvm works the same way.

Another thing to note is the - before the command in clean. This
means that make should continue on even if the command fails.

Example Makefile #2
===================

(I use this to generate my web sites.)

html = index.html more.html
subdirs = rest

all: subdirs html

subdirs: $(subdirs)
	for dir in $(subdirs); do \
		(cd $$dir; $(MAKE)); \
	done

html: $(html)

%.html: %.ht
	ht2html $+ > $@.new
	mv $@.new $@
	fiximg $@

.PHONY: all html subdirs

Please note the way this recurses into subdirectories using the
subdirs rule. Also note that a single command can be extened onto
multiple lines using \, and that a $ can be passed to the shell using
$$.


For More Information
====================

Check out the info system. This can be accessed using the info or
pinfo commands, through emacs, or on the web at (among other places) 

  http://onegeek.org/cgi-bin/info2www/

The Make, Automake, and Autoconf info pages are the ones most relavant
to this talk.

- Tom Rothamel <tom-lilug@onegeek.org>
  9 May 2000

(Updated 10 May 2000, fixed a few bugs and added the "Phases of Compiling" 
 section.)