嵌入式面经:一分钟速成Makefile(持续更新版本)

Makefile

​ 假设我们现在需要做一道水煮鱼,它需要n多复杂布置。但是我们厨艺不精,我们能不能写个配料表,直接给一个经验丰富的老师傅,让他制作(make)?这个配料表就是Makefile文件了,给老师傅一键制作的过程就是一键make了。对应代码就是,我们需要分步骤对文件进行编译,我们现在写个脚本,只要运行就能一键编译所有过程。这就是Makefile。

1、简单规则

  • 在Makefile中,#代表着注释,这个是不会被编译进去的。

  • Makefile的基本语法是:

    目标文件:依赖文件...(可以是多个依赖文件)
    目标文件1:依赖文件...
    目标文件2:依赖文件...
    ...
    

    可以理解为需要做一道水煮鱼(目标文件),需要鱼、调理(依赖文件)

    水煮鱼:鱼 配料    //鱼已经有了,就需要其它“依赖文件”来制造他了,现在差调料
    配料:调料 油
    调料:辣椒 花椒 醋...
    ...             //直到层层配好所有东西,即可一键制作“make”
    
  • 越是接近目标文件的命令,就越是要写在前面。程序按照递归的方式进行依赖文件查找的

    现在了解了规则,可以开始进行写配料表了。

1.1 例子

Makefile例子:生成可执行文件全过程

hello:hello.o                   //最终目标:可执行文件hello,它依赖于hello.o
	gcc hello.o -o hello        //链接出可执行文件hello

hello.o:hello.S				    //hello.o,它又依赖于hello.S
	gcc -c hello.S -o hello.o	//汇编

hello.S:hello.i					//hello.S,它又依赖于hello.i
	gcc -S hello.i -o hello.S	//编译
	
hello.i:hello.c					//hello.i,它又依赖于hello.c
	gcc -E hello.c -o hello.i   //预处理

2、伪目标

​ 水煮鱼做好了,我们发现我们多做了很多不需要的“调料”,我们只需要水煮鱼,不需要其它调料占地方。我们就需要添加一键去除多余材料的功能了。

​ 假设当前文件夹中有hello.cMakefile两个文件,当我们在终端输入make指令的时候,就会自动编译出hello.o,hello.S,hello.i(多余调料)以及hello可执行文件。当我们不需要这些不相关的文件,想对这些文件做一些操作,我们把这样的操作叫做伪目标,标志位.PHONY: 。我们只需在上述代码的最后面加上即可:

.PHONY:
clear:
	rm hello.o hello.S hello.i

​ .PHONY:固定格式,不能变的,clear可以自己取比如“clear”,对应一键去除”多余调料“。当我们执行make clear指令后,将只剩下hello.c 和 hello可执行文件。

3、复杂例子简化

​ 现在我们需要做一道更复杂的菜,比如“佛跳墙”,这道菜的菜单(Makefikle脚本),如下:

# 目标文件:test
# 现有文件:program1.c program1.h program2.c program2.h main.c main.h

test:program1.o program2.o main.o
	gcc program1.o program2.o main.o -o test

program1.o:program1.c
	gcc -c program1.c -o program1.o

program2.o:program2.c
	gcc -c program2.c -o program2.o

main.o:main.c
	gcc -c main.c -o main.o

.PHONY:
clean_all:
	rm program1.o program2.o main.o

​ 我们发现配料太多了,菜单太长太复杂了,我们能不能用某些记号来代替它,比如定义个TAR代表“佛跳墙”,OBJ代表那些“配料”,那我们定义以下统一规则来简化菜单(Makefile文件)

变量

符号含义
=替换
+=追加
:=恒等于
  • 如果我们写TAR = test,就表示下面的代码中,我们可以用TAR代表test文件。
    如果再写TAR += test1,就表示TAR代表test和test1。
  • CC := gcc 就表示下面写gcc的地方全部可以用CC代替,因为gcc这个是不会变的,是常量,所以可以用恒等于替换,这个不能用+=。
  • 当我们要调用这些变量的时候,就直接使用$(变量)的方式进行调用。

上面代码可以简化如下:

TAR = test
OBJ = program1.o program2.o main.o
CC := gcc

$(TAR):$(OBJ)                  //使用$(变量)的方式进行调用
	$(CC) $(OBJ) -o $(TAR)

program1.o:program1.c
	$(CC) -c program1.c -o program1.o

program2.o:program2.c
	$(CC) -c program2.c -o program2.o

main.o:main.c
	$(CC) -c main.c -o mian.o

.PHONY:
clean_all:
	rm $(OBJ)

4、通配符

​ 现在我们发现“菜单”还是太长了,我们能不能进一步进行简化,我们现在又加上新的一套规则(我们称它为通配符),假设.c结尾的配料我们统一称为原料:如:辣椒、花椒…现在我们只需要使用通配符这个规则,我们就不需要写这些原料的具体名称,只需要知道.c结尾的就回自动匹配为原料。下面就是我们定义的规则:

符号含义
%.o任意的.o文件
*.o所有的.o文件
  • %.o%.c 中的 %通配符,表示任何文件名。
  • %.o: %.c 表示所有以 .o 结尾的目标文件,都依赖于相应的以 .c 结尾的源文件。例如,program1.o 依赖于 program1.cmain.o 依赖于 main.c

上面代码可再次简化如下:

TAR = test
OBJ = program1.o program2.o main.o
CC := gcc

$(TAR):$(OBJ)
	$(CC) $(OBJ) -o $(TAR)

%.o:%.c
	$(CC) -c %.c -o %.o

.PHONY:
clean_all:
	rm $(OBJ)

我们再多加个规则:

符号含义
$^所有依赖文件
$@所有目标文件
$<所有依赖文件的第一个文件

上面代码可再次简化如下:

TAR = test
OBJ = program1.o cube.o main.o
CC := gcc
RMRF := rm 

$(TAR):$(OBJ)
	$(CC) $^ -o $@
%.o:%.c              //%.o表示以.o结尾的文件
	$(CC) -c $^ -o $@

.PHONY:
cleanall:
	$(RMRF) $(OBJ)

5、更多内容

​ OK,你已经入门Makefile,但要完成更复杂的任务还需要更多手法,比如修一栋房子,你需要进入其它房间,分批完成,这就涉及到多个Makefile文件的相互嵌套和更多的命令了。这就等后续再进行讲解了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值