makefiles

makefiles

[ makefiles | Structure | Comments | Explicit rules | Implicit rules | Variables | Examples | Links ]

The purpose of makefiles is to help you with your coding projects. One will often have a program which have, say, several header files and a number of C source files. If you then make a change to one of the files, you will have to recompile all the files. This is handled by the program make, following the commands in your makefile - it will only recompile the files which contains changes, and also makes it easier and faster to give the order to compile everything. You no longer have to write long and complex compiler commands every time.

Usually, the file that contains all the commands to make is called makefile or Makefile. You can then just invoke make and it will follow these instructions. You can, however, give the file any name. If you call it something else you will have to use make -f <name of makefile> to call it.

Structure

A makefile consists of three sections: target, dependencies, and rules. The target is normally either an executable or object file name. The dependencies are source code or other things needed to make the target. The rules are the commands needed to make the target.

A simple makefile might be structured like this:

# Comments are preceded by the hash symbol
target: dependencies
        command 1
        command 2
        ...
        command n

A makefile can also contain definitions of variables and inclusion of other makefiles. The variables in makefiles may be overridden in the command-line arguments that are passed to the make utility. An example is that the variable "CC" is often used in makefiles to refer to a specific C compiler, and the user may wish to provide an alternate compiler to use.

A very important thing to remember about makefiles are that every rule line begins with a tab, not spaces. Otherwise make might think it is some sort of dependency.

Comments

Any line that begins with a # is a comment and will be ignored.

Explicit rules

These are rules that tell make which files depend on the compilation of other files, as well as the commands required to compile a particular file. They have this form:

targetfile : sourcefiles
# NOTE: there is a TAB character before each command.
	commands           

This rule means that to create the targetfile, make must perform the listed commands on the sourcefiles.

Example

main: main.c test.h List.h
	pathcc -o main test.h List.h

The above example shows a rule that says that in order to create the target file main, the source files main.c, test.h and List.h have to exist, and make should use the command:

pathcc -o main test.h List.h

to create it.

Implicit rules

Implicit rules are in many ways like explicit rules, they are just listed without commands. This means make will use the suffixes on the files to determine which commands to perform.

Example

test.o: test.c io.h

This will cause the following command to be executed:

$(CC) $(CFLAGS) -c test.c io.h

Variables

It is possible to define variables in a makefile. To do this use the following command:

VAR_NAME=value

It is a convention to write variable names in uppercase. For instance:

OBJECTS=main.o hello.o test.o

In order to get a variables value, put the symbol $before the varables name, like this:

$(VAR_NAME)

Examples

Hello: Hello.o
	cc -o $@ $<
 
Hello.o: Hello.c
	cc -c -o $@ $<
 
.PHONY: clean
 
clean:
	rm -f Hello Hello.o
 

This small makefile is started with either make or make Hello. It does one more thing than just compile the program - there is also the target 'clean' which is used to remove all the files generated by the compilation with one command: make clean.

The first line in this makefile is the dependendencies (Hello: Hello.o), while the second line contains the rule to create the target Hello. The third line the dependencies for making Hello.o are listed, while line 4 contains the rules to make the target Hello.o in line 3.

Note that the PHONY tag is a technicality that tells make that a particular target name does not produce an actual file. It is not strictly necessary to include the line with the PHONY tag, unless a file named clean exists in the current directory. The $@and $<are two of the so-called internal macros and stand for the target name and "implicit" source, respectively. There are a number of other internal macros, which can be seen here.

main.exe : main.o foo.o
	pathcc main.o foo.o -o main.exe

main.o : main.c
	pathcc -c main.c

foo.o : foo.c
	pathcc -c foo.c

This simple makefile is run by giving the command make. The program always starts with the first rule it sees, in this case for main.exe. It then tries to build that first and finds dependencies. It will then check to see if any of those needs to be updated. This means, that the first time you call make for this makefile, it will run the following three commands:

pathcc -c main.c
pathcc -c foo.c
pathcc main.o foo.o -o main.exe

Let us assume you then edit the file foo.c and run make again. It will then only run these commands:

pathcc -c foo.c
pathcc main.o foo.o -o main.exe

Because there was no reason to recompile main.c, it will not do that.

makefile with variables

CC = pathcc
CFLAGS = -g -O2
OBJECTS = main.o foo.o

main.exe : $(OBJECTS)
	$(CC) $(CFLAGS) $(OBJECTS) -o main.exe

main.o : main.c
	$(CC) $(CFLAGS) -c main.c

foo.o : foo.c
	$(CC) $(CFLAGS) -c foo.c

There are many similarities between this makefile and the last. The difference is that many of the commands have been replaced with variables. Then, when make runs, it replaces the variables in the target, dependency, and command sections of the rules. This is often advantage, since it lets you specify the things that changes often in one place. One example is that it is very easy to change the compiler, since we are using the variable CC everywhere - and it is defined at the very top.

makefile with patterns

CC = pathcc
CFLAGS = -g -O2
OBJECTS = main.o foo.o

main.exe : $(OBJECTS)
	$(CC) $(CFLAGS) $(OBJECTS) -o main.exe

%.o : %.c
	$(CC) $(CFLAGS) -c $<

This is almost the same makefile as the one above, however, if you look in the last line you will see a pattern has been defined. This can be used every time make needs to compile any source. This is much simpler if we have many sources - otherwise we would have to write a rule for including the source for each of them. In the pattern, the % character is used to denote the part of the target and dependency that matches whatever the pattern is used for. The $< is a special variable meaning "whatever the dependencies are". There is another useful variable which we will often have use for. It is $@, which means "the target".

After this addition we can now add more source files in a simple manner, by just updating the line that defines the OBJECTS variable. The variable names CC and CFLAGS are part of make's built-in rules. To see a list of all of these, look at man make or run make -p. There is also a reference manual for make, which can be accessed by running info make. It will contain many examples and suggestions for building makefiles.

Links

Here is a list of links to more information about makefiles.

Updated: 2017-09-21, 11:05