#Makefile的编译规则
(1)在Makefile 中#的相当于注释,转意字符是\,\可以用来换行,Makefile对缩进有要求
(2)Makefile中的完整语句的格式(简写隐式转换)
targets : prerequisites
command
argets:规则的目标,可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签;
prerequisites:是我们的依赖文件,要生成 targets 需要的文件或者是目标。可以是多个,也可以是没有;
command:make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。
简单举个例子:
#Makefile的简写命令
test:test.c
gcc -o test test.c
#作用生成一个可执行test文件,依赖于test.c,规则是gcc -o test test.c
总的来说就是:1.生成目标 2.依赖文件 3.编译规则
(3)Makefile的完整语句的格式(完整)
main:main.o test1.o test2.o
gcc main.o test1.o test2.o -o main
main.o:main.c test.h
gcc -c main.c -o main.o
test1.o:test1.c test.h
gcc -c test1.c -o test1.o
test2.o:test2.c test.h
gcc -c test2.c -o test2.o
解释:
## 1
main是生成的目标
main的生成依赖于main.o test1.o test2.o
规则是:gcc main.o test1.o test2.o -o main
## 2
main.o 是生成目标
main.o的生成依赖于main.c test.h
规则是:gcc -c main.c test.h
## 3
test1.o是生成目标
test1.o的生成依赖于test1.c test.h
规则是:gcc -c test1.c test.h
## 4
test2.o是生成目标
test2.o的生成依赖于test2.c test.h
规则是:gcc -c test1.c test.h
注意:Makefile有严格依赖关系,生成的文件必定是依赖于另外一个文件,依赖的文件生成来自于之后。
相当于先写结果,然后写过程
注意:-o后面的是编译后生成的文件名
(4)清除工作目录中的过程文件(位指令的定义和使用规则.PHONY:伪指令)
.PHONY:clean #这一句加不加都无所谓(前提是当前目录没有名为clean的文件)
clean:
rm -rf *o
rm -rf test
注意:实际上是没有clean这个指令的,这是弄的伪指令
使用make的时候这句不会执行(前提是没有其他的目标文件或者其他的目标文件依赖于clean)
使用make clean 才会执行我清除指令
我们可以仿照上面定义更多的位指令也没问题,执行伪指令的方式是make 位指令
就会根据相应的规则执行相关命令。
-rf的作用就是不管能不能执行,接着往下走不报错,执行完这条位指令
(5)通配符(* [] ?)
[]的用法:
gcc -c test1.c test2.c test3.c -o test1.o test2.o test3.o
实际可以写做:gcc -c test[1-3].c -o test[1-3].o
*的用法(%的用法和*差不多的):
gcc test1.c test2.c test3.c -o test
实际可以写做:gcc *.c -o test
?的用法:
gcc test1.c test2.c test3.c -o test
实际上可以写做:gcc test?.c -o test
拓展:
wildcarb:展开通配符,不能用来展开还不存在的东西,不同于依赖
$^:在当前整个一段有效语句中对应的依赖文件
$@:在当前整个一段有效语句中对应的目标文件
实例:
** 1 假设当前目录中只存在test.c 文件和Makefile文件
obj=$(wildcard *.o)
test:$(obj)
gcc $^ -o $@
test:test.o
gcc -c $^ -o $@
上面会直接报错,为什么,因为会先执行wildcard *.o但是此时文件.o是不存在的。
假如这样就可以:
obj=$(wildcard *.c)
test:$(obj)
gcc $^ -o $@
这样就不会报错,因为.c是存在的;这里我用了一下隐式规则(gcc -o 和gcc -c -o)。
看到这里应该发现了规律:
$^和$@到底是指什么?
好吧上面挨着的例子实际上等于:
obj=(wildcard *.c)
test:$(obj)
gcc $(obj) -o test
$@:一条完整语句中的的目标文件
$^: 一条完整语句中的依赖文件
(6)变量的定义和使用(赋值,引用)
前面其实已经创建了变量
再写个例子:
obj=$(test.c)
test:$(obj)
gcc test.c -o test
实际上等于:
test:test.c
gcc test.c -o test
变量的基本赋值:
简单赋值(:=),需要和$()一起用才能明显看出效果,什么是简单赋值,
从什么时候开始引用,就从什么时候替换,替换变量即使在将来改变,
也不会改变已经被替换了的变量改变.
举个例子:
x:=tes
y:=$(x)t
x:=new
test:
@echo "y=$(y)"
@echo "x=$(x)"
输入:
make test
打印结果:
y=test
x=new
总结:简单理解为不是赋值变量,是赋值变量所代表的东西
递归赋值(=),需要$()才能明显看出效果,不截断,持续替代
举个例子:
x=tes
y:=$(x)t
x:=new
test:
@echo "y=$(y)"
@echo "x=$(x)"
输入:
make test
打印结果:
y=newt
x=new
总结:简单理解就是赋值变量,而不是赋值变量所代表的东西
条件赋值(?=),在前面是否已经赋值,如果已经赋值,那么?=就不赋值了,否则将会赋值
举个例子:
x=test
x?=new
y?=no
test:
@echo "x=$(x)"
@echo "y=$(y)"
输入:
make test
打印结果:
x=test
y=no
总结:前面赋值了,后面就不赋值了,如果前面没赋值,就从这里开始赋值
追加赋值(+=),就是当前的加上要追加的内容赋值给当前的变量
举个例子:
x=test
y:=$(x)
x+=$(y)
test:
@echo "x=$(x)"
输入:
make test
打印结果:
x=test test
总结:就相当于加法其他语言的+=运算规则
(7)
$@ 表示规则的目标文件名。如果目标是一个文档文件(Linux 中,一般成 .a 文件为文档文件,
也成为静态的库文件),那么它代表这个文档的文件名。在多目标模式规则中,
它代表的是触发规则被执行的文件名。
$% 当目标文件是一个静态库文件时,代表静态库的一个成员名。
$< 规则的第一个依赖的文件名。如果是一个目标文件使用隐含的规则来重建,
则它代表由隐含规则加入的第一个依赖文件。
$? 所有比目标文件更新的依赖文件列表,空格分隔。如果目标文件时静态库文件,代表的是库文件(.o 文件)。
$^ 代表的是所有依赖文件列表,使用空格分隔。如果目标是静态库文件,
它所代表的只能是所有的库成员(.o 文 件)名。
一个文件可重复的出现在目标的依赖中,变量“$
Makefile基础知识点及其简单运用
于 2022-02-19 16:15:24 首次发布