为了账号安全,请及时绑定邮箱和手机立即绑定

轻松玩转makefile | 变量与模式

标签:
Linux

前言

本文通过简单的几个示例,以及对同一个Makefile进行几个版本的迭代,帮助快速的理解变量和模式规则的使用。

1、回顾

在上一篇文章中,我们使用Makefile编译fun.c和main.c这两个文件,最终生成名为app的可执行文件。

fun.c的内容

#include <stdio.h>

void fun()
{
	printf("This is fun()!\n");
}

main.c的内容

extern void fun(); 

int main()
{ 
	fun(); 
	return 0; 
}

第一版Makefile

.PHONY:clean

all: main.o fun.o
	gcc -o app main.o fun.o
main.o : main.c 
	gcc -o main.o -c main.c
fun.o : fun.c 
	gcc -o fun.o -c fun.c
clean:
	rm app main.o fun.o

可以发现,Makefile里面有很多重复的内容,我们可以利用变量和模式规则对其进行优化。

2、自动变量

KaTeX parse error: Expected 'EOF', got ':' at position 2: @:̲用于表示一个规则中的目标。当有…@指的是其中任何导致规则命令被运行的自标。

$^:表示的是规则中的所有先决条件。

$<:表示的是规则中的第一个先决条件。

是不是看得有点晕?没关系,我们基于上面的Makefile,做一点点修改,把这些东西都打印出来看一下,就很清楚了。

.PHONY:clean

all: main.o fun.o
	gcc -o app main.o fun.o
	
	@echo "\$$@ = $@"
	@echo "$$^ = $^"
	@echo "$$< = $<"
	
main.o : main.c 
	gcc -o main.o -c main.c
fun.o : fun.c 
	gcc -o fun.o -c fun.c
clean:
	rm app main.o fun.o

运行make,终端打印如下内容

gcc -o app main.o fun.o
$@ = all
$^ = main.o fun.o
$< = main.o

了解到这些之后,我们再次修改

第二版Makefile

.PHONY:clean

all: main.o fun.o
	gcc -o app $^
	
main.o : main.c 
	gcc -o $@ -c $^
fun.o : fun.c 
	gcc -o $@ -c $^
clean:
	rm app main.o fun.o

3、变量的类别与赋值

变量的类别有递归扩展变量简单扩展变量

3.1 递归扩展变量

这种只用一个“=”符号定义的变量被称为递归扩展变量

.PHONY:all

goal = $(mid)
mid = $(fun)
fun = test

all:
	@echo "goal = $(goal)"

运行make命令 ,打印如下

goal = test

3.2 简单扩展变量

用“:=”操作符来定义的,make只对其进行一次展开。

.PHONY:all

goal_A = hello 
mid_A  = $(goal_A) world
goal_A = test

goal_B := hello
mid_B  := $(goal_B) world
goal_B := test

all:
	@echo "mid_A = $(mid_A),mid_B= $(mid_B)"

运行make命令 ,打印如下

mid_A = test world,mid_B= hello world

3.3 变量条件赋值

用“?=”操作符来定义,如果变量没有被定义,将右边的值赋值给它,如果变量已经定义了,则不改变其原值。

.PHONY:all

funA = original
funA ?= replacement

funB ?= replacement
all:
	@echo "funA = $(funA),funB = $(funB)"

运行make命令 ,打印如下

funA = original,funB = replacement

3.4 变量追加赋值

通过“+=”实现追加赋值

.PHONY:all

objects = main.o fun.o
objects += append.o

all:
	@echo "objects = $(objects)"

运行make命令 ,打印如下

objects = main.o fun.o append.o

3.5 高级变量引用功能

在赋值的同时,完成文件名后缀替换操作

.PHONY:all

src = a.c b.c c.c
objs := $(src:.c=.o)

all:
	@echo "objs = $(objs)"

运行make命令 ,打印如下

objs = a.o b.o c.o

注意,src:.c=.o 冒号后面不能有空格,如果加了空格变成src: .c=.o ,运行make,打印的结果如下

objs = a.c b.c c.c

4、模式规则

一个模式规则的格式为:

%.o : %.c 
	command...

我们利用模式规则对第二版的Makefile进行优化

第三版Makefile


#替换掉这部分
#main.o : main.c 
#	gcc -o $@ -c $^
#fun.o : fun.c 
#	gcc -o $@ -c $^

.PHONY:clean

all: main.o fun.o
	gcc -o app $^
%.o : %.c
	gcc -o $@ -c $^
clean:
	rm app main.o fun.o

这里将两条构建目标文件的规则变成了一条

" % " 类似于通配符,%.c匹配所有以".c "结尾的文件,采用了模式以后,不管有多少个源文件,都可以用同一条规则,可以极大的简化Makefile

5、利用变量和模式规则优化Makefile

我们再对第三版的Makefile进行优化,将编译器,目标等都用变量替代,这样以后修改只需要改动变量部分就好了

第四版Makefile

.PHONY:clean

CC = gcc
RM = rm

TARGET = app
OBJS = main.o fun.o

$(TARGET) : $(OBJS)
	$(CC) -o $@ $^
%.o : %.c
	$(CC) -o $@ -c $^
clean:
	$(RM) $(TARGET) $(OBJS)

到这里,Makefile已经得到了很大的改善,但是我们可以看到OBJS = xxxx 这里,如果文件数量多,得一个个书写,还是不够智能。

下一篇文章,将介绍Makefile函数的使用,利用函数可以轻松管理好源文件和目标文件。
码字不易,点个赞再走吧!

欢迎关注我的同名公众号,这里有更多好料等着你哦!

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消