1、什么是makefile
当我们在写单个c或者cpp文件时,可直接用以下命令来编译文件
# 编译c文件
gcc main.c -o main
# 编译c++文件
g++ main.cpp -o main
但是当我们项目中有很多文件的时候,就不能用这种命令来编译了,首先成本太高,其次维护麻烦;所以大神们开发出了 makefile;可以同时编译多个文件;并且会自动检测出哪些文件是修改过的,只编译修改过的文件,
只编译修改过的文件原理
刚刚说过,makefile只会编译那些已经修改过的文件,如果未修改就不会再次编译,提升了效率,那他是什么原理呢,其实很简单,就是每次执行make的时候都会去检测c/cpp文件的修改时间;如果发现修改时间有变动,就会去重新编译;是不是很简单呢
编写规则
target ... : prerequisites ...
command
...
...
2、实战
首先准备三个文件 student.h、student.cpp 和主程序 main.cpp
student.h
#ifndef NAKEFILE_PROJECT_STUDEN_H
#define NAKEFILE_PROJECT_STUDEN_H
int getAge();
#endif //NAKEFILE_PROJECT_STUDEN_H
student.cpp
#include "student.h"
int getAge(){
return 1;
}
main.cpp
#include <iostream>
#include "student.h"
int main() {
std::cout << "Hello, World!" << std::endl;
std::cout << "getAge:"<<getAge() << std::endl;
return 0;
}
编写makefile
注意:下面的缩进,必须用tab键,不能用4个空格键代替,否则会报错
而且,makefile的前后的顺序没有要求,在编译的时候会自动推导;
main : main.o student.o
g++ -o main main.o student.o
main.o:main.cpp
g++ -c main.cpp
studen.o: student.cpp student.h
g++ -c student.cpp student.h
clean :
rm main main.o student.o
目录结构
执行makefile
进入项目目录,执行名命令make
,完美,没有报错;
执行完后,会发现目录下多了三个文件,分别是main、main.o、student.o
到这一步,程序就已经编译好了,也生成执行文件了;
运行
运行makefile有一个前提,就是必须得在当前目录下有makefile文件;否则是无法运行的;
接下来在执行main文件,在控制台输入 ./main
后,发现是可以正常运行的;打印结果也和预期一样
修改后再编译
接下来我们将文件修改一下,在执行make命令,在main.cpp文件中,的hello world!
后面加上yexindong
,如下:
#include <iostream>
#include "student.h"
int main() {
std::cout << "Hello, World! yeindong" << std::endl;
std::cout << "getAge:"<<getAge() << std::endl;
return 0;
}
执行make
命令,发现只编译了main.cpp文件,其他文件的编译动作并没有执行;
3、变量
使用 Makefile 进行规则定义的时候,为了写起来更加灵活,我们可以在里边使用变量。makefile 中的变量分为三种:
- 自定义变量:用户自己定义的变量;
- 预定义变量:在 Makefile 中有一些已经定义的变量,用户可以直接使用这些变量
- 自动变量:Makefile 中的规则语句中经常会出现目标文件和依赖文件,自动变量用来代表这些规则中的目标文件和依赖文件,并且它们只能在规则的命令中使用。比如
$*
、$+
变量使用方法
$(变量名)
3.1、自定义变量
makefile中变量的赋值有以下几种方式
- 简单赋值(:=)
- 递归赋值(=)
- 条件赋值(?=)
- 追加赋值(+=)
接下来我们用自定义变量来重新修改下上面的makefile文件
# 声明student_file变量,值为:student.cpp student.h
student_file:=student.cpp student.h
# 声明main_file变量,值为:main.cpp
main_file:=main.cpp
# 声明main_and_student_o_file变量,值为:main.o student.o
main_and_student_o_file:=main.o student.o
main : $(main_and_student_o_file)
g++ -o main $(main_and_student_o_file)
main.o:$(main_file)
g++ -c $(main_file)
studen.o: $(student_file)
g++ -c $(student_file)
clean :
rm main $(main_and_student_o_file)
3.2、预定义变量
在 Makefile 中有一些已经定义的变量,用户可以直接使用这些变量,不用进行定义。在进行编译的时候,某些条件下 Makefile 会使用这些预定义变量的值进行编译。这些预定义变量的名字一般都是大写的,经常采用的预定义变量如下表所示:
变 量 名 | 含 义 | 默 认 值 |
---|---|---|
AR | 生成静态库库文件的程序名称 | ar |
AS | 汇编编译器的名称 | as |
CC | C 语言编译器的名称 | cc |
CPP | C 语言预编译器的名称 | $(CC) -E |
CXX | C++ 语言编译器的名称 | g++ |
FC | FORTRAN 语言编译器的名称 | f77 |
RM | 删除文件程序的名称 | rm -f |
ARFLAGS | 生成静态库库文件程序的选项 | 无默认值 |
ASFLAGS | 汇编语言编译器的编译选项 | 无默认值 |
CFLAGS | C 语言编译器的编译选项 | 无默认值 |
CPPFLAGS | C 语言预编译的编译选项 | 无默认值 |
CXXFLAGS | C++ 语言编译器的编译选项 | 无默认值 |
FFLAGS | FORTRAN 语言编译器的编译选项 | 无默认 |
3.3、自动变量
Makefile 中的变量除了用户自定义变量和预定义变量外,还有一类自动变量。Makefile 中的规则语句中经常会出现目标文件和依赖文件,自动变量用来代表这些规则中的目标文件和依赖文件,并且它们只能在规则的命令中使用。
变 量 | 含 义 |
---|---|
$* | 表示目标文件的名称,不包含目标文件的扩展名 |
$+ | 表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能 包含重复的依赖文件 |
$< | 表示依赖项中第一个依赖文件的名称 |
$? | 依赖项中,所有比目标文件时间戳晚的依赖文件,依赖文件之间以空格分开 |
$@ | 表示目标文件的名称,包含文件扩展名 |
$^ | 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开 |