MakeFile 文件的使用
什麽是Makefile?
一個工程中的源文件不計其數,其按類型、功能、模塊分別放在若幹個目錄中,makefile定義了一系列的規則來指定,哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯,甚至於進行更復雜的功能操作,因為 makefile就像一個Shell腳本一樣,其中也可以執行操作系統的命令.為什麽要使用Makefile?
就像前面提到的,一個工程的源文件可能不計其數,編寫makefile,使用make命令來構建工程,會使原本復雜繁瑣的工作簡化許多,極大地提高了效率。如何使用make命令?
Makefile 文件描述了整個工程的編譯、連接等規則,make是一個命令工具,它解釋Makefile中的指令(規則)。
一個基本的makefile主要由目標對象、依賴文件、變量和命令4部分組成。
命令行中執行makefile內容:
◆宏定義
◆ 源文件之間的相互依賴關系
◆ 可執行的命令
通常makefile文件中的一條規則的編寫形式如下:
target ... : prerequisites ...
(tab)command
...
...
解釋為:
目標:依賴文件
(制表符)執行指令 ...
下面來看一個具體的例子:
新建 三個文件: main.c add.c fun.h
fun.h
#include<sdtio.h> #include<math.h> int add(int a,int b);
add.c
int multi(int a,int b) { return a+b; }
main.c
#include"fun.h" int main() { int a=12,b=6; c=add(a,b); printf("%d\n",add(a,b)); return 0; }
下圖體現了文件間的依賴關系:
我們先使用gcc 命令來構建這個工程:
gcc -c main.c add.c
查看當前文件目錄:
文件夾中多了main.o 和 add.o這兩個文件,接著在執行下面的命令:
gcc main.o add.o -o math -l m//用main.o add.o 進一步生成目標 ,最後兩個參數 -l m 為連接數學函數庫
我們發現生成目標文件math需要兩步,也就是要先生成main.o 和 add.o 這兩個中間文件,這兩個文件稱為目標文件的直接依賴文件,那麽main.c和add.c分別又是main.o和add.o的直接依賴文件。
makefile正事依據這樣一層一層的的依賴關系和連接 依賴文件 和 目標文件 的命令 所構成的。
下面來看一個最基本的makefile文件:
以下makefile文件顯示了各個目標與依賴文件直接的關系,以及生成它們的命令
add:main.o add.o //目標文件add的依賴文件為main.o、add.o gcc -o add main.o add.o -l m //將目標文件連接為可執行文件,並連接數學函數庫 main.o:main.c //main.o的依賴文件為main.c gcc -c main.c //將源文件main.c編譯成目標文件main.o add.o:add.c gcc -c test.c clean: //清理中間文件 rm main.o add.o add
編寫makefile文件中要註意的幾點:
1、clean沒有被第一個目標add直接或間接依賴,那麽它後面的命令就不會被自動執行可以在make 命令後面跟clean目標作為參數來執行其後所定義的命令,
即執行"make clean"命令,用於清除make過程中生成的目標,以便重新編譯
2、在定義好依賴關系後,後續的那一行定義了如何生成目標文件的操作系統命令,一定要以一個Tab鍵作為開頭。
3、記住,make並不管命令是怎麽工作的,他只管執行所定義的命令。make會比較目標文件和依賴文件的修改日期,即時間戳
如果依賴文件的日期要比目標文件的日期要新,或者目標不存在的話,那麽,make就會執行後續定義的命令
先執行rm main.o add.o math 清除之前生成的中間文件和目標文件
然後用ls命令查看以下當前目錄所包含的文件:
執行make命令,再用ls查看當前目錄下的文件:
我們發現,make命令已經生成了add目標文件,還有依賴文件main.o, add.o
執行結果:
執行make命令時,可以通過參數為makefile文件的宏變量CC賦值,通過宏變量CC指定不同的編譯器來編譯源文件
CC= add:main.o add.o $(CC) -o add main.o add.o main.o:main.c $(CC) -c main.c add.o:add.c $(CC) -c add.c clean: rm main.o add.o add
下面,對makefile做一點小小的改動:
OBJS=main.o add.o #使用了變量OBJS CC=gcc CFLAGS=-Wall -O -g add:$(OBJS) $(CC) $(OBJS) -o add main.o:main.c $(CC) $(CFLAGS) -c main.c add.o:add.c $(CC) $(CFLAGS) -c add.c clean: rm *.o add
這裏使用到了變量,用CC代替了gcc, CFLAGS是makefile中預定義的變量,我們為將它初始化為-Wall -O -g (開啟警告信息、編譯鏈接過程中執行優化處理、增加調試信息),這三個參數都是gcc參數的常用的值,關於gcc參數常用值,這裏不做具體介紹。
Makefile中允許使用簡單的宏指代源文件及其相關編譯信息,在Linux中也稱宏為變量。在引用宏時只需在變量前加$符號,
但值得註意的是,如果變量名的長度超過一個字符,在引用時就必須加圓括號()。
有效的宏引用
$(CFLAGS)
$Z
$(Z)
makefile中常見的預定義變量及其部分默認值
我們先使用make clean 清除之前生成的目標文件,再執行make命令,得到的結果是一樣的.
下面再對makefile進行升級:
#Makefile CC=gcc CFLAGS=-Wall -O -g OBJS=main.o add.o add:$(OBJS) $(CC) $^ -o $(OBJS) main.o:main.c $(CC) $(CFLAGS) -c $< -o $@ add.o:add.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f *.o
這裏使用了makefile 的自動變量,下表是makefile中常見的自動變量:
makefile中常見的自動變量
自動變量通常可以代表編譯語句中出現的目標文件和依賴文件等,自動變量的使用進一步簡化makefile的編寫,自動變量的書寫比較難記,但是在熟練了之後會非常方便。
下面是一個使用二進制作為目標文件的makefile模板:
.PHONY:clean all CC=gcc CFLAGS=-Wall -g -I../include //-I[頭文件目錄路徑] :用來找到不再當前目錄下的頭文件 BIN=main add //這一行添加依賴文件的名稱 all:$(BIN) %.o:%.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f *.o $(BIN)
終極版makefile
關於maefile的寫法,其形式可能有很多種,makefile還支持帶有條件語句的條件編譯、函數、以及一些隱含規則等,這裏不做深入介紹,只有多加練習、實踐,才能真正掌握make這個強大的工具。
MakeFile 文件的使用