Makefile学习(二)- 语法(变量、伪目标)

一、简介

       上一章节,我们介绍了Makefile的基本规则,如果不了解的可以先看这篇文章:https://blog.youkuaiyun.com/qq_26226375/article/details/151828250?sharetype=blogdetail&sharerId=151828250&sharerefer=PC&sharesource=qq_26226375&spm=1011.2480.3001.8118

        Makefile语法是一套用于定义编译规则的特殊格式,核心是通过“规则”描述文件依赖关系和编译命令。下面我们来详细介绍下。

二、语法

%(通配符)

        %可以匹配任意字符串,用于批量定义规则。例如上一章节的Makefile文件。

a.o: a.c
	gcc -o a.o -c a.c

        利用通配符,可以修改为

%.o: %.c
	gcc -o %.o -c %.c

       %.o表示所有的.o文件,%.c表示所有的.c文件

        但是这样写歧义会非常的大,make执行是会直接报错。

自动变量

        简化命令中的文件引用,常用如下指令

  • $@当前规则的目标文件
  • $<当前规则的第一个依赖文件
  • $^当前规则的所有依赖文件(去重)
  • $+当前规则的所有依赖文件(保留重复)

        加入自动变量后,可以优化如下代码

test: a.o b.o
	gcc -o test a.o b.o

a.o: a.c
	gcc -o a.o -c a.c

b.o: b.c
	gcc -o b.o -c b.c

        加入变量

test: a.o b.o
	gcc -o $@ $^

%.o: %.c
	gcc -o $@ -c $<

      $@为当前规则目标文件,则gcc -o test a.o b.o可以缩减为gcc -o $@ a.o b.o

        $^为当前规则依赖的所有文件,则gcc -o $@ a.o b.o可以缩减为gcc -o $@ $^

        $<为当前规则的第一个依赖文件,则gcc -o b.o -c b.c可以缩减为gcc -o b.o -c $<

变量

        变量用于简化重复内容,定义和引用方式。常见的表达方式有如下:

变量名 = 值       # 递归展开(可能有副作用)
变量名 := 值      # 简单展开(推荐)
变量名 ?= 值      # 若变量未定义则赋值
变量名 += 值      # 追加内容
$(变量名)         # 引用变量

        :=(立即赋值)

        变量在定义时立即展开后续修改依赖的变量不会影响当前变量

A := hello
B := $(A) world  # 定义时立即展开,B 的值固定为 "hello world"
A := hi          # 后续修改 A 不影响 B

test:
	@echo "B = $(B)"  

        =(递归赋值)

        变量在定义时不会展开,在使用时展开,后续变量修改会影响当前变量

SRC = a.c
OBJ = $(SRC:.c=.o)  # 用 = 定义,依赖 SRC

# 后续修改 SRC
SRC += b.c

test:
	@echo "OBJ = $(OBJ)"  

        ?=(条件赋值)

        仅当变量未被定义过时才赋值,若变量已经存在,则不改变其值。

SRC = a.c
SRC ?= b.c

SRC2 = a.c
SRC2 = b.c

test:
	@echo "SRC = $(SRC), SRC2 = $(SRC2)" 

        +=(追加赋值)

        向已定义的变量追加内容,自动在新内容前添加空格(分隔多个值)

SRC := a.c b.c
SRC += c.c  

test:
	@echo "SRC = $(SRC)"  

        按照这个,如下代码可以进一步优化。

test: a.o b.o
	gcc -o $@ $^

%.o: %.c
	gcc -o $@ -c $<

        引入变量

CC := gcc # 指定编译器
SRC := a.c b.c # 指定源文件
OBJ := $(SRC:.c=.o) # 指定目标文件

test: $(OBJ)
	$(CC) -o $@ $^	# 也可以写为 $(CC) -o $@ $(OBJ)

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

        这里$(SRC:.c=.o)是一种字符串替换语法,用于将变量SRC中所有以.c结尾的文件名替换为.o结尾的文件名,从而自动生成目标文件列表。

伪目标

        用于定义不生成文件的操作,避免与同名文件冲突

        例如,在文件夹中存在clean文件,此时执行make clean将会报错。

        修改代码,声明伪目标

CC := gcc # 指定编译器
SRC := a.c b.c # 指定源文件
OBJ := $(SRC:.c=.o) # 指定目标文件
.PHONY: clean

test: $(OBJ)
	$(CC) -o $@ $^	# 也可以写为 $(CC) -o $@ $(OBJ)

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

clean:
	rm -f $(OBJ) test

       all

        这里需要介绍一个特殊的伪目标“all”

        在Makefile中,all是一个特殊的伪目标,通常用于定义默认执行的任务,即当在命令行直接输入make而不指定目标时,make会执行all所定义的操作。例如下面的代码:

CC := gcc # 指定编译器
SRC := a.c b.c # 指定源文件
OBJ := $(SRC:.c=.o) # 指定目标文件
.PHONY: clean all

all: test clean
	echo "所有目标构建完成"

test: $(OBJ)
	$(CC) -o $@ $^

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

clean:
	rm -f $(OBJ) test

        运行make等价于make all,会依次构建test和clean,最后输出提示信息。若不定义all,make会默认执行第一个目标test,而忽略clean

        可以看到运行Make后,程序执行了make test 和make clean,导致最终并没有生成.o和test程序。

        而all后面跟的目标文件的顺序也决定了程序运行的顺序,例如将all test clean更换为all clean test,在执行make

CC := gcc # 指定编译器
SRC := a.c b.c # 指定源文件
OBJ := $(SRC:.c=.o) # 指定目标文件
.PHONY: clean all

all: clean test 
	echo "所有目标构建完成"

test: $(OBJ)
	$(CC) -o $@ $^	

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


clean:
	rm -f $(OBJ) test

        可以看到,执行make后,先执行了make clean,再执行了make test。

@

         运行make时,系统会打印执行的命令,如果不希望显示这些命令,可以在命令前加上@。

CC := gcc # 指定编译器
SRC := a.c b.c # 指定源文件
OBJ := $(SRC:.c=.o) # 指定目标文件
.PHONY: all

all: clean test 
	@echo "所有目标构建完成"

test: $(OBJ)
	@$(CC) -o $@ $^	

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


clean:
	@rm -f $(OBJ) test

        可以看到,所有执行的命令都没有在窗口上回显出来。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

t_guest

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值