本文旨在从零开始学习Makefile的编写,先了解make命令,后面再详细介绍Makefile文件的编写规则,日常不需要太复杂的makefile文件编写,所以本文的例子比较简陋~。
引入Makefile文件是因为工程项目中有很多文件,并且它们相互依赖,一个一个编译会很花时间,而且如果有某个文件修改过需要重新编译,那么所有相关的文件都要重新编译,这就很操蛋。Makefile文件是去判断哪个文件被修改了,然后会重新生成修改后的文件,而且只需要一个make命令,极大地简化了编译过程。
一、make及其用法
Makefile文件是一类工程管理工具的工程描述文件的默认名称,名称不一定是Makefile,也可以是makefile或GNUmakefile。
make命令会在执行路径中搜索Makefile文件,如果同时存在以上三个文件,执行顺序是GNUmakefile > makefile > Makefile,如果选择执行一个,其他的就不会再执行了。
如果想执行某个文件,只需要make -f 文件名就可以指定执行文件,-f也可以用--file=FILE 或 --makefile=FILE功能相同。
另一个常用命令选项是-d,用于调试Makefile文件,不过不是单步调试,而是在屏幕上输出Makefile文件的执行过程,另一种命令选项是--debug[=FLAGS]。
make命令详细参数通过make -h 或者 make --help来获取。
二、Makefile文件编写规则
首先给出测试代码,测试代码由两个cpp文件组成,a.cpp和b.cpp,b.cpp里面是一个加法函数add,a.cpp的主函数直接调用add函数。
a.cpp
#include<stdio.h>
#include"b.cpp"
int main()
{
int a = 1;
int b = 2;
printf("%d\n",add(a,b));
return 0;
}
b.cpp
#include<stdio.h>
int add(int a, int b)
{
return a + b;
}
Makefile的基本语法:
目标1 目标2 目标3 ... : 条件1 条件2 条件3 ...
[tab]命令1
[tab]命令2
[tab]命令3
Makefile基础版本
all:test #最后的可执行程序test,无论书写顺序是怎样,最后是生成test
test:a.o #test是结果,a.o是来源
#命令必须开头是tab键 -o后面生成目标
g++ -o test a.o
a.o:a.cpp #a.o是结果,a.cpp是来源
#-c表示只编译不链接,生成.o文件
g++ -c a.cpp -o a.o
输入make命令
[wanghe@localhost testmake]$ make
g++ -c a.cpp -o a.o #-c表示只编译不链接,生成.o文件
g++ -o test a.o #命令必须开头是tab键 -o后面生成目标
[wanghe@localhost testmake]$ ls
a.cpp a.o b.cpp Makefile test
Makefile进阶版本
问题引入,如果某个文件被多次引用,但是现在需要修改文件名,那么一个一个修改就会很麻烦,所以Makefile文件中允许定义变量,然后后面只需要修改变量的值就可以了,原理就是Makefile文件会展开变量,类似于宏定义。
变量定义规则 变量名 = 命令,使用变量是通过$(变量名)或者$(变量名)
Bin = test #定义变量名Bin
all:$(Bin) #生成可执行程序test
test:a.o
g++ -o $(Bin) a.o
a.o:a.cpp
g++ -c a.cpp -o a.o
clean: #clean需要使用命令make clean才会执行
rm -f *.o $(Bin) #删除生成的.o文件和可执行文件
如果要修改文件名,只需要修改test就行了,这样就很方便。
一般如果再次make可能会提示make无需做任何事,但是需要重新生成的话需要把原来的.o和可执行程序删除,所以定义一个clean,俗称假目标。
Makefile终极版
如果有很多个.o文件需要引用,每次写就会感到很烦,Makefile提出了自动变量的概念,需要注意的事自动变量只能用在命令里面!
下面给出常用的六个自动变量:
变量名 | 作用 |
$@ | 目标的文件名 |
$< | 第一个条件的文件名 |
$? | 时间戳在目标之后的所有条件, 并以空格隔开这些条件 |
$^ | 所有条件的文件名, 并以空格隔开, 且排除了重复的条件 |
$+ | 与$^类似, 只是没有排除重复的条件 |
$* | 目标的主文件名, 不包含扩展名 |
Bin = test
all:$(Bin)
test:a.o
g++ -o $(Bin) $< #$< 表示第一个条件名,也就是a.o
a.o:a.cpp
g++ -c $< -o $@ #$<表示a.cpp , $@表示目标文件名,也就是a.o
clean:
rm -f *.o $(Bin)
熟练掌握以上写法,基本上普通的Makefile文件就没有问题了。