Makefiles

Notes on Makefiles


Why learn about makefiles?

This is motivated well by [2]:

Starting Out

A Simple Makefile

Here is a straightforward makefile that describes the way an executable file called edit depends on 4 object files which, in turn, depend on four C source and three header files.

edit : main.o kbd.o command.o display.o 
        g++ -g -o edit main.o kbd.o command.o display.o

main.o : main.c defs.h
        g++ -g -c main.c

kbd.o : kbd.c defs.h command.h
        g++ -g -c kbd.c

command.o : command.c defs.h command.h
        g++ -g -c command.c

display.o : display.c defs.h buffer.h
        g++ -g -c display.c

clean :
        rm edit main.o kbd.o command.o display.o 

To use this makefile to create the executable file called 'edit', type: make
To use this makefile to delete the executable file and all the object files from the directory, type: make clean

Adding Variables

Now we're going to "spice" up the above makefile example a bit. To start with, we will add a few variables. A variable is defined in the makefile using format:

    variable_name = value

In our case, we would like to define a variable for all of the object files. This way, we only need to list all of the objects files once.

Further, it is stylistic to specify the compiler type and options in only one place. This way different compiler specifications can be used easily.

COMPILER = g++
CFLAGS   = -g
OBJECTS  = main.o kbd.o command.o display.o 

edit : $(OBJECTS)
        $(COMPILER) $(CFLAGS) -o edit ($OBJECTS)

main.o : main.c defs.h
        $(COMPILER) $(CFLAGS) -c main.c

kbd.o : kbd.c defs.h command.h
        $(COMPILER) $(CFLAGS) -c kbd.c

command.o : command.c defs.h command.h
        $(COMPILER) $(CFLAGS) -c command.c

display.o : display.c defs.h buffer.h
        $(COMPILER) $(CFLAGS) -c display.c

clean :
        rm edit $(OBJECTS)

Dealing with errors in commands

After each shell command returns, make looks at its exit status. If the command completed successfully, the next command line is executed; after the last command line is finished, the rule is finished. If there is an error (the exit status is nonzero), make gives up on the current rule, and perhaps on all rules.

Sometimes the failure of a certain command does not indicate a problem. For example, in the above we don't want an error reported if one of the object files does not exist for removal by make clean.

To ignore errors in a command line, write a `-' at the beginning of the line's text (after the initial tab). The `-' is discarded before the command is executed. In our case, this will look:

...
clean :
        -rm edit $(OBJECTS)

Now the makefile will continue executing in spite of errors reported by rm

Adding echo statements and automatic variables

Normally make prints each command line before it is executed. This is referred to as echoing because it gives the appearance that you are typing the commands yourself. When a line starts with `@', the echoing of that line is suppressed. The `@' is discarded before the command is executed. Typically this feature is only used with echo commands that indicate progress through the makefile

Automatic variables have values computed afresh for each rule that is executed, based on the target and dependencies of the rule. For example:

Incorporating these features into our running example, we get:

COMPILER = g++
CFLAGS   = -g
OBJECTS  = main.o kbd.o command.o display.o 

edit : $(OBJECTS)
        @echo "$@ being recompiled due to updates in $?"
        $(COMPILER) $(CFLAGS) -o $@ ($OBJECTS)

main.o : main.c defs.h
        @echo "$@ being recompiled due to updates in $?"
        $(COMPILER) $(CFLAGS) -c $<

kbd.o : kbd.c defs.h command.h
        @echo "$@ being recompiled due to updates in $?"
        $(COMPILER) $(CFLAGS) -c $<

command.o : command.c defs.h command.h
        @echo "$@ being recompiled due to updates in $?"
        $(COMPILER) $(CFLAGS) -c $<

display.o : display.c defs.h buffer.h
        @echo "$@ being recompiled due to updates in $?"
        $(COMPILER) $(CFLAGS) -c $<

clean :
        -rm edit $(OBJECTS)

References

  1. http://www.gnu.org/manual/make-3.77/make.html
  2. "The Berkeley UNIX Environment", 2nd edition, by R. Nigel Horspool