how to create a Makefile

This article will provide a guidance to create your own Makefile. The article will explain why we need a Makefile and will also list several things we should consider in creating a Makefile.

Introduction

Imagine you are developing a program called foo, which consists of five headers, that is 1.h, 2.h, 3.h, 4.h, and 5.h, six C-language source code files named 1.cpp to 5.cpp, and amain.cpp file (Remember: we do not recommend to use such file naming scheme in the real life).

Suppose you find a bug in 2.cpp and has fix it. In order to get a new foo program, you have to recompile all files, header and source code, even though you just change one file. This is not a fun job, waiting for the computer to finished its process compiling your program. Particularly if you don't have fast computer.

What can you do then? Is there any solution for this problem ?

Please do not worry my friends. That kind of problem has already been experienced by our fellow computer hackers years ago. To tackle this problem, they have developed a program calledmake. Instead of build all of the source codes, this program will only build source code that has been changed. If you change file 2.cpp, then make will only build it. Isn't it fun?

The followings are several other reasons why we need make [2] :

  • A software project which consists of many source codes, can have complex and long compiler commands. Using make, it can be reduced.
  • Programming project sometimes need specialized compiler options that are so rarely used they are hard to remember; with make this can be reduced.
  • Maintaining a consistent development environment.
  • Automating the build process, because make can be called easily from a shell script or a cron job.

Why Do We Need a Makefile?

Although make is very useful, it cannot do its job without the instructions given by us, the programmer. make instructions is stored in a text file. This file is usually called makefile and contains commands that must be processed by make.

This file is normally named makefile or Makefile. As a convention, GNU programs named their makefile, Makefile, because it is easy to see (if you do "ls" then this file is usually always on the top of the list). If you give it another name, just make sure you include option -f to make command in order to let it know that you use it.

For example, if we have a makefile named bejo, then the command we use to instruct make to process that file is :

make -f bejo

Makefile Structure

A makefile consists of targetdependencies and rules section. Dependecies are things or source code needed to make a target; target is usually an executable or object file name. Rules are commands needed to make the target.

Following is a simple description of a makefile :

target: dependencies
	command
	command
	...

An Example of Makefile

The following is a simple makefile example (line numbers added for the article):

1 client: conn.o 
2	g++ client.cpp conn.o -o client
 
3 conn.o: conn.cpp conn.h
4   g++ -c conn.cpp -o conn.o

In the makefile above, dependencies is line contained client: conn.o, while rules is line contained g++ client.cpp conn.o -o client. Note that every rule line begins with a tab, not spaces. Forgetting to insert a tab at the beginning of the rule line is the most common mistakes in constructing makefiles. Fortunately, this kind of error is very easy to be spotted, becausemake program will complain about it.

Detail description of the makefile depicted above are as follows :

  • Create an executable file named client as a target, which depends on file conn.o
  • Rules to create the target are in line 2.
  • In the third line, to make target conn.o, make needs files conn.cpp and conn.h.
  • The rules to make target conn.o are in line 4.

Comment

To give a comment in makefile, merely put '#' in the first column of each line to be commented.

Below is an example makefile that has already been commented :

# Create executable file "client"
1 client: conn.o
2   g++ client.cpp conn.o -o client

# Create object file "conn.o"
3 conn.o: conn.cpp conn.h
4   g++ -c conn.cpp -o conn.o

Phony Target[1]

A phony target is a fake filename. It is just a name for commands that will be executed when you give an explicit request. There are two reasons for using phony target : to avoid conflicts with a file with the same name, and to enhance the makefile performance.

If you write a rule whose command will not create a target file, those commands will be executed every time the target is remade. For example:

clean:
	rm *.o temp

Because the command rm will not create a file named clean, that file will never exist. Command rm will always be executed every time you called make clean, because make assume that the clean file is always new.

The above target will stop working if a file named clean exists in the current directory. Because it does not require dependencies, file clean will be considered up-to-date, and the command 'rm *.o temp' will not be executed. To resolve this problem, you can explicitly declare a target as phony, using special target command .PHONY. For example :

.PHONY : clean

In the makefile above, if we give instruction make clean from the command-line, the command 'rm *.o temp' will always be run, whether or not a file named clean exists in the current directory.

Variable

To define a variable in a makefile, you can use the following command:
$VAR_NAME=value

As a convention, a variable name is given in uppercase, for example :

$OBJECTS=main.o test.o

To get a varible's value, put the symbol $ before the variable's name, such as :

$(VAR_NAME)

In makefile, there are two kinds of variables, recursively expanded variable and simply expanded variable.

In the recursively expanded variable, make will continue expanding that variable until it cannot be expanded anymore, for example :

TOPDIR=/home/tedi/project
SRCDIR=$(TOPDIR)/src

SRCDIR variable will be expanded, first by expanding TOPDIR variable. The final result is /home/tedi/project/src

But, recursively expanded variable will not be suitable for the following command :

CC = gcc -o
CC = $(CC) -O2

Using a recursively expanded variable, those command will go to endless loop. To overcome this problem, we use a simply expanded variable :

CC := gcc -o
CC += $(CC) -O2
The ':=' symbol creates the variable CC and given its value "gcc -o". The '+=' symbol appends "-O2" to CC's value.

Closing Remarks

I hope this short tutorial will give you enough knowledge to create makefile. Until then, happy hacking.

Bibliography

  • 1 GNU Make Documentation File, info make.
  • 2 Kurt Wall, et.al., Linux Programming Unleashed, 2001.

你可能感兴趣的:(how to create a Makefile)