When writing C++, when studying program construction, Python programmers have already gone home to hug his wife :)
Article Directory
What is Makefile?
In simple terms, Makefile
it is a file that contains some compiled and linked rules ( rule
), when we use the make
command, make
the program will interpret these rules and execute them. A bit similar to a script, but it is mainly used to build projects (compile, link) to generate targets.
Why do I need Makefile?
The law of peace in the world
I must admit that in modern software development, integrated development environment ( IDE
) may be substituted make
; but make
in Uniux系统
a still relatively high position.
Second, while IDE
helping us to achieve the compiler and linker. But simply it means losing control over the details . To achieve control over details, you must face complexity.
It is important to find a balance between the two.
In most cases, we do not need to be compiled and linked detail control, IDE
provides a default compile and link the program, to help us write the Makefile
liberation process, which is IDE
one of value.
For make
, considering its background, it helps us get rid of repeated compilation and linking instructions, and can control the details, which is the meaning of its existence.
So we now need to learn to write Makefile
it?
-
Not
IDE
in the case,Makefile
is still a good choice -
Need to read the source code (it exists in some well-known open source projects
Makefile
, if you want to study them, you can’t get aroundMakefile
)
Make tool
Makefile
We need make
to parse executed. There are many options in this regard:
Linux下的 GNU make
Visual C++ 的 nmake
...
Different manufacturers make
vary, grammar are not the same; but essentially make a fuss about file dependencies. This article chooses yes GNU make3.8.1
.
In addition, since its Makefile
appearance, many tools have been developed to help us generate Makefile
, for example:
Qt 的 qmake
支持跨平台的 CMake
Linux下的 Autoconf+Automake
GNUmake
Program compilation
In the absence Makefile
before, we generate an executable file, you can execute the following command:
//编译
g++ -c main.cpp -o main.o
g++ -c foo.cpp -o foo.o
//链接
g++ main.o foo.o -o app
These steps need to be performed every time the program is modified (this is still the simplest case, what if there are 10 files constituting our project?), and it is a repetitive mechanical movement.
As lazy behalf , thinking liberated from mechanical motion how can you call it laziness?
script
The first thing that comes to mind is: write a script and make it an "action".
For example, write one build.sh
and execute the script every time you need to build.
But this method introduces a problem, which is more obvious in large projects:
if you only modify a file and then execute the script, many files that do not need to be compiled again will be regenerated. If the file is very large ... like Ubuntu
the kind of level, the compilation time is very long. But in fact, we only need to compile the changed files and relink them.
Derived from make
To solve this problem, at the same time and a better readability shell
, bash
and so the script can not meet. So people defined it make
, it reads in Makefile
(makefile, MAKEFILE can also be), Makefile
contains source file dependencies and compilation rules; and then generates the target program through these rules.
As long as we are Makefile
well written, we only need one make指令
, you can automatically and intelligently in accordance with the revision of the current file to determine which files need to be recompiled in order to automatically compile the necessary documents and link object files.
# 依赖关系
app: foo.o main.o
# 规则(注意:前面是一个Tab,不要打空格)
g++ main.o foo.o -o app
foo.o: foo.cpp
g++ -c foo.cpp -o foo.o
main.o: main.cpp
g++ -c main.cpp -o main.o
Makefile
The dependencies in constitute a dependency tree:
How does make work?
Note: Makefiles are not executed sequentially!
When we execute make
the instruction:
-
make
Will find firstMakefile
-
If you find the default will be the first target file as a final target file (for example
app
) -
If the target file does not exist, or behind depends file modification time newer than the target file is re-executed later defined rules to generate an object file
-
If the dependent file already exists, it
make
will look for the dependencies of the dependent file (for examplefoo.o
). And generated according to the above rules. Will eventually find the dependency tree叶子节点
In the above process, if an error occurs, it make
will be said:I quit! And throw the error to you.
PHONY dependence
According to the above workflow, whether the rule is executed depends on whether the target exists, whether the dependency is updated, etc.
But sometimes, we look forward to certain rules unconditional implementation .
Then you can define a dependency that will never be satisfied:
clean:
rm main.o
rm foo.o
clean文件
It will never be produced, the rules must be enforced. Although this form of viable rules, but make
will be clean
compared to a file, when it became part of the dependency tree, it can easily lead to misunderstanding and error handling.
So Makefile
allow us to rely target definition display is false ( Phony
), so do not embarrass make
the.
.PHONY: clean
app: foo.o main.o
g++ main.o foo.o -o app
foo.o: foo.cpp
g++ -c foo.cpp -o foo.o
main.o: main.cpp
g++ -c main.cpp -o main.o
clean:
rm main.o
rm foo.o
Macro
We can find Makefile
there are many duplicate content, duplicate content of these can 宏
be replaced
.PHONY: clean
CC = g++ -c
LD = g++
app: foo.o main.o
$(LD) main.o foo.o -o app
foo.o: foo.cpp
$(CC) foo.cpp -o foo.o
main.o: main.cpp
$(CC) -c main.cpp -o main.o
clean:
rm main.o
rm foo.o
There is still a lot of repetition. For example, we wrote it in the dependency foo.o
and wrote it again in the rule.
GNUmake
It allows us to use $@
alternative dependent objects , using the $^
alternative was dependent objects .
So it can be rewritten as:
.PHONY: clean
CC = g++ -c
LD = g++
app: foo.o main.o
$(LD) $^ -o $@
foo.o: foo.cpp
$(CC) $^ -o $@
main.o: main.cpp
$(CC) -c $^ -o $@
clean:
rm main.o
rm foo.o
Wildcard
Obviously, there are still a lot of repetitions. We will change the repetitive part to 通配符
:
.PHONY: clean
CC = g++ -c
LD = g++
app: foo.o main.o
$(LD) $^ -o $@
%.o: %.cpp
$(CC) $^ -o $@
clean:
rm main.o
rm foo.o
Wildcard %
means:
-
For example, we need to
foo.o
construct rules, justMakefile
look for, and then found%.o: %.cpp
-
foo.o
Set into%.o
, so%
thatfoo
the back of%.cpp
thatfoo.cpp
-
OK, construct
Implicit rule
There are more concise approach, namely the use of GNUmake
implicit rules:
SRC = $(wildcard *.cpp)
OBJ = $(SRC:.cpp=.o)
app: $(OBJ)
g++ $^ -o $@
Not defined here foo
, main
dependent, but gnumake
by default, if .cpp
present, .o
to the corresponding dependent .cpp
, and .o
to .cpp
the rule
, by macros defined by default. We can modify CC
, LDLIBS
this type of macro to change the default rule.
So far, preliminary spy Makefile
or two.
Reference thanks
Getting started with Makefile concepts
Cheng Hao "Write Makefile with Me"
Xu Haibing translated "GNU make Chinese Manual"
The difference between the% mark in Makefile and the system wildcard *