分別放在若干個目錄中,makefile定義了一系列的規則 來指定哪些檔案需要先編譯,哪些檔案需要后編譯,哪些檔案需要重新編譯,甚至于進行更復雜的功能操作,因為 makefile就像一個
Shell腳本一樣,也可以執行作業系統的命令,–引自百科詞條
往期文章鏈接
文章目錄
- 1 學習目標
- 2 makefile概述
- 3 目標、依賴、處理動作的概念(重要)
- 4 makefile 基礎規則
- 4.1 一個規則的概念
- 4.2 兩個函式的概念
- 4.3 三個自動變數的概念
- 5 makefile 基礎規則實體解釋
- 5.1 一個規則演示(加減乘除多檔案編譯)
- 5.1.1 代碼部分
- 5.1.2 結果
- 5.1.3 利用規則改進
- 5.2 補充-ALL指定輸出目標
- 5.3 兩個函式演示
- 5.4 補充-clean用法
- 5.5 三個自動變數用法
- 5.6 補充-模板規則
- 5.7 補充-靜態模板規則
- 5.8 補充-偽目標
- 5.9補充-第三方函式的添加
- 小點補充
- 總結
1 學習目標
網上對于
makefile總結學習文章有許多,但是大部分排版或者內容雜亂無章,所以還是自己進行一個總結學習,大家可以根據自己的閱讀習慣選擇適合自己的文章,
在實體部分的代碼是層層遞進改變,每一次都是在之前的基礎上修改,
- 了解Make工具給我們帶來的好處和便利
- makefile的書寫格式、關鍵字、函式,像C 語言有自己的格式、關鍵字和函式一樣(重點)
2 makefile概述
make工具是一個根據makefile檔案內容,針對目標(可執行檔案)進行依賴性檢測(要生成該可執行檔案之前要有哪些中間檔案)并執行相關動作(編譯等)的工具 ,而這個makefile檔案類似一個腳本,其中內容包含make所要進行的處理動作以及依賴關系,
3 目標、依賴、處理動作的概念(重要)
學習make工具,需要明白三個概念:
目標、依賴、處理動作,makefile所要進行的主要內容是明確目標、明確目標所依賴的內容、明確依賴條件滿足時應該執行對應的處理動作,例如我們最終要實作a這個目標,但是需要依賴b,而b依賴于c的存在,則可以描述為:
a:b
cmdbtoa
b:c
cmdctob
//---------------中文表示如下--------------
目標:依賴條件
(一個tab縮進)命令
目標:依賴條件
(一個tab縮進)命令
- " : "代表依賴,另外每個處理動作之前都要用tab鍵分隔,
- 上述四行的意思是:a依賴于b,而處理cmdbtoa;b依賴于c,而處理cmdctob,
4 makefile 基礎規則
在網上一個比較好的視頻學習中總結了一個口訣規則:
- 一個規則
- 二個函式
- 三個自動變數
4.1 一個規則的概念
- 目標的時間必須晚于依賴條件的時間,否則,更新目標
- 依賴條件如果不存在,找尋新的規則去產生依賴條件,
- makefile的依賴是從上至下的,換句話說目標檔案是第一句里的目標,如果不滿足執行依賴,就會繼續向下執行,如果滿足生成目標的依賴,就不會再繼續向下執行了,make會自動尋找規則里需要的材料檔案,執行規則下面的行為生成規則中的目標,
4.2 兩個函式的概念
為了方便學習,我們可以把
wildcard、patsubst看做C語言的函式名,src、obj看成變數名(表示函式的回傳值)- 函式名后面跟著的
./*.c %.c, %.o看做函式的引數,根據順序可以看做引數一、引數二、引數三
src = $(wildcard ./*.c):作用:匹配當前作業目錄下的所有.c 檔案,將檔案名組成串列,賦值給變數 src,等價于src = add.c sub.c div1.cobj = $(patsubst %.c, %.o, $(src)):作用 將引數 3 中,包含引數 1 的部分,替換為引數 2,等價于obj = add.o sub.o div1.o
4.3 三個自動變數的概念
$@: 在規則的命令中,表示規則中的目標,$^: 在規則的命令中,表示所有依賴條件,$<: 在規則的命令中,表示第一個依賴條件,如果將該變數應用在模式規則中,它可將依賴條件串列中的依賴依次取出,套用模式規則,
5 makefile 基礎規則實體解釋
5.1 一個規則演示(加減乘除多檔案編譯)
演示利用makefile演示多檔案編譯,把加減乘除的函式分別放在不同的檔案中,hello.c進行呼叫執行,
5.1.1 代碼部分
makefile
hello:hello.c add.c sub.c div1.c
gcc hello.c add.c sub.c div1.c -o hello
hello.c
# include<stdio.h>
int add(int,int);
int sub(int,int);
int div1(int,int);
int main(int argc,char*argv[])
{
int a=1,b=2;
printf("%d+%d=%d\n",a,b,add(a,b));
printf("%d-%d=%d\n",a,b,add(a,b));
printf("%d+%d=%d\n",a,b,add(a,b));
printf("over\n");
return 0;
}
add.c
# include<stdio.h>
int sub(int a,int b)
{
int c=a+b;
return c;
}
sub.c
# include<stdio.h>
int sub(int a,int b)
{
int c=a-b;
return c;
}
div1.c
# include<stdio.h>
int sub(int a,int b)
{
int c=a/b;
return c;
}
5.1.2 結果
演示結果

5.1.3 利用規則改進
- 這樣帶來的問題就是當你其中一個函式修改的時候,那么全部的檔案都要重新編譯,連接,如果每個檔案單獨執行需要1小時,全部重新編譯時間就非常長了,我們完全可以讓修改的檔案執行生成
.o檔案,再跟其他的.o檔案鏈接就可以了,
補充:不懂的預處理-編譯-匯編-鏈接 查看往期文章
修改makefile
hello:hello.o add.o sub.o div1.o
gcc hello.o add.o sub.o div1.o -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
div1.o:div1.c
gcc -c div1.c -o div1.o
- 修改后,我們把
hello當作目標,hello.o add.o sub.o div1.o作為依賴,如果檔案第一次編譯,這些.o檔案不存在,那就去下面的檔案需要生產規則,當我們單獨修改add.c檔案,由于依賴時間不能先于目標add.o那么需要重新單獨執行gcc -c add.c -o add.o,這樣就省去了許多功夫,
5.2 補充-ALL指定輸出目標
makefile 默認第一個目標檔案為終極目標,生成就跑路,這時候可以用 ALL 來指定終極
目標指定目標的 makefile
ALL:hello
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
div1.o:div1.c
gcc -c div1.c -o div1.o
hello:hello.o add.o sub.o div1.o
gcc hello.o add.o sub.o div1.o -o hello
5.3 兩個函式演示
利用函式生成的
src,obj可以代替原本一長串的.c or .o,如下展示,
*.c表示的是當前目錄下所有.c檔案%.c表示當前目錄下第一個,這邊用%做到依次取出.c修改成.o
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
ALL:hello
hello:$(obj)
gcc $(obj) -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
div1.o:div1.c
gcc -c div1.c -o div1.o
5.4 補充-clean用法
為了方便使用,能夠一次性清楚
.o檔案和輸出檔案,使用clean做出如下修改
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
ALL:main
main:$(obj)
gcc $(obj) -o main
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
div1.o:div1.c
gcc -c div1.c -o div1.o
clean:
-rm -rf $(obj) main
rm前面的-,代表出錯依然執行,比如,待洗掉檔案集合是 5 個,已經手動洗掉了 1 個,就只剩下 4個,然而洗掉命令里面還是 5 個的集合,就會有洗掉不存在檔案的問題,不加這-,就會報錯,告訴你有一個檔案找不到,加了-就不會因為這個報錯,
5.5 三個自動變數用法
$@:在規則命令中,表示規則中的目標$<:在規則命令中,表示規則中的第一個條件,如果將該變數用在模式規則中,它可以將依賴條件
串列中的依賴依次取出,套用模式規則$^:在規則命令中,表示規則中的所有條件,組成一個串列,以空格隔開,如果這個串列中有重復項,則去重
做出如下修改
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
ALL:main
main:$(obj)
gcc $(obj) -o $@
hello.o:hello.c
gcc -c $< -o $@
add.o:add.c
gcc -c $< -o $@
sub.o:sub.c
gcc -c $< -o $@
div1.o:div1.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) main
補充說明
- sub,add 這些指令中使用 < 和 <和 <和^都能達到效果,但是為了模式規則,所以使用的$<
5.6 補充-模板規則
此時要添加一個乘法函數,就需要在 makefile 里面增加乘法函式的部分,擴展性就不行,所有就有了模板規則了
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
ALL:main
main:$(obj)
gcc $(obj) -o $@
%.o:%.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) main
此時我們增加一個乘法的模板重新make ./

增加函式的時候,不用改 makefile,只需要增加.c 檔案,改一下原始碼就行,
5.7 補充-靜態模板規則
使用靜態模式規則,就是指定模式規則給誰用,這里指定模式規則給 obj 用,以后檔案多了,檔案集合會有很多個,就需要指定哪個檔案集合用什么規則,
也可以理解成目標依賴從那個模板規則來.
$(obj):%.o:%.c
修改如下
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
ALL:main
main:$(obj)
gcc $(obj) -o $@
$(obj):%.o:%.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) main
5.8 補充-偽目標
當前檔案夾下有 ALL 檔案或者 clean 檔案時,會導致 makefile 癱瘓,所以添加一行
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
ALL:main
main:$(obj)
gcc $(obj) -o $@
$(obj):%.o:%.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) main
.PHONY: clean All
5.9補充-第三方函式的添加
src=$(wildcard *.c) # add.c sub.c div1.c hello.c
obj=$(patsubst %.c,%.o,$(src)) # add.o sub.o div1.o hello.o
myArgs=-Wall -g -pthread
ALL:main
main:$(obj)
gcc $(obj) -o $@ $(myArgs)
$(obj):%.o:%.c
gcc -c $< -o $@ $(myArgs)
clean:
-rm -rf $(obj) main
.PHONY: clean All
小點補充
- makefile 也可以寫成Makefile
src=$(wildcard *.c)表示的當前檔案夾下的所有.c等價與src=$(wildcard ./*.c)
總結
重點關注實體部分是怎么層層遞進修改的,如有錯誤,歡迎指出,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280591.html
標籤:其他
上一篇:基于Ubuntu系統下的Hadoop平臺搭建詳細步驟
下一篇:編碼編成翔的十八般兵器

