makefile

完整的例子:


簡化:

make是一個命令工具,它解釋makefile中的指令(或者說規則),在Linux環境下使用GNU的make 工具能夠比較容易地構建一個工程,整個工程的編譯只需要一個命令就可以完成編譯、鏈接以至於最後的執行。
make在執行時,需要一個命名爲Makefile的文件。

make -c  //make目標文件所在目錄
          -f   //目標文件

make會自動根據修改情況(通過比較對應文件(規則的目標和依賴)的最後修改時間,來決定哪些文件要更新,哪些文件不需要更新),完成源文件對應.o文件的更新、庫文件的更新、最終可執行程序的更新。
當使用make工具進行編譯時,工程中以下幾種文件在執行make時將會被編譯:
1.如果是第一次編譯,則所有源文件都會被進行編譯。
2.每一個在上次執行make之後修改過的源代碼文件在本次執行make時將會重新編譯。
3.頭文件在上一次執行make之後被修改,則所有包含此頭文件的C源文件在本次執行make時將會被重新編譯。

make的執行過程如下:
1. 依次讀取變量“MAKEFILES”定義的makefile文件列表
2. 讀取工作目錄下的makefile文件(根據命名的查找順序“GNUmakefile”,“makefile”,“Makefile”,首先找到那個就讀取那個)
3. 依次讀取工作目錄makefile文件中使用指示符“include”包含的文件
4. 查找重建所有已讀取的makefile文件的規則(如果存在一個目標是當前讀取的某一個makefile文件,則執行此規則重建此makefile文件,完成以後從第一步開始重新執行)
5. 初始化變量值並展開那些需要立即展開的變量和函數並根據預設條件確定執行分支
6. 根據“終極目標”以及其他目標的依賴關係建立依賴關係鏈表
7. 執行除“終極目標”以外的所有的目標的規則(規則中如果依賴文件中任一個文件的時間戳比目標文件新,則使用規則所定義的命令重建目標文件)
8. 執行“終極目標”所在的規則

makefile的內容
makefile文件描述了整個工程的編譯、鏈接等規則,其中包括:
(1) 工程中哪些文件需要編譯以及如何編譯
(2) 需要創建哪些庫文件以及如何創建這些庫文件
(3) 如何最後產生我們想要的可執行文件


makefile的規則組成
目標:依賴文件列表
命令行
...
注意:1.每一個命令行必須以Tab字符開始
    2.可以將一個較長行使用反斜線"\"來分解爲多行,但反斜線之後不能有空格。

儘量一個規則只存在一個目標文件,但可有多個依賴文件。
一個目標可以沒有依賴而只有動作,比如make clean,用來刪除make過程產生的中間文件。makefile中把那些沒有任何依賴只有執行動作的目標稱爲“僞目標”(phony targets)

默認情況下,make執行makefile中的第一個規則,此規則的第一個目標稱爲“終極目標”。make在處理終極目標之前,會先處理終極目標的所有依賴文件的更新規則。
如果makefile中一個規則所描述的目標不是“終極目標”相關的依賴,那麼這個規則將不會被執行,除非明確指定這個規則。
除了makefile的“終極目標”所在的規則以外,其他規則的順序在makefile中沒有意義。

一個完整的makefile中,包含了5個東西:顯式規則、隱含規則、變量的定義、指示符和註釋。

批處理文件:windows下.bat文件,Linux下.sh文件。

編譯宏在代碼中採用,如#if defined(_INSTALL_LINUX);編譯變量在makefile中採用,如ifeq(RTOS_TYPE=_INSTALL_LINUX)
變量的使用: $(objects)  ,objects爲變量,makefile中的變量可以和C語言中的宏一樣來理解。
當變量名爲單字符時,直接使用$x的格式來實現。shell中變量的引用可以是"${xx}"或"$xx"格式,但在Makefile中多字符變量名的引用只能是"${xx}"或"$(xx)"格式。
兩種變量定義(賦值)
1. 遞歸展開式變量:這種類型變量的定義,可以引用其它的之前沒有定義的變量。
foo = $(bar)
bar = $(ugh)
使用此風格的變量定義,可能會由於出現變量的遞歸定義而導致make陷入到無限的變量展開過程中,最終使make執行失敗,如:
x = $(y)
y = $(x)$(z)

