介紹 一般程式都是由多個源檔案編譯連結而成的,這些源檔案的處理步驟通常由Makefile檔案管理。
索引
1、用途 1)準備 2)方便使用 3)原理 4)格式 5)案例2、規則3、Makefile中的變數 1)作用 2)文法 3)案例4、偽目標5、條件陳述式6、調試make7、參考文獻 用途 make工具用來進行協調的工具,可以根據程式模組的修改情況重新編譯連結目標代碼,以保證目標代碼總是由它的最新模組組成。
準備: 要使用make,準備Makefile的檔案(也可以準備其他檔案如GNUMakefile或makefile,推薦使用Makefile),它描述了軟體包中各個檔案之間的關係,提供了更新每個檔案的命令。 方便使用: 當一個適當的Makefile存在時,每次改變某些源檔案,用簡單的shell命令(make),將足以完成所有必需的重新編譯。 原理: make 程式利用Makefile的資料和每個檔案最新一次更改的時間來確定哪些檔案需要更新;對每個需要更新的檔案,make程式使用Makefile中定義的命令來更新它。 格式:
#用“井”號表明注釋。target(要產生的檔案): dependencies(被依賴的檔案) #命令前面用的是“tab”而非空格。誤用空格是初學者容易犯的錯誤! 命令1 命令2 命令3 . . . 命令n#可以使用“\”表示續行。注意,“\”之後不能有空格!
- target通常是我們要產生的檔案的名字,擺放的順序不重要,但第一個target是預設的target。當make不帶參數時,自動執行第一個target。target也可以是要求make完成的動作,執行這種target後並不能得到和target同名的檔案,因此,也稱為偽target(phony target)。
- dependencies是產生target所需的檔案名稱列表。依賴可以為空白,常用的“clean”target就常常沒有依賴,只有命令。
- 命令可以是任何一個shell能啟動並執行命令。
案例:
比如產生exe檔案,它由2個目標代碼某塊組成,分別為module1.o和module2.o module1.h檔案
int module1 = 1;
module1.c檔案
#include "module1.h"void print1(){ printf("var module1:%d\n", module1);}
module2.h檔案
int module2 = 2;
module2.c檔案
#include <stdio.h>#include "module2.h"void print2(){ printf("var module2:%d\n", module2);}int main(){ print1(); print2(); return 0;}
編譯Makefile檔案
exe:module2.o module1.o gcc -g module1.o module2.o -o exemodule2.o:module2.h module2.c gcc -g -c module2.cmodule1.o:module1.h module1.c gcc -g -c module1.cclean: rm -f exe *.o
規則 在編寫完來源程式檔案後,從中產生需要的Makefile規則。 最基本的編寫規則的方法是從最終的來源程式檔案開始一個一個的查看源碼檔案,把它們要產生的目標檔案做為目標,而C語言源碼檔案和源碼檔案包含的標頭檔作為依賴檔案建置規則。 目標和條件之間的關係是:
欲更新目標,必須首先更新它的所有條件;所有條件中只要有一個條件被更新了,目標也必須隨之被更新。所謂“更新”就是執行一遍規則中的命令列表,命令列表中的每條命令必須以一個Tab開頭,注意不能是空格,Makefile的格式不像C語言的縮排那麼隨意,對於Makefile中的每個以Tab開頭的命令,make會建立一個Shell進程去執行它。 Makefile中的變數 Makefile中變數就像一個環境變數。事實上環境變數在make中也被解釋成make的變數。 作用: 儲存檔案名稱列表。——可以方便地加入新的目標檔案而且不易出錯。 儲存編譯器參數。——在很多原始碼編譯時間,gcc需要很長的參數選項,在很多情況下,所有的編譯命令使用一組相同的選項,如果把這組選項使用一個變數表示,那麼可以把這個變數放在所有引用編譯器的地方。(當要改變選項的時候,只需改變一次這個變數內容即可) 文法: 變數:“變數”指的是用一個字串代替另一個字串的功能。在makefile中可以使用“=”號來定義變數,使用“$(變數名)”來使用變數;還可以用“:=”追加變數的內容。習慣上,變數名使用大寫。 定義: 變數名=字串使用: $(變數名)追加: 變數名:=字串 案例:進化上面的Makefile
OBJS=module1.o module2.oC=-cCC=gccexe:$(OBJS) $(CC) -g $(OBJS) -o exemodule2.o:module2.h module2.c $(CC) -g $(C) module2.cmodule1.o:module1.h module1.c $(CC) -g $(C) module1.cclean: rm -f exe *.o
偽目標
首先要明確,並不是所有的目標檔案都對應於磁碟檔案,有的目標檔案的存在只是為了形成一條規則,從而使make完成特定的工作,並不產生新的目標檔案,這樣的目標稱為偽目標。——如上面Makefile中的clean。常用的還有all。
放例子:
all:exe1 exe2 exe1:exe1.c exe1.h gcc exe1.c -o exe1exe2:exe2.c exe2.h gcc exe2.c -o exe2clean: rm -f exe*
其中的all和clean都為偽目標。偽目標檔案是不存在的。注意上面例子中第一條規則下的命令列為空白,make不會執行任何動作,只是檢查依賴檔案的更新情況, 掃描剩下的幾條規則並執行相應的編譯命令產生可執行檔。
條件陳述式 條件陳述式可以將一個變數與其他變數的值進行比較,或將一個變數與一個字串常量相比較。——這樣就可以根據變數的值執行或忽略Makefile檔案中的一部分指令碼。 注意:條件陳述式用於控制make時間看見的Makefile檔案部分,而不能用於執行時控制shell命令。 條件陳述式3條指令:ifeq, else 和endif 放範例:
ifeq($(VAR), 1) gcc -o exe1 moduleelse gcc -o exe2 moduleendif
調試make 我們在很多語言中都要用到調試,那麼我們自然對make也要想到調試了。 make的調試很簡單,只需通過-d選項可是make在執行命令時列印調試資訊。 這些資訊包括: 1、make重新編譯時間需要檢查的檔案 2、哪些檔案被比較以及比較的結果 3、需要重建的檔案 4、make將要使用的隱含規則 5、make實際執行的隱含規則和命令 放範例(一部分)
參考文獻 make - 維基百科,自由的百科全書 第 22 章 Makefile基礎 總結 想要熟練地掌握make工具,必需通過不斷的練習並參考其他Makefile的例子。 我會在後期的開發學習中不斷完善這篇博文。 推薦