来写Makefile吧

来写Makefile吧

一些小程序可能使用Makefile就足够了,比如只有几个源文件的C++程序,使用CMake可能有点杀鸡用牛刀,直接g++又会重复输入,所以写个Makefile比较省心

命名:makefile Makefile

Makefile书写规则

目标...:依赖...
	命令(shell命令)
	....
	....
	#目标是最终要生成的文件,依赖是生成目标所需的文件或目标,命令前必须Tab缩进
demo1:sub.c div.c add.c main.c mult.c
        gcc sub.c add.c div.c main.c mult.c -o demo1

来写Makefile吧

root@ziggy-virtual-machine:~/learn_Makefile# ./demo1 
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.666667

Makefile工作原理

一个Makefile文件中可以有多条规则

在执行规则之前,会先检查依赖项是否存在

如果依赖项不存在且前面的规则使用了依赖项,则会向下查找其他规则

demo1:sub.o div.o add.o main.o mult.o
	gcc sub.o add.o div.o main.o mult.o -o demo1
sub.o:sub.c
	gcc -c sub.c -o sub.o
add.o:add.c
	gcc -c add.c -o add.o
mult.o:mult.c
	gcc -c mult.c -o mult.o
main.o:main.c
	gcc -c main.c -o main.o
div.o:div.c
	gcc -c div.c -o div.o
root@ziggy-virtual-machine:~/learn_Makefile# make
gcc -c sub.c -o sub.o
gcc -c div.c -o div.o
gcc -c add.c -o add.o
gcc -c main.c -o main.o
gcc -c mult.c -o mult.o
gcc sub.o add.o div.o main.o mult.o -o demo1

我们的规则书写一般都是为第一条规则来服务(Makefile自身默认执行第一条规则,如果下面的规则和第一条没啥关系,则不会执行)

Makefile会检测依赖和目标文件的更新

检测目标文件和依赖的新旧程度,如果依赖比目标文件早,则make不会重新执行内容

root@ziggy-virtual-machine:~/learn_Makefile# make
make: 'demo1' is up to date.

这样,我们写的第二个版本的Makefile更好,因为如果单独修改了某几个依赖,它不会将所有的依赖都重新编译

更完善的Makefile

用自定义变量和预定义变量简化Makefile

一大堆规则,过于繁琐也不好修改

幸亏Makefile有自定义变量:
变量名:变量值

预定义变量

AR:默认值为ar 使用ar rc生成静态库文件
CC:默认cc
CXX:默认g++
$@:目标的完整名称
$<:第一个依赖文件的名字
$^:所有有依赖文件
app:main.c a.c b.c
	gcc -c main.c a.c b.c

上面的Makefile可以替换为:

app:main.c a.c b.c
	$(CC) -c $^ -o $@

在shell命令中的make选型也可以:make CC=arm-linux-gcc这样会将Makefile中所有CC变量的默认值cc替换为arm-linux-gcc

#自定义变量
src=sub.o div.o add.o main.o mult.o
target=demo2
$(target):$(src)
	$(CC) $(src) -o $(target)
sub.o:sub.c
	gcc -c sub.c -o sub.o
add.o:add.c
	gcc -c add.c -o add.o
mult.o:mult.c
	gcc -c mult.c -o mult.o
main.o:main.c
	gcc -c main.c -o main.o
div.o:div.c
	gcc -c div.c -o div.o

来写Makefile吧

使用通配符

%

src=sub.o div.o add.o main.o mult.o
target=demo3
$(target):$(src)
	$(CC) $(src) -o $(target)
%.o:%.c
	$(CC) -c $< -o $@

上面Makefile中,每个依赖文件都会去匹配第二条规则

来写Makefile吧

自动获取依赖文件列表

$(wildcard [file_pattern])
#[]中的是某个或多个目录下对应的某种类型的文件
#使用例子:
$(wildcard *.c /root/newc/*.c)
#返回值为:xx.c xxx.c x.c
#由于我们需要的是.o文件名,所以需要将.c文件名批量替换,使用:
$(patsubst %.c, %.o, $(src))
#格式:$(patsubst <file_pattern>, <replace>, <text>)

作用为查找text种的单词(以空格,Tab或回车分隔)如果匹配file_pattern的格式,则以replace格式替换

此函数返回被替换后的字符串,即为我们需要的依赖文件名列表

如果前两者都有%,则replace中的%将是pattern中%所代表的字符串

%可以用'\'转义,来表示真实的%

来写Makefile吧

src=$(wildcard *.c)
srco=$(patsubst %.c, %.o, $(src))
target=demo5
$(target):$(srco)
	$(CC) $(srco) -o $(target)
%.o:%.c
	$(CC) -c $< -o $@

来写Makefile吧

src=$(wildcard *.c)
srco=$(patsubst %.c, %.o, $(src))
target=demo5
$(target):$(srco)
	$(CC) $(srco) -o $(target)
%.o:%.c
	$(CC) -c $< -o $@
clean:
	rm $(srco) -f

来写Makefile吧

make clean

src=$(wildcard *.c)
srco=$(patsubst %.c, %.o, $(src))
target=demo5
$(target):$(srco)
	$(CC) $(srco) -o $(target)
%.o:%.c
	$(CC) -c $< -o $@
	#clean是没有依赖文件的,为了防止目录中有clean文件,所以我们使用伪目标

.PHONY:clean
clean:
	rm $(srco) -f

来写Makefile吧

上一篇:使用空镜像scratch构建镜像


下一篇:XCTF-攻防世界CTF平台-Reverse逆向类——56、tar-tar-binks