目錄
一、make/Makefile的簡單使用
二、Makefile 的語法規則
三、實現的原理
3.1 make/Makefile識別文件新舊
3.2?.PHONY修飾的偽目標總是被執行
3.3?make/Makefile是具有依賴性的推導能力的
四、語法技巧
五、注意事項
Linux中自動化構建項目最簡單的方式:make/Makefile
make:是一個命令
Makefile:是一個在當前目錄下存在的一個具有特定格式的文本文件。
(Makefile首字母可以小寫,但建議使用大寫)makefile文件中,保存了編譯器和鏈接器的參數選項,并且描述了所有源文件之間的關系。make程序會讀取makefile文件中的數據,然后根據規則調用編譯器,匯編器,鏈接器產生最后的輸出。
一、make/Makefile的簡單使用
- 創建Makefile:
touch Makefile
- ?編寫Makefile:
vim Makefile
- 編寫要生成的可執行程序mybin和項目清理clean:
- 使用make命令生成可執行程序
make
- 使用make命令進行項目清理
make clean
二、Makefile 的語法規則
Makefile 中包括依賴關系(目標、依賴)和依賴方法(命令)。
下面是 Makefile 中一些要素的基本語法規則:
目標:指定了要生成的文件或要執行的操作名。
例如:上面的mybin就是要生成的目標文件名。
依賴:指定了目標所依賴的文件或其他目標。
例如:上面的test.c 是目標文件依賴的文件。一個目標文件可以有多個依賴文件,用空格分開。
目標和依賴構成了依賴關系。
命令(依賴方法):包含了生成目標所需的具體操作步驟,通常是一條或多條 Shell 命令。
第二行必須以Tab開頭,不能是空格,緊接著是生成目標文件的命令。
例如:上面的gcc test.c -o mybin -std=c99
(gcc test.c -o mybin 與gcc -o mybin test.c 相同,-o后面跟目標文件名即可)
偽目標:偽目標是指在 Makefile 中.PHONY定義的不對應實際文件的目標,通常用于執行一些特定的操作,比如清理臨時文件。?
例如:上面的clean目標用于執行清理操作,刪除mybin文件。
注:make默認執行的是第一行的命令,一般把清理工作放在最后面。
注釋:使用 # 符號來添加注釋,注釋從 # 開始一直到該行的末尾。
變量:可以使用變量來存儲命令選項、編譯器名稱等信息,然后在規則中引用這些變量。
語法格式:VAR_NAME = value條件判斷:可以使用條件判斷(ifeq、ifdef 等)來根據不同的條件執行不同的命令。
函數:Makefile 支持一些內置函數,可以用于字符串處理、文件查找等操作。
使用make和make clean,就可以方便地完成項目自動化構建和清理。
三、實現的原理
3.1 make/Makefile識別文件新舊
make命令不是每次都會重新編譯,只有更改過的文件才會重新編譯。(提高編譯效率)
若源代碼沒有更改也重新編譯,那么每次預處理編譯匯編鏈接的時間比較長,成本高。
make/Makefile是如何知道文件更改過的?
答:通過源文件的修改時間和形成的可執行程序(也是文件)的修改時間做對比。
重新編譯的本質:重新寫入一個二進制的可執行文件(bin文件),文件的修改時間會跟著更改。
- 第一次的時候,一定是先有源文件,才有bin文件。
源文件的修改時間 < bin文件的修改時間 - 第二/n次的時候,我們對源文件做任何修改的時候,
源文件的修改時間 > bin文件的修改時間?????
重新編譯形成可執行
大部分情況下重新編譯都沒問題,問題的產生不僅僅是修改新文件就能解決的。有些歷史問題需要重新清理項目才可以解決。
文件 = 內容 + 屬性,所以文件的ACM時間肯定與內容或屬性有關。
Access(最近訪問時間):普通文本文件打開:cat、vim,或者對目錄進入、ls顯示等
Modify?(對內容修改):當文件內容發生變化時,修改時間(mtime)會被更新。
Change(對屬性修改):當文件的權限、所有者、鏈接數或文件名發生變化時,更改時間(ctime)會被更新。
注:
- 三種時間會出現聯動,例如對內容修改,Access和Change時間也會更改。
- Access時間不是每次訪問時都更改,讀取查看文件操作最頻繁,如果每次都改的話,比較浪費時間,因為文件一般都在磁盤存放,更改時間的本質就是訪問磁盤。但是訪問磁盤的速度比較慢(相對cpu而言),讀取查看文件操作又是很頻繁,如果每次都更改Access time的話,系統效率就會降低很多,所以就會隔一段時間更改一次。
(具體間隔時間和是否間隔,由內核版本決定)- 使用touch命令可以修改ACM時間。
-a 選項? 修改Access時間,但同時也修改了change時間,因為access時間也是屬性。
-m 選項 修改Modify時間,但是Change時間也會跟著改。
綜上,make?是通過對比源文件和bin文件的Modify時間確定文件新舊的。
3.2?.PHONY修飾的偽目標總是被執行
通過時間對比,可以做到不讓有些代碼進行重新編譯(不讓某些操作進行)。
總是被執行就是:不考慮其他任何問題,總是執行依賴方法,不會被任何情況攔截。
(make/makefile不再依靠時間對比了,直接執行對應的命令)
例如:mybin被.PHONY修飾,則多次make時,都會執行gcc命令,把可執行程序重新形成。
3.3?make/Makefile是具有依賴性的推導能力的
上一節講到gcc編譯生成一個可執行程序需要經過預處理、編譯、匯編和連接,中間會產生.i,.o,.s文件。但是在上面的操作中都沒有生成中間文件。
但是我們知道一件事:生成bin文件,就需要對應的.o文件。
以Makefile的推導過程如下:(類似一個棧結構)
生成了臨時文件 code.o code.s code.i
以上寫法只是為了了解編譯推導的過程,實際上不推薦使用。
建議直接用gcc形成可執行!
四、語法技巧
- Makefile里面的指令執行時會自動回顯出來,可以在前面加上?@?符號使其不回顯,不顯示指令信息。
- 可以使用?echo?添加一些輸出信息。
- 依賴方法可以不止一個,用回車隔開。
- makefile中用?#?注釋
- makefile中可以編寫變量,表達式之間不建議帶空格
通過 $(變量名)?來引用變量的值。
用途:之后如果想使用g++,只需要把gcc改成g++,mybin改成mybin.exe - 可以用 #^ 符號代替依賴關系中的所有內容,#@?代替要形成的目標文件
?
五、注意事項
- 首次make時,make掃描Makefile文件時,自頂向下。如果發現第一個目標文件,則嘗試根據該目標及其依賴關系構建目標文件。(默認一次形成一個最終的目標文件)
- 偽目標文件沒有實際的依賴關系,每次都會執行其定義的命令,而不是構建文件。
- Makefile里主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和注釋。
顯式規則說明了,如何生成一個或多個目標文件。 - make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地簡略地書寫makefile,比如源文件與目標文件之間的時間關系判斷。
- 在makefile中可以定義變量,當makefile被執行時,其中的變量都會被擴展到相應的引用位置上,通常使用 $(var) 表示引用變量。
- 文件指示。在一個makefile中引用另一個makefile,類似C語言中的include;
".mk" 是用來表示 Makefile 文件的擴展名。include path/to/another_makefile.mktarget: dependencycommand
- 注釋,makefile中可以使用 # 在行首表示行注釋
- 默認的情況下,make命令會在當前目錄下按順序找尋文件名為"GNUmakefile"、"makefile"、"Makefile"的文件。