一、入门级

入门级其实就和直接用命令在终端下编译基本上没有任何区别。只是把在终端中键入的命令全部放入到Makefile文件中。

  • 举例:
//hello.cpp
#include<iostream>
using namespace std;
int main()
{
cout<<"Hello world!"<<endl;
return 0;
}

1.打开终端,进入当前test目录。新建一个名为Makefile的文件,注意其中M要大小。

2.输入以下命令然后保存退出:

TARGET:hello.o
g++ -o Hello hello.o
hello.o:hello.cpp
g++ -c hello.cpp

打开终端,进入test目录,即Makefile所在的目录,运行make命令,最终会生成名为Hello的可执行文件。

其中:

TARGET:hello.o表示要生成的目标文件为hello.o,得到目标文件之后再用g++ -o Hello hello.o命令生成可执行文件。

hello.o:hello.cpp表示要想得到目标文件hello.o,得依赖于g++ -c hello.cpp生成。即整个执行过程是从下到上的。

二、进阶级

进阶级就是在入门级的基础之上运用递推实现。

先假设当前所在的目录为test,里面有两个文件test/min和test/max,一个源文件main.cpp。其中min中有源文件min.cpp和min.h;max中有源文件max.cpp和max.h。即以下五个源文件:

  • 举例:
//  test/max/max.h
#ifndef MAX_H
#define MAX_H
int Max(int a,int b);
#endif

// test/max/max.cpp
#include "max.h"
int Max(int a, int b)
{
return a > b ? a : b;
}

// test/min/min.h
#ifndef MIN_H
#define MIN_H
int Min(int a,int b);
#endif

// test/min/min.cpp
#include "min.h"
int Min(int a, int b)
{
return a > b ? b : a;
}

// test/main.cpp
#include"max/max.h"
#include"min/min.h"
#include<iostream>
using namespace std;
int main()
{
int a,b;
cin>>a>>b;
cout<<" max = "<<Max(a,b)<<
" min = "<<Min(a,b)<<endl;
return 0;
}

1.打开终端,进入当前test目录。新建一个名为Makefile的文件,注意其中M要大小。

2.输入以下命令然后保存退出:

TARGET:main.o max.o min.o
g++ -o Main main.o max.o min.o
main.o:main.cpp max/max.h min/min.h
g++ -c main.cpp
max.o:max/max.cpp
g++ -c max/max.cpp
min.o:min/min.cpp
g++ -c min/min.cpp

注意:每一编译命令也就是g++前面是一个tab的间隔,一定不要用8个空格来代替。

不然会有以下错误提示:Makefile:6: * missing separator。

打开终端,进入test目录,即Makefile所在的目录,运行make命令,最终会生成名为Main的可执行文件。其中的各种依赖关系同之前的道理。

这和之前的入门级的写法有区别? 当然没区别,唯一的区别就是多了几行,而且是重复的。试想一下,要是这个工程有上千个源文件,难道要依次写进去?当然不是。这儿只是想从侧面说明为什么要使用递推的方法来写Makefile。

  • 递推:
CXX = g++ 
OBJS = main.o max/max.o min/min.o
TARGET = Main
RM = rm -f
$(TARGET):$(OBJS)
$(CXX) -o $(TARGET) $(OBJS)
$(OBJS):%.o : %.cpp
$(CXX) -c $< -o $@
clean:
-$(RM) $(TARGET) $(OBJS)

依次大致解释一下:

CXX = g++ 表示把g++ 用变量CXX来表示,在后面如果再须要用到g++只需用 (CXX)CXX便OBJS=main.omax/max.omin/min.oOBJSobjectsTARGET=Main(binary) (TARGET): (OBJS) ”这个符号的作用是引用变量,其中括号里面的就是变量名。表示Main 依赖于OBJS即所有的.o文件。

(CXX)o (TARGET) (OBJS)g++oMainmain.omax/max.omin/min.o (OBJS):%.o : %.cpp 表示把OBJS中,所有.o的目标文件,换成.cpp源文件

(CXX)c < -o @g++cmain.cppomain.o < 表示 .cpp文件, $@ 表示.o文件

到这儿,就已经能完成编译工程。后面的两行表示删除目标文件和可执行文件。命令为make clean,其中最后一行前面的 “-“作用是在没有要删除的文件时,执行这条命令不会报错,提示说没有该文件。