Makefile from entry to entry

The makefile file is used to help compile and manage the C++ project code and needs to be used with the make command. Shell operations can also be performed in the makefile, with some functions of the .sh script.

makefile format

The content of the makefile is written according to the following rules

目标1:依赖1
  命令1

目标2:依赖2
  命令2

目标3:依赖3
  命令3
.........................
目标N:依赖N
            命令N

The command can be any shell statement. In most cases, commands are used to generate targets from dependencies. For example, if a .o file is generated from a .cpp file, the command must include a complete compilation command of g++ and some compilation parameters.
Target 1 2 3 can be a nested dependency. If dependency 1 contains target 2 and target 3, it is a nested dependency. It can also be independent. For example, the target 1 2 3 is three independent executable files, or three dynamic libraries, then they can have no dependencies at all, and they can be written in a makefile to facilitate unified management.
Start with a tab before the command. If you use spaces instead of tab, it will report when you execute the make command

[root@localhost makefiletest]# make
makefile:5: *** missing separator (did you mean TAB instead of 8 spaces?).  Stop.

for example

The following simple C++ code is taken as an example to illustrate the specific use of makefile.

Source code file test.cpp

#include <string>
#include <iostream>
#include<iomanip>

int main(int argc, char** argv)
{
using namespace std;
int i =1 ;
int j = 2;
        j += 3;
cout << j<<endl;
}

Makefile file, the file is makefile

CC=g++
all = test.o

test: $(all)
$(CC) -o test $(all)

test.o: ./test.cpp
$(CC) -c test.cpp

clear:
        rm -f *.o test

Execute the make command

[root@localhost makefiletest]# make
g++ -c test.cpp
g++ -o test test.o
[root@localhost makefiletest]# ls -lrt
total 24
-rw-r--r--. 1 root root  196 Aug  6 11:00 test.cpp
-rw-r--r--. 1 root root  120 Aug  6 11:04 makefile
-rw-r--r--. 1 root root 2328 Aug  6 11:04 test.o
-rwxr-xr-x. 1 root root 8840 Aug  6 11:04 test

Test and test.o are generated correctly

Example explanation

The "target 1" test in the makefile is an executable file, and it is what we ultimately need. test depends on (all)这个变量,文件开头定义了all = test.o,所以test依赖的是test.o,生成test的命令是(CC) -o test $(all), after variable substitution is g++ -o test test.o, which is the most basic compilation command we know.
Similarly, "target 2" test.o depends on test.cpp, and the command to generate the target is g++ -c test.cpp.
The above two rules complete the compilation from source code to executable file.

Makefile must be used for large projects

其实我们直接执行g++ -o test test.cpp就可以生成test了,但这种直接敲命令只适用于代码文件很少的情况。
即使项目只有5个文件,每次代码更新都要敲5个编译命令也是很麻烦的。我们只要编写一次makefile,之后每次代码更新,或者代码文件有增减,都只需要修改makefile对应的一小部分内容,然后执行make就行了。 例如test依赖是100个.o文件,在上面的makefile中我们只要写一次all = test.o test1.o test2.o ..... test99.o,就把目标test的生成规则表达清楚了。当然下面要写上100个.o文件的生成规则。

上面说的是按最原始的写法,实际makefile的编写有很多技巧使得编写量大大减少,

  • 编译命令的各种参数选项统一都写在变量中
  • 模式匹配
  • 特殊符号代码依赖集
  • 目标集
  • shell指令在makefile里完成自动查找生成所有文件名,然后替换.cpp为.o的玩法

这些都可以大大减少makefile的篇幅。如果打开一个开源C++项目的makefile,会觉得完全看不懂,就是因为里面大量使用各种技巧。但即使我们用最原始办法也就是第一次编写麻烦一些,之后维护是很简单的,因为一个C++项目不会频繁的大变样。

makefile文件名

make默认支持makefile和Makefile两种文件名,所以我们直接执行make等价于执行make Makefile。如果我们写make规则的文件叫test20200806,需要执行的命令是make -f test20200806。

并行编译

并行make的命令是make -j。可以加快工程编译速度,对于大规模工程适用。

自动推导

make会自动推导各个目标的依赖关系,按照依赖关系的顺序生成目标文件。

伪目标

本文makefile里的“目标3”clear是个伪目标,伪目标后面无文件依赖,make不自动找文件依赖,无法执行后面的命令。要执行伪目标,就要make+为目标名。执行make clear,会执行下面的rm命令,这种命令用来清理项目之前编译的.o等文件,在需要彻底重新编译项目时都会执行这个命令。

[root@bogon makefiletest]# make clear
rm -f *.o test

如果不执行make clear清理之前的.o文件,make会比较.o和.cpp谁更新,如果依赖文件cpp更新,重新编译这个.o,否则不重新编译。


Guess you like

Origin blog.51cto.com/14947900/2540196