Makefile基础入门
第1章 Makefile快速入门
基础概念
make :项目构建工具——用于管理文件的更新 Makefile:规则文件,告诉make如何进行编译与管理 Makefile(取名makefile也行)其实就是一个脚本文件。
快速入门
- 创建文本文档——文件名Makefile
- #代表注释
- 显示规则:一条显示规则由以下构成
| 1 2 | 目标文件:依赖文件[Tab键]指令 | 
示例: 1)首先我们新建一个文件夹,在该文件夹内写一个hello.cpp文件 2)我们新建一个Makefile文件。 3)在Makefile内第1个文件通常是我们的目标文件。 4)显然,在下面的文件中我们写上了4条显示规则。Makefile默认情况下会把第一条显示规则当作最终目标,也就是说,如果完成了第一条显示规则,那么Makefile是有可能不执行后面的显示规则的。可以通过ALL命令来指示最终目标:ALL hello,这样就无需将最终目标放在文件开头了。
| 1 2 3 4 5 6 7 8 9 10 11 | hello:hello.o    g++ hello.o -o hellohello.o:hello.s    g++ -c hello.s -o hello.ohello.s:hello.i    g++ -S hello.i -o hello.shello.i:hello.cpp    g++ -E hello.cpp -o hello.i | 
- 伪目标 .PHONY:目标名(可以任意命名),使用伪目标指令就会执行目标后面的命令。
| 1 2 3 | .PHONY:clean:    rm  -rf hello.o hello.s hello.i | 
示例:执行clean命令
| 1 | make clean | 
变量的使用
变量=(替换) 变量+=(追加) 变量:=(常量) 使用变量——$(变量名)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | TARGET=helloOBJ=hello.o$(TARGET):$(OBJ)    g++ hello.o -o hellohello.o:hello.s    g++ -c hello.s -o hello.ohello.s:hello.i    g++ -S hello.i -o hello.shello.i:hello.cpp    g++ -E hello.cpp -o hello.i.PHONY:clean:    -rm  -rf hello.o hello.s hello.i(rm前面加-表示执行过程中出错了也要继续往下执行) | 
隐含规则
%.c文件表示任意的.c文件,%.o表示任意的.o文件。
通配符(自动变量 )
| 1 2 3 | $@ 表示所有的目标文件$^ 表示所有的依赖文件$< 所有的依赖文件的第一个文件 | 
第2章 Makefile详解
1个基本原则
- 若想生成目标,检查规则中的依赖条件是否存在,若不存在,则检查是否有规则用来生成该文件。
- 检查规则中的目标是否需要更新,必须先检查他的所有依赖,依赖中有任意一个被更新,则目标必须被更新(目标更新时间必须晚于依赖文件的更新时间,否则就会更新目标)。
2个函数
wildcard函数
| 1 2 3 | src=$(wildcard *.c)或者src=$(wildcard ./*.c) | 
src是Makefile文件的一个变量,Makefile只有一种变量类型字符串类型。 wildcard是一个函数,函数名意思是通配符。 以上函数语句的意思就是把当前目录下所有.c文件提取出来作为一个列表赋值给src。
patsubst函数
patsubst是patten substitude的缩写,匹配替代的意思。
| 1 | obj=$(patsubts %.c, %.o, $(src)) | 
将参数3中,包含参数1的部分,替换为参数2。 比如src = add.c sub.c div.c 则obj =add.o sub.o div.o
3个自动变量
@:在规则的命令中,表示规则中的目标@:在规则的命令中,表示规则中的目标^:在规则的命令行中,表示所有的依赖条件 $<:在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件中的依赖依次取出,套用模式规则。
注意:在一条规则中,$@只能用于命令行,而不能用于目标文件和依赖文件.看不懂这句话就先忽略
假设我们有Makefile文件内容如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | src=$(wildcard *.c) # add.c sub.c div.c main.cobj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.oALL:a.outa.out:$(obj)    gcc $(obj) -o a.outadd.o:add.c    gcc -c add.c -o add.osub.o:sub.c    gcc -c sub.c -o sub.odiv.o:div.c    gcc -c div.c -o div.omain.o:main.c    gcc -c main.c -o main.oclean:    -rm -rf $(obj) a.out | 
通过自动变量我们可以做出如下替换:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | src=$(wildcard *.c) # add.c sub.c div.c main.cobj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.oALL:a.out#在下面这条规则中,#目标文件是a.out,所以在命令行中$@的值就是a.out#依赖文件是$(obj)——值为add.o sub.o div.o main.o,所以在命令行中$^的值就是以上的4个文件a.out:$(obj)      gcc $^ -o $@#在下面的这条规则中,目标文件的值是add.o,依赖文件的值是add.c#所以$<的值就是add.c,$@的值就是add.o,这里由于只有一个依赖文件,所以$<与$^的取值是一样的,我们使用$<add.o:add.c    gcc -c $< -o $@sub.o:sub.c    gcc -c $< -o $@div.o:div.c    gcc -c $< -o $@main.o:main.c    gcc -c $< -o $@clean:    -rm -rf $(obj) a.out | 
现在,你知道$@为什么不能用于目标文件和依赖文件的值了吧。因为以上三个自动变量的值就取决于目标文件和依赖文件的值。
模式规则
现在,我们要求再添加进一个功能,我们要添加mul.c文件实现乘法功能。 那么,我们现在也就必须要修改我们的Makefile文件。 但是我们想要实现的最终目标是,添加进新的文件时,不用修改我们的Makefile文件,这就需要用到模式规则。 %.c文件表示任意的.c文件,%.o表示任意的.o文件。 所以,在Makefile文件中,下面的几条规则我们可以进行替换
| 1 2 3 4 5 6 7 8 | add.o:add.c    gcc -c $< -o $@sub.o:sub.c    gcc -c $< -o $@div.o:div.c    gcc -c $< -o $@main.o:main.c    gcc -c $< -o $@ | 
我们只用一条规则就可以替换上面的规则了
| 1 2 | %.o:%.c    gcc -c $< -o $@ | 
请你思考,在这里为什么不能使用*.c而是必须使用%.c?为什么不能使用*.o而是必须使用%.o?也就是说,通配符*与%的区别是什么? 这样,我们添加新的mul.c文件时,通过模式规则我们就不用修改Makefile文件了。
静态模式规则
$(obj):%.o:%.c 相当于在模式规则的前面加上了个前缀,指定了(obj)应该要套用的模式规则。假设有以下场景:下面有两条模式规则都能产生.o文件,(obj)应该要套用的模式规则。 假设有以下场景:下面有两条模式规则都能产生.o文件,(obj)应该要套用的模式规则。假设有以下场景:下面有两条模式规则都能产生.o文件,(obj)应该套用哪天模式规则呢?这里就产生了歧义。需要用到静态模式规则。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | src=$(wildcard *.c) # add.c sub.c div.c main.cobj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.oALL:a.outa.out:$(obj)    gcc $(obj) -o a.out%.o:%.c    gcc -c $< -o $@%.o:%.s    gcc -S $< -o $@clean:    -rm -rf $(obj) a.out | 
修改如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | src=$(wildcard *.c) # add.c sub.c div.c main.cobj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.oALL:a.outa.out:$(obj)    gcc $(obj) -o a.out$(obj):%.o:%.c    gcc -c $< -o $@%.o:%.s    gcc -S $< -o $@clean:    -rm -rf $(obj) a.out | 
from:https://blog.nowcoder.net/n/16b8c4e009454abda117661f9bfbc212
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号