1.Make Tool

Make tool is useful to generate executables (usually referred as make a file) by considering all dependencies and rules. It takes care of building executables or object files whose dependencies are modified; this will reduce the effort of building all project and decrease build time.

Make tool uses a file called make file, which contains all the rules, dependencies to build executable (or project). If the project contains thousands of source files, compiling every time entire project is a tedious job. Instead, define all relationship between various files in your project in make file, It automatically determines which part of the project needs recompile, and runs command according to that.

Default make file name is make file, however user is allowed to define own file name.

To Write a make file, one has to understand different components of a makefile. They are listed in later sections. Let us start looking at simple make file to build hello executable using hello.cpp file.

Lets explore this command bit more. Here hello.cpp is a source file, hello is a target. The entire command to build hello from hello.cpp is known as command.hello.cpp is known as dependency to build hello executable.

putting all these i.e source, target, command and dependencies together into a file becomes Makefile.

Pre requisites are those files which are required to build a target. For example all c , c++ and header files are considered as a pre-requisites to build object files and object files are considered as pre-requisites to build executable. The specified command is executed to build the target using prerequisites specified.

Once the target is build, running make command again will have no effect unless any pre-requisites are modified. If no file is modified then make do not build the target. Make does this job for you automatically by tracking time stamp of target and its dependencies.

Make file may consists of multiple targets. One target may depend on another target also. If a target is specified with multiple target as dependencies, then all dependent targets are executed first in order and then final target. First target in the make file is called default target.

Every make file usually consist (Recommended) of at least three targets listed below.

all: List all targets here separated by space, so that entire project can be build by executing "make all" command. Notice here that make can accept target name as argument, if you want to build a specific target, then pass the target name to make command.

make <targetname>

install: This target should contain all steps to install the resulted executable and other files if any.

make install

clean: This target should contain cleaning steps , which can be invoked to clean the entire project so that it can be rebuild from scratch.

make clean

Let us see the hello example with all, install and clean targets.

all: hello

hello: hello.cpp

g++ hello.cpp –o hello

install:

cp hello /usr/bin

clean:

rm –rf *.o hello

Lets run make using above makefile.

# make clean

rm -rf *.o hello

# make

g++ hello.cpp -o hello

# make hello

make: `hello' is up to date.

# make install

cp hello /usr/bin

Similarly you can write uninstall target which will uninstall the files. Observer the 3rd command, since hello is already built using 'make ' , make did not build it again.

make command on above file is equal to 'make all', since all is the first target in the file.

Dependencies are pre requisites of target. This can be of various types.

Executable depends on objects, objects in turn depends on source and header file. For example consider the below programs.

#

# hello.cpp

#

#include <iostream>

#include "print.h"

using namespace std;

main()

{

print_message(10);

}

#

# print.h

#

void print_message(int i);

#

# print.cpp

#

#include <iostream>

using namespace std;

void print_message(int i)

{

cout << "your entered: " << i << endl;

}

To build hello executable, it depends on print.o and hello.o object files. Each object file depends on its source file. This pre requisite dependency is shown in the below make file.

#

# Makefile to build hello

#

hello: hello.o print.o

$(CXX) hello.o print.o -o hello

hello.o: hello.cpp print.h

$(CXX) -c hello.cpp -o hello.o

print.o: print.cpp print.h

$(CXX) -c print.cpp -o print.o

In a ideal case, in a project there may be thousands of source and header file, change in one file may require to build entire project. But Thanks to Make, who will take care of building only modified file (usually object files) and generates a executable.

This is illustrated in the below example:

# make

g++ -c hello.cpp -o hello.o

g++ -c print.cpp -o print.o

g++ hello.o print.o -o hello

# make

make: `hello' is up to date.

# touch print.cpp

# make

g++ -c print.cpp -o print.o

g++ hello.o print.o -o hello

# make

