|
...making Linux just a little more fun! |
By Tedi Heriyanto |
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 a main.cpp file (Remember: we do not recommend to use such file naming scheme in the real life).
Suppose one day you find a bug in 2.cpp and fix it. In order to get a new foo program, you must recompile all of the 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, especially if you don't have fast computer.
What can you do then? Are there no solutions for this?
Please worry not my friends. That kind of problem has already been experienced by our fellow computer hackers years ago. As a solution to this matter, they made a program called make. This program will only build source code that has been changed instead of build all of source code. If you change file 2.cpp, then make will build it and only it. Isn't is fun?
The followings are other reasons why we need make [2] :
If you think that make can solve all your problems in building source code, please think again, because make cannot do anything without instructions given by the programmer. make must be accompanied by another file which contains commands to make, this file usually called makefile.
This file is normally named makefile or Makefile. As a convention, GNU programs have makefile called Makefile, because it is easy to see (if you do "ls" then this file is usually always be in the top). If you called it with another name, you have to give make option -f to let it know that you use that file.
For example, if we have a makefile named bejo, the command to run make against this file is :
make -f bejo
A makefile consists of target, dependencies and rules section. Dependecies are things or source code needed to make a target; the target is usually an executable file. The rules are the commands needed to make that target.
Below is a simple description of a makefile.
target: dependencies command command ...
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. That's a tab, not spaces. Forgetting the tab or using spaces instead are two of the most common mistakes in constructing makefiles, and the makefile won't work without the tabs.
The above makefile can be describe as follows:
To put 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 given comments :
# Creating target named "client" 1 client: conn.o 2 g++ client.cpp conn.o -o client # Creating object file "conn.o" 3 conn.o: conn.cpp conn.h 4 g++ -c conn.cpp -o conn.o
A phony target is a fake filename. It is just a name for commands that will 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 enable the makefile to do other things besides creating files.
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 the clean file is always new, so it needs to be executed.
The phony target will stop working if someone creates a file named clean in the current directory. Because it doesn't require dependencies, file clean will be considered up-to-date, and the 'rm' command won't be executed. To resolve this problem, you can explicitly declare a target as phony, using special target .PHONY. For example :
.PHONY : clean
In the makefile above, make clean will always run the clean commands, whether or not a file named clean exists.
$VAR_NAME=value
Usually 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 two kind of variables, the first is recursively expanded variable and simply expanded variable.
In 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 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) -O2The ':=' creates the variable CC. The '+=' appends to its value.
I hope this short tutorial will give you enough knowledge to create makefile. Until then, happy hacking.