輕松玩轉(zhuǎn)makefile | 變量與模式
前言
本文通過(guò)簡(jiǎn)單的幾個(gè)示例,以及對(duì)同一個(gè)Makefile進(jìn)行幾個(gè)版本的迭代,幫助快速的理解變量和模式規(guī)則的使用。
1、回顧
在上一篇文章中,我們使用Makefile編譯fun.c和main.c這兩個(gè)文件,最終生成名為app的可執(zhí)行文件。
fun.c的內(nèi)容
#include <stdio.h>
void fun()
{
printf("This is fun()!\n");
}
main.c的內(nèi)容
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
可以發(fā)現(xiàn),Makefile里面有很多重復(fù)的內(nèi)容,我們可以利用變量和模式規(guī)則對(duì)其進(jìn)行優(yōu)化。
2、自動(dòng)變量
\(@:用于表示一個(gè)規(guī)則中的目標(biāo)。當(dāng)有多個(gè)目標(biāo)時(shí),\)@指的是其中任何導(dǎo)致規(guī)則命令被運(yùn)行的自標(biāo)。
$^:表示的是規(guī)則中的所有先決條件。
$<:表示的是規(guī)則中的第一個(gè)先決條件。
是不是看得有點(diǎn)暈?沒(méi)關(guān)系,我們基于上面的Makefile,做一點(diǎn)點(diǎn)修改,把這些東西都打印出來(lái)看一下,就很清楚了。
.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
運(yùn)行make,終端打印如下內(nèi)容
gcc -o app main.o fun.o
$@ = all
$^ = main.o fun.o
$< = main.o
了解到這些之后,我們?cè)俅涡薷?/p>
第二版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、變量的類(lèi)別與賦值
變量的類(lèi)別有遞歸擴(kuò)展變量和簡(jiǎn)單擴(kuò)展變量
3.1 遞歸擴(kuò)展變量
這種只用一個(gè)“=”符號(hào)定義的變量被稱(chēng)為遞歸擴(kuò)展變量
.PHONY:all
goal = $(mid)
mid = $(fun)
fun = test
all:
@echo "goal = $(goal)"
運(yùn)行make命令 ,打印如下
goal = test
3.2 簡(jiǎn)單擴(kuò)展變量
用“:=”操作符來(lái)定義的,make只對(duì)其進(jìn)行一次展開(kāi)。
.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)"
運(yùn)行make命令 ,打印如下
mid_A = test world,mid_B= hello world
3.3 變量條件賦值
用“?=”操作符來(lái)定義,如果變量沒(méi)有被定義,將右邊的值賦值給它,如果變量已經(jīng)定義了,則不改變其原值。
.PHONY:all
funA = original
funA ?= replacement
funB ?= replacement
all:
@echo "funA = $(funA),funB = $(funB)"
運(yùn)行make命令 ,打印如下
funA = original,funB = replacement
3.4 變量追加賦值
通過(guò)“+=”實(shí)現(xiàn)追加賦值
.PHONY:all
objects = main.o fun.o
objects += append.o
all:
@echo "objects = $(objects)"
運(yùn)行make命令 ,打印如下
objects = main.o fun.o append.o
3.5 高級(jí)變量引用功能
在賦值的同時(shí),完成文件名后綴替換操作
.PHONY:all
src = a.c b.c c.c
objs := $(src:.c=.o)
all:
@echo "objs = $(objs)"
運(yùn)行make命令 ,打印如下
objs = a.o b.o c.o
注意,src:.c=.o 冒號(hào)后面不能有空格,如果加了空格變成src: .c=.o ,運(yùn)行make,打印的結(jié)果如下
objs = a.c b.c c.c
4、模式規(guī)則
一個(gè)模式規(guī)則的格式為:
%.o : %.c
command...
我們利用模式規(guī)則對(duì)第二版的Makefile進(jìn)行優(yōu)化
第三版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
這里將兩條構(gòu)建目標(biāo)文件的規(guī)則變成了一條
" % " 類(lèi)似于通配符,%.c匹配所有以".c "結(jié)尾的文件,采用了模式以后,不管有多少個(gè)源文件,都可以用同一條規(guī)則,可以極大的簡(jiǎn)化Makefile
5、利用變量和模式規(guī)則優(yōu)化Makefile
我們?cè)賹?duì)第三版的Makefile進(jìn)行優(yōu)化,將編譯器,目標(biāo)等都用變量替代,這樣以后修改只需要改動(dòng)變量部分就好了
第四版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已經(jīng)得到了很大的改善,但是我們可以看到OBJS = xxxx 這里,如果文件數(shù)量多,得一個(gè)個(gè)書(shū)寫(xiě),還是不夠智能。
下一篇文章,將介紹Makefile函數(shù)的使用,利用函數(shù)可以輕松管理好源文件和目標(biāo)文件。
————————————————————————————————
碼字不易,點(diǎn)個(gè)贊再走吧!
歡迎關(guān)注我的同名公眾號(hào),這里有更多好料等著你哦!

浙公網(wǎng)安備 33010602011771號(hào)