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
The build process contains two steps;
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.
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
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.
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.