什么是Makefile?
- 一個工程中的源文件不計其數(shù),其按類型、功能问麸、模塊分別放在若干個目錄中,Makefile定義了一系列規(guī)則來制定钞翔,哪些文件需要先編譯口叙,哪些文件需要重新編譯,如何進(jìn)行鏈接等操作嗅战。
- Makefile就是"自動化編譯"妄田,告訴make命令如何編譯和鏈接俺亮。
- Makefile也是make命令的配置腳本,默認(rèn)情況下GUN make會在當(dāng)前目錄下尋找文件疟呐,按照優(yōu)先級依次尋找 GNUmakefile -> makefile -> Makefile脚曾。也可使用 make -f/-file “文件名" 手動指定Makefile文件
Makefile文件內(nèi)容
- 顯示規(guī)則
- 如何生成一個或多個目標(biāo)文件
- 隱晦規(guī)則
- 依賴于Makefile自動推導(dǎo),可以簡略書寫Makefile
- 變量定義
- 可以定義變量 一般為String启具,類似于“宏”本讥,當(dāng)Makefile被執(zhí)行時,變量會擴(kuò)展到相應(yīng)的引用位置上
- 文件指示
- 一個Makefile引用另外一個Makefile鲁冯。類似于C的include
- 根據(jù)情況拷沸,指定Makefile有效部分。類似于C的預(yù)編譯
- 定義多行命令
- 注釋
- 只有行注釋“#”
Makefile的規(guī)則
target ... : prerequisites ...
command
或
target ... : prerequisites ... ; command
- target: 目標(biāo)文件薯演∽采郑可以是Object File,也可以是執(zhí)行文件跨扮,還可以是標(biāo)簽(Label)序无。
- 如果是多文件用空格隔開。
- 也可使用通配符
- prerequisites:依賴文件衡创,即要生成那個target所需要的文件或其他target
- command:make需要執(zhí)行的命令
如果命令太長可以使用“\”作為換行符進(jìn)行換行
Makefile的規(guī)則就是告訴make 文件的依賴關(guān)系以及如何生成目標(biāo)文件帝嗡;
target的文件依賴prerequisite文件,生成規(guī)則在command中
如果prerequisite有一個以上的文件比target新璃氢,target會被認(rèn)為是過時的需要重新生成哟玷,command將被執(zhí)行,從而生成新的target一也。
示例
# 當(dāng)前目錄存在main.c碗降、tool.c、tool.h三個文件
# 要生成一個main目標(biāo)文件依賴于main.o tool.o
main: main.o tool.o
# 生成目標(biāo)的命令
gcc main.o tool.o -o main
# .PHONY:顯式的指明clean是一個“偽目標(biāo)”
.PHONY: clean
# clean: 標(biāo)簽塘秦,不會生成“clean”文件讼渊,這樣的target稱之為“偽目標(biāo)”,偽目標(biāo)的名字不能和文件名重復(fù)尊剔。clean一般放在文件最后
clean:
# -rm “-” 表示如果某些文件出現(xiàn)問題 跳過
-rm main *.o
clean偽目標(biāo)需要make顯式調(diào)用make clean
makefile執(zhí)行效果如下
Makefile是如何工作的
默認(rèn)方式下爪幻,輸入make命令后:
- make會在當(dāng)前目錄下找名字叫“Makefile”或“makefile”的文件。
- 如果找到须误,它會找文件中第一個目標(biāo)文件(target)挨稿,并把這個target作為最終目標(biāo)文件,如前面示例中的“main”京痢。
- 如果main文件不存在奶甘,或main所依賴的.o的修改時間要比main文件新,那么它會執(zhí)行后面所定義的命令來生成main文件
- 如果main所依賴的.o文件也存在祭椰,那么make會在當(dāng)前文件中找目標(biāo)為.o文件的依賴性臭家,若找到則根據(jù)規(guī)則生成.o文件疲陕。
- make再用.o文件聲明make的終極任務(wù),也就是可執(zhí)行文件“main”钉赁。
make會層層找文件依賴關(guān)系蹄殃,直到最終編譯出第一個目標(biāo)文件,如果在找的過程出現(xiàn)錯誤你踩,make會退出并拋出錯誤诅岩。Make只管文件的依賴性,編譯錯誤不會理會
Makef中變量的使用
? 如果工程需要加入一個新的“.o”文件 Makefile需要修改多處带膜,為了易維護(hù)吩谦,在Makefile中我們可以使用變量。比如膝藕,我們聲明一個變量為objects式廷,這樣就可以方便的在Makefile中以$(objects)的方式使用這個變量了。
我們修改一下剛剛的Makefile文件
objects = main.o tool.o
main: $(objects)
gcc $(objects) -o main
.PHONY: clean
clean:
-rm main $(object)
引用其他的Makefile
在實際開發(fā)中我們會按類型將源文件會分成不同的模塊束莫,每個模塊有一個單獨的Makefile文件懒棉,那么編譯時就需要引入其他模塊的Makefile草描,在Makefile中可以使用include關(guān)鍵字引入其他模塊
# 語法格式
include <filename>
# 如果文件找不到览绿,而你希望make時不理會那些無法讀取的文件而繼續(xù)執(zhí)行,可以在include前加"-"
-include <filename>
環(huán)境變量 MAKEFILES
? 如果當(dāng)前環(huán)境中定義了環(huán)境變量MAKEFILES穗慕,make會把這個變量中的值做一個類似于include的動作饿敲。這個變量中的值是其它的Makefile,用空格分隔逛绵。只是怀各,它和include不同的是,從這個環(huán)境變量中引入的Makefile的“目標(biāo)”不會起作用术浪,如果環(huán)境變量中定義的文件發(fā)現(xiàn)錯誤瓢对,make也會不理。但是建議不要使用這個環(huán)境變量胰苏,因為只要這個變量一被定義硕蛹,那么當(dāng)你使用make時,所有的Makefile都會受到它的影響硕并。
? 也許有時候Makefile出現(xiàn)了奇怪的事法焰,可以查看當(dāng)前環(huán)境中有沒有定義這個變量。
Makefile預(yù)定義變量
Makefile自動變量
函數(shù)
# 不帶參數(shù)
define FUNC
$(info echo "hello")
endef
# 調(diào)用 FUNC函數(shù) 輸出hello
$(call FUNC)
# 帶參數(shù)
define FUNC1
$(info echo $(1) $(2))
endef
# 調(diào)用FUNC1函數(shù) 輸出hello world
$(call FUNC1,hello,world)
make的工作流程
- 讀入所有的Makefile倔毙。
- 讀入被include的其他Makefile埃仪。
- 初始化文件中的變量。
- 推導(dǎo)隱晦規(guī)則陕赃,并分析所有規(guī)則卵蛉。
- 為所有的目標(biāo)文件創(chuàng)建依賴關(guān)系鏈颁股。
- 根據(jù)依賴關(guān)系,決定哪些目標(biāo)要重新生成毙玻。
- 執(zhí)行生成命令豌蟋。
上面的流程分兩個階段:1-5 為第一階段、6桑滩、7為第二階段
在第一階段中如果定義的變量被使用了梧疲,make會把變量展開在使用的位置,但不完全展開运准,如果變量出現(xiàn)在依賴關(guān)系的規(guī)則中幌氮,只有依賴被使用的時候,變量才會被展開