通常我們在命令行使用GCC對程序進行編譯,如果對於單個或者幾個文件時比較方便的,但當工程中的文件逐漸增多甚至變得十分龐大的時候,使用GCC顯然力不從心,不好管理。因此我們有必要編寫一個Makefile來對工程進行管理。就以下工程目錄進行學習。
生成可執行程序cacu,建立如下規則的Makefile文件。
#生成test,":"左邊為目標,右邊為依賴 。gcc后是命令 cacu:add_int.o add_float.o sub_int.o sub_float.o main.o gcc -o cacu add/add_int.o add/add_float.o \ (連接符) sub_int.o sub_float.o main.o #生成add_int.o的規則 add_int.o:add/add_int.c add/add_int.h gcc -c -o add/add_int.o add/add_int.c #生成add_float.o的規則 add_float.o:add/add_float.c add/add_float.h gcc -c -o add/add_float.o add/add_float.c #生成sub_int.o的規則 sub_int.o:sub/sub_int.c sub/sub_int.h gcc -c -o sub/sub_int.o sub/sub_int.c #生成sub_float.o的規則 sub_float.o:sub/sub_float.c sub/sub_float.h gcc -c -o sub/sub_float.o sub/sub_float.c #生成main.o的規則 main.o:main.c add/add.h sub/sub.h gcc -c-o main.o main.c -Iadd -Isub #清理的規則 clean: rm -f test add_int.o add_float.o sub_int.o \ sub_float.o main.o
Makefile的規則:
Makefile的框架是由規則構成的,make命令執行時,先在Makefile文件中查找各種規則,對各種規則進行解析后,運行規則。規則的基本格式為
TARGET... :DEPENDEDS...
COMAND
……
……
TARGET:規則所定義的目標。通常規則是最后生成的可執行文件的文件名或者為了生成可執行文件而依賴的目標文件的文件名,也可以是一個動作,稱之為。偽目標。
DEPENDEDS:執行此規則所必須的依賴條件,例如生成可執行文件的目標文件。DEPENDEDS也可以是某個TARGET,這樣就形成了TARGET之間的嵌套。
COMMAND:規則所執行的命令,即規則的動作,例如編譯文件、生成庫文件、進入目錄等。動作可以是多個,每個命令占一行。規則的形式比較簡單,要寫好一個MakeEle需要注意一些地方,並對執行的過程有所了解。
1.規則的書寫
在書寫規則的時候,為了使Make租e更加清晰,要用反斜杠(\)將較長的行分解為多行, 例如將"rm-fcacu add/add_int. o add/add_tloat. o sub/sub_int. o sub/sub_float. o main. o"分解為了兩行。命令行必須以Tab鍵開始,m工程序把出現在一條規則之后的所有連續的以Tab鍵開始的行都作為命令行處理。
注意:規則書寫時要注意COMMAND的位置,COMMAND前面的空白是一個Tab鍵,不是空格。Tab告訴make這是一個命令行,make執行相應的動作。
2.目標
Makefile的目標可以是具體的文件,也可以是某個動作。例如目標cacu就是生成cacu的規則,有很多的依賴項,及相關的命令動作。而clean是清除當前生成文件的一個動作,不會生成任何目標項。
3.依賴項
依賴項是目標生成所必須滿足的條件,例如生成cacu需要依賴main.o,main.o必須存在才能執行生成cacu的命令,即依賴項的動作在TARGET的命令之前執行。依賴項之間的順序按照自左向右的順序檢查或者執行。例如,下面的規則
main. o main. c add/add. h sub/sub. h
gcc-c-o main. o main. c-ladd-Isub
main.c、add/add.h和sub/sub.h必須都存在才能執行動作。gcc-c-omaiH.o main.c -ladd -lsub。。,當add/add.h不存在時,是不會執行規則的命令動作的,而且也不會檢查sub/sub.h文件的存在,當然main.c由於在add/add.h依賴項之前,會先確認此項沒有問題。
4.規則的嵌套
規則之間是可以嵌套的,這通常通過依賴項實現。例如生成cacu的規則依賴於很多的.o文件,而每個.o文件又分別是一個規則。要執行規則cacu必須先執行它的依賴項,即
add_int.o、add_float.o、sub_int.o、sub_float.o、main.o,這5個依賴項生成或者存在之后才進行cacu的命令動作。
5.文件的時間戳
make命令執行的時候會根據文件的時間戳判定是否執行相關的命令,並且執行依賴於此項的規則。例如對main.c文件進行修改后保存,文件的生成日期就發生了改變,再次調
用make命令編譯的時候,就會只編譯main.c,並且執行規則cacu,重新鏈接程序。
6、執行的規則
在調用make命令編譯的時候,m工程序會査找MakeEle文件中的第1個規則,分析並執行相關的動作。例子中的第1個規則為cacu,所以m工程序執行cacu規則。由於其依賴項包含5個,第1個為add_int.o,分析其依賴項,當add/add_int.c add.h存在的時候,執行如下命令動作:
gcc-c-o addladd_int. o add/add_int. c
當命令執行完畢的時候,會按照順序執行第2個依賴項,生成add/add_flaot.o.當第5個依賴項滿足時,即main.o生成的時候,會執行cacu的命令,鏈接生成執行文件cacu.當把規則clean放到第一個的時候,再執行make命令不是生成cacu文件,而是清理文件。要生成cacu文件需要使用如下的make命令。
Debain #make cacu
7.模式匹配
在上面的Makefile中,main.o規則的書寫方式如下
main. o :main. c add/add. h sub/sub. h
gcc-c-o main. o main. c-Iadd-Isub
有一種簡便的方法可以實現與上面相同的功能
main. o :%o %c
gcc-c $<-o $@
這種方法的規則main.o中依賴項中的。%o:%c。的作用是將TARGET域的.o的擴展
名替換為.c,即將main.o替換為main.c.而命令行的S〈表示依賴項的結果,即main.c$@
表示TARGET域的名稱,即main.o。
在Makefile中使用用戶自定義變量
定義OBJS變量表示目標文件:
OBJS = add_int.o add_float.o sub_int.o sub_float.o main.o
在調用OBJS的時候在前面加上$,並且變量的名稱可以用括號括起來。例如,使用gcc的默認規則進行編譯,cacu的規則可以采用如下形式
cuca:gcc -o cacu $(OBJS)
用CC表示gcc,用CFLAGS表示編譯選項,RM表示rm -f ,TARGET表示最終的生成目標cacu。
CC = gcc (CC定義成為gcc)
CFLAGS = -Isub -Iadd (加入頭文件搜索路徑sub,add文件夾)
TARGET = cacu (最終生成的目標)
RM = rm -f (刪除的命令)
這樣,之前冗長的Makefile可以簡化為如下形式。
1 CC = gcc 2 CFLAGS = -Isub -Iadd -O2 (O2為優化) 3 OBJS = add_int.o add_float.o sub_int.o sub_float.o main.o 4 TARGET = cacu 5 RM = rm -f 6 $(TARGET):$(OBJS) 7 $(CC) -o $(TARGET) $(OBJS) $(CFLAGS) 8 $(OBJS):%.o:%.c (將OBJS中所有擴展名為.o的文件替換成擴展名為.c的文件) 9 $(CC) -c $(CFLAGS) $< -o $@ (生成目標文件) 10 clean: 11 -$(RM) $(TARGET) $(OBJS) - 表示忽略錯誤
由於CC的默認值已經為cc,RM的默認值為 rm -f,因此,如果在調用這些變量的時候未顯式給出變量的定義,編譯器就去調用其默認值。經過簡化,可以得到以下形式:
1 CFLAGS = -Isub -Iadd -O2 (O2為優化) 2 OBJS = add_int.o add_float.o sub_int.o sub_float.o main.o 3 TARGET = cacu 4 $(TARGET):$(OBJS) 5 $(CC) -o $(TARGET) $(OBJS) $(CFLAGS) 6 $(OBJS):%.o:%.c (將OBJS中所有擴展名為.o的文件替換成擴展名為.c的文件) 7 $(CC) -c $(CFLAGS) $< -o $@ (生成目標文件) 8 clean: 9 -$(RM) $(TARGET) $(OBJS) - 表示忽略錯誤
Makefile很智能(會自動推導,使用默認的方式生成目標文件),可以再簡化,就可以得到如下形式:
1 CFLAGS = -Isub -Iadd -O2 (O2為優化) 2 OBJS = add_int.o add_float.o sub_int.o sub_float.o main.o 3 TARGET = cacu 4 $(TARGET):$(OBJS) 5 $(CC) -o $(TARGET) $(OBJS) $(CFLAGS) 6 clean: 7 -$(RM) $(TARGET) $(OBJS) - 表示忽略錯誤
Makefile之博大精深,暫時學習到這里(待續)。。。。