前言 本文通過簡單的幾個示例,以及對同一個Makefile進行幾個版本的迭代,幫助快速的理解變數和模式規則的使用。 1、回顧 在上一篇文章中,我們使用Makefile編譯fun.c和main.c這兩個文件,最終生成名為app的可執行文件。 fun.c的內容 #include <stdio.h> vo ...
前言
本文通過簡單的幾個示例,以及對同一個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、自動變數
$@:用於表示一個規則中的目標。當有多個目標時,$@指的是其中任何導致規則命令被運行的自標。
$^:表示的是規則中的所有先決條件。
$<:表示的是規則中的第一個先決條件。
是不是看得有點暈?沒關係,我們基於上面的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函數的使用,利用函數可以輕鬆管理好源文件和目標文件。
————————————————————————————————
碼字不易,點個贊再走吧!
歡迎關註我的同名公眾號,這裡有更多好料等著你哦!