Makefile

Running the command

make

causes a search for a file called Makefile or makefile in your directory and then execute it. In case you have several makefiles, you can specify one as:

make -f MyMakefile

Basic Makefile

The build process contains two steps;

  1. Compiler takes the source file and outputs the object files
  2. Linker takes the object files and creates an executable

The basic makefile is composed of:

target: dependencies
[tab] system command

By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe. If the first rule in the makefile has several targets, only the first target in the rule becomes the default goal, not the whole list.

The default target for makefiles is called all. In a simple case the target all has no dependencies:

all:
	g++ main.cpp hello.cpp factorial.cpp -o hello

In some cases it is useful to have different targets. This way, you don't need to recompile everything after modifying a single file:

all: hello
 
hello: main.o factorial.o hello.o
	g++ main.o factorial.o hello.o -o hello
 
main.o: main.cpp
	g++ -c main.cpp
 
factorial.o: factorial.cpp
	g++ -c factorial.cpp
 
hello.o: hello.cpp
	g++ -c hello.cpp
 
clean:
	rm -rf *o hello

In order to for make to execute correctly, it has to meet all the dependencies of the all target. It is very useful to have a clean target to get rid of all the object files and executables quickly.

Using variables

You can also use variables in your Makefiles. They are very helpful particularly when you want to change the compiler, or the compiler options. The variables are defined at the beginning of a makefile.

CC=g++
CFLAGS=-c -Wall
 
 
all: hello
 
hello: main.o factorial.o hello.o
	$(CC) main.o factorial.o hello.o -o hello
 
main.o: main.cpp
	$(CC) $(CFLAGS) main.cpp
 
factorial.o: factorial.cpp
	$(CC) $(CFLAGS) factorial.cpp
 
hello.o: hello.cpp
	$(CC) $(CFLAGS) hello.cpp
 
clean:
	rm -rf *o hello

There are some variables already prescribed and available; for more info have a look at this page: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html

Searching Directories for Prerequisites

It is often desirable to put sources in a separate directory from the binaries. The directory search features of make facilitate this by searching several directories automatically to find a prerequisite.

The value of the make variable VPATH specifies a list of directories that make should search. VPATH specifies a search list that make applies for all files, including files which are targets of rules.

In the VPATH variable, directory names are separated by colons or blanks. The order in which directories are listed is the order followed by make in its search.

For example,

VPATH = src:../headers

specifies a path containing two directories, src and ../headers, which make searches in that order.

With this value of VPATH, the following rule,

foo.o : foo.c

is interpreted as if it was written like:

foo.o : src/foo.c

assuming the file foo.c does not exist in the current directory but is found in the directory src.

Phony targets

A phony target is one that is not really the name of a file. It is just a name for some commands to be executed when you make an explicit request. There are two reasons to use a phony target: to avoid a conflict with a file of the same name, and to improve performance.

If you write a rule whose commands will not create the target file, the commands will be executed every time the target comes up for remaking. Here is an example:

clean:
        rm *.o temp

Because the rm command does not create a file named clean, probably no such file will ever exist. Therefore, the rm command will be executed every time you say make clean.

The phony target will cease to work if anything ever does create a file named clean in this directory. Since it has no prerequisites, the file clean would inevitably be considered up to date, and its commands would not be executed. To avoid this problem, you can explicitly declare the target to be phony, using the special target .PHONY as follows:

.PHONY : clean
clean:
        rm *.o temp

Once this is done, make clean will run the commands regardless of whether there is a file named clean. Since it knows that phony targets do not name actual files that could be remade from other files, make skips the implicit rule search for phony targets. This is why declaring a target phony is good for performance, even if you are not worried about the actual file existing.

Log In