2. 直接展開式變量
使用":="來定義變量。此風格變量在定義時就完成了對所引用變量的展開,因此它不能實現對其後定義變量的引用。$

追加變量值:
objects = main.o foo.o bar.o utils.o
objects += another.o
相當於
objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o

如何定義一個空格:
nullstring:=
space:=$(nullstring)

"?="操作符
Foo?=bar    //如果變量"Foo"之前沒有定義過,就給它賦值"bar",否則不改變它的值

main.o: main.c  defs.h
              cc -c main.c
"cc -c"用來編譯.c源文件,"cc -o"用來編譯.o文件,對於目標爲"N.o",依賴文件是"N.c"的規則,可使用make的隱規則,因此上述規則也可用 main.o:def.h

%CD%   //當前目錄
./  爲當前目錄
../  爲上一級目錄
“#”字符後的內容爲註釋內容,當正文中需要使用字符"#"時,可用"\#"來實現,如果需要用到"$",可用"$$"。
條件語句:ifdef/ifndef,  ifeq/ifneq

clean:
           rm edit $(objects)
可寫爲
.PHONY:clean
clean:
          -rm edit $(objects)
(1) 通過".PHONY"特殊目標"clean"目標聲明爲僞目標,防止當磁盤上存在一個名爲"clean"文件時,"clean"所在規則的命令無法執行;(2)在命令行之前使用"-",意思是忽略"rm"的執行錯誤。

默認情況下,make會在工作目錄(執行make的目錄)下按照文件名順序尋找makefile文件讀取並執行,查找的文件名順序爲:"GNUmakefile"、“makefile”、“Makefile”,推薦使用"Makefile"作爲文件名。
“include”指示符告訴make暫停讀取當前的Makefile,而轉去讀取“include”指定的一個或者多個文件,完成以後再繼續當前Makefile的讀取。

通配符
*.c代表當前工作目錄下所有以.c結尾的文件。
變量定義中使用的通配符不會被展開,需要用函數wildcard,如object=$(wildcard *.o)

目錄搜尋
make執行時的目錄自動搜索順序:
1.先在當前目錄下搜索
2.如果當前工作目錄下不存在,則繼續搜索"VPATH"或"vpath"中指定的目錄
3.對於庫文件,如果還不存在,make程序將搜索系統默認目錄,順序是:/lib、/usr/lib、/usr/local/lib

VPATH爲特殊變量,在其定義中,使用空格或冒號將多個目錄分開。
vpath爲關鍵字,它可以爲不同類型的文件(由文件名區分)指定不同的搜索目錄。
VPATH = src:../headers
vpath %.h ../headers

自動化變量
$^:通過目錄搜索得到的依賴文件的完整路徑名(目錄+一般文件名)列表
$@:代表規則的目標
$<:代表規則中通過目錄搜索得到的依賴文件列表的第一個依賴文件

命令回顯:
make在執行命令行之前會把要執行的命令進行輸出,稱爲回顯。
echo 開始編譯XXX模塊   //將輸出"開始編譯XX模塊"的信息
要取消回顯,則用@echo

在Makefile中書定在同一行中的多個命令屬於一個完整的shell命令行,書寫在獨立行的一個命令是一個獨立的shell命令行。所以需要注意:在一個規則的命令中,命令行"cd"改變目錄不會對其後的命令的執行產生影響。就是說其後的命令執行的工作目錄不會是之前使用"cd"進入的那個目錄。

在make執行失敗時,修改錯誤之後執行make之前,使用"make clean"明確地刪除第一次錯誤重建的所有目標。











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章