make: `hello' is up to date.

·First make, it build hello.o, print.o and then hello executable.

·Second make, it does nothing, since there is no change in all dependent source files.

·We modified one of the dependent which is print.cpp using touch command. Notice here that touch changes the time stamp, but not the content. It indirectly indicates make, that this file is modified. (content is ignored by make)

·Third make, it identified changes in time stamp, so it only compiled print and generated executable hello. So assume if a project has thousands of files, then imagine the time you have saved using make files if only one file is modified.

6.Rules Types

Make file rules are of two types, are described as below with example.

Explicit rule

Explicit rule says , when and how to remake the one or more files, where in which each file has specified as separate target , pre requisites and command.

For example: consider the previous example hello.cpp, print.cpp. To build hello executable, hello.o and print.o needs to be build first and then hello executable.

OBJS = hello.o print.o

hello: $(OBJS)

$(CXX) $(OBJS) -o hello

hello.o: hello.cpp print.h

$(CXX) -c hello.cpp -o hello.o

print.o: print.cpp print.h

$(CXX) -c print.cpp -o print.o

BY observing the above make file, building command for hello.o and print.o is same except file name. Assume if you have thousands of files in your project, It is very time consuming, complicate to write make file with such explicit rule. The solution for this is use Implicit rule.

Implicit rule

Implicit rule says, when and how to remake a set of similar type files, where all targets can be build using a single rule.

Let us rewrite the above example using implicit rule, and make file is shown below.

OBJS = hello.o print.o

hello: $(OBJS)

$(CXX) $? -o $@

.cpp.o: print.h

$(CXX) -c $<

The last target ".cpp.o" indicates a implicit rule which builds all .o files for .cpp files mentioned as a dependency in hello target. New files can be added to project , include new file object name in OBJS variable,, that's it. No need to add any rule to build newly added files.

8.Directives

Directives in make file are similar to directives in C. directives allows user to add conditional statements in make file, overwriting a variable and including make file with in a make file.

ifeq/endif: ifeq directive allows to execute statements in a make file based on some condition. For example, if the build machine is 32 bit then add "-m32" option during compilation.

So that the same file can be used to make 64 bit or 32bit executable based on the machine architecture.

ifeq ($(ARCH),32)

FLAGS=-m32

endif

hello: hello.cpp

g++ $(FLAGS) hello.cpp -o hello

NOTE: The variable ARCH can be set at command line using "-e" option. Refer variables section of this article for more details.

Similarly ifneq/endif can be used.

ifneq ($(ARCH),64)

FLAGS=-m32

endif

hello: hello.cpp

g++ $(FLAGS) hello.cpp -o hello

Ifeq/else conditions can be used as shown below.

ifeq ($(ARCH),32)

FLAGS=-m32

else

FLAGS=

endif

hello: hello.cpp

g++ $(FLAGS) hello.cpp -o hello

include: include directive is used to include other make files in current make file.This is useful when all variables and configuration is stored in some external make file and rules are stores in another make file.

Variables.mk file is included in make file, so that all variables from variables.mk file are imported into make file. In this example, new .cpp files can be added into variables.mk file, and no modification required to make file to build the executable, because there is no change required in rule.

Multiple files can be included as shown below.

include *.mk foo bar

override: override directive is used to force the value of a variable to a new value even it is set explicitly at command line.

Let us look at the make file.

Override TARGET = hello

If the make file is executed using below command, there there wont be any change in TARGET. Without override, target file will change to main instead of hello.

By default make stops execution as soon as a command is failed. There may be cases where you may want make to ignore return codes of few commands. For example

SRC = hello.cpp

TARGET = hello

all: clean $(TARGET)

$(TARGET): $(SRC)

@$(CXX) $(SRC) -o $(TARGET)

clean:

rm –rf *.o hello

The target "all" depends on target "clean" and target "hello", but the above make file stops execution while executing clean target, as in very first execution the command may fail( assuming hello file is not exist). But this is not so important so the return code of this command can be ignored. To ignore return code of a command execution, command should be predeced by "-" as shown below.