Makefiles by example
Compiling your source code file can be tedious, specially when you want to include sereral source files and have to copy the compiling commond everytime you want to do it.
Well, I have news for you... Your days of commond line compiling are mostly over, because you well learn how to write Makefiles.
Makefiles are special format files that togather with make utility will help you automagically build and mange your projects.
For this session you will need these files: Download
I recommond creating a new directory ans placing all the files in there.
Note:I use g++ for compiling. You are free to change it to a compiler of your choice.
The make utility
If you run
make
this program will look for a file named makefile in your dircetory, and then execute it.
If you have several makefiles, then you can execute them with commond:
make -f MyMakefile
There are several other sitches to the make utility. For more info, man make.
Build process
- Compiler takes the source files and outputs object files
- linker takes the object files and creates an executable
Compiling by hand
The trivial way to compile the files and obtain the executable, is by running the commond:
g++ main.cpp hello.cpp factorial.cpp -o hello
The basic Makefile
The basic makefile is composed of:
target: dependencies
[tab] system commond
This sample applied to our sample would look like:(Makefile-1 contain following:)
all:
g++ main.cpp hello.cpp factorial.cpp -o hello
To run the makefile on your files, type:
make -f makefile-1
On this first sample we see that our target is called all. This is default target for makefiles.
The make utility will execute this target if no other one is specified.
We all see that there are no dependencies for target all, so make safely execute the system commond specified.
Finally, make compiles the program according to commond line we gave it.
Using dependencise##
Sometimes it is useful to use different targets. This is because if your modify a single file in your project, you don't have to recompile everything, only what you modified.
Here ia an example:
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
Now we see that the target all has only dependcies, but no system commond. In order for make to execute correctly, it has to meet all the dependencies of the called target ( in this case all).
Each of the dependencies are searched through all the targets available and executed if found.
In this example we see a target called clean. It is useful to have such target if you want to have a fast way to get rid of all the object files and executables.
Using vairalbes and commonts
You can also use vairalbes when you write Makefiles. It comes in handy in situation where you want to change the compiler, or the compiler options.
# I am a comment, and I want to say the variable CC will be
# the compiler to use
CC = g++
# Hey!, I am comment number 2. I want to say that CFLAGS will be the
# options I'll pass to compiler.
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:
$(CC) $(CFLAGS) hello.cpp
clean:
rm -f *o hello
As you can see, varialbe can be very useful sometimes. To use them, just assign a value to a variable before you start to write your targets. After that, you can just use them with the dereference operator $(VAR).
Where to go from here
With the brief introduction to Makefiles, you can create some sophisticated mechanism for compiling your projects. However, this is a tip of iceberg. I don't expect anyone to fully understand the example presented below without consulted some Make Documentation(which I had to myself) or read pages 347 to 354 of your Unix book.
CC = g++
CFLAGS = -c -Wall
LDFLAGS =
SOURCES = main.cpp hello.cpp factorial.cpp
OBJECT = $(SOURCES:.cpp = .o)
EXECUTABLE = hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE):$(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -O $@
.cpp.o:
$(CC) $(CFLAGS) $< -O $@
If you understand the last example, you could adapt it to your own personal projects changing only 2 lines,
no matter how many additional files you hava!!!