總結下邊的內容 :
- 文件中的第一個target是最終目標
- 命令列表中的每條命令必須以 Tab 開頭
- 如果 prerequistes 中如果有一個以上的文件比 target 文件更新的話,command 所定義的命令就會執行,這就是 Makefile 規則
- 如果這個工程的頭文件改變了,那么我們需要編譯引用了這個頭文件的C文件,並鏈接目標程序。
- make clean 執行刪除文件和所有中間文件。這里要說明,clean, 類似C語言中的 label一樣,其冒號后什么也沒有,那么,make就不會自動去找文件的依賴性,也就不會自動執行其后所定義的命令,要執行其后的命令,就要在make命令后明顯得指出這個label的名字,這樣的方法非常有用,我們可以在一個makefile中定義不用的編譯或和編譯無關的命令,比如程序的打包,程序的備份.
- make 會比較 targets 文件和 prerequisits 文件的修改日期,如果 prerequistes 文件的日期要比 targets文件的日期新,或者 target不存在的話,那么,make就會執行后續定義的命令.
- make 會一層一層的找文件的依賴關系。知道編譯出第一個目標文件。如果在找的過程中,出現問題,那么make 就會自動退出,並報錯。但是make只管文件依賴性,比如,編譯錯誤等等問題,make根本不理。即,如果在我找了依賴關系之后,冒號后面的文件還是不在,那我就不工作了。
- 自動推到 只要 make 看到一個.o 文件,它就會自動的把 .c 文件加載依賴關系中。所以不需要我們自己指定. 如果一個目標在 Makefile 中的所有規則都沒有零零列表,make會嘗試在內建的隱含規則 ( Implicit Rule) 數據庫中查找適用的規則,所以才會有如下例子中,哪些沒有被指定的命令,只是指定了規則的,會執行隱含規則 gcc -c main.c 例如
- all : ( 表示缺省的目標,就是最后目標啦,跟clean,是大家約定俗成的 )
- @echo 正在編譯 XXX 模塊, 當我們用 “@”字符在命令行前,那么,這個命令將不被make顯示出來。這個例子,當make執行時,會輸出”正在編譯 XXX 模塊”,但不會輸出命令
例子:
# This is a temple makefile ( comment )
all : main
main : main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main.o : main.h stack.h maze.h
stack.o : stack.h main.h
maze.o : maze.h main.h
.PHONY : clean
clean :
@echo "cleanning project"
-rm main *.o
@echo "clean completed"
Makefile 不需要任何文件擴展名,只需要用 vi Makefile,編輯就可以了。
除了Hello World 這種極為簡單的程序之外,一般的程序都是由多個源文件編譯鏈接而成的,這些源文件的處理通常用 Makefile 來管理。
多個文件編譯時,如果一個文件需要修改,例如有3個源文件, gcc main.c stack.c maze.c –o main 如果編譯之后又對 maze.c做了修改,又要把所有的源文件編譯一遍,即使 main.c stack.c 和那些頭文件都沒有修改也要跟着重新編譯。(還記的以前不,只要你的文件中加入了新修改的文件的頭文件,即有 #include “maze.h”, 那么就要跟着重新編譯),一個大型的軟件項目往往由上千個源文件組成,全部編譯一遍要幾個小時,而且,只改一個源文件就要求全部重新編譯肯定是不合理的。
寫一個makefile文件和源代碼放在同一個目錄下: ( 使用 Makefile 做文件名 )
makefile文件
然后,在這個目錄下運行 make 編譯
make
gcc –c main.c
gcc –c stack.c
gcc –c maze.c
gcc main.o stack.o maze.o –o main
make命令會自動讀取當前目錄下的Makefile文件,完成相應編譯步驟,Makefile由一組規則組成,每條格式為:
target : prerequistes
command1
command2
例如:
main: main.o stack.o maze.o
gcc main.o stack.o maze.o –o main
目標和條件之間的關系是,欲更新目標,必須首先更新它的所有條件,所有條件中只要有一個條件被更新了,目標也必須隨之被更新,所謂“更新”就是執行一遍規則中的命令列表,命令列表中的每條命令必須以一個 Tab開頭,注意不能是空格,Makefile的格式不像C語言的縮進那么隨意,對於Makefile中的每個以Tab開頭的命令,make會創建一個Shell進程去執行它。
如果 prerequistes 中如果有一個以上的文件比 target 文件更新的話,command 所定義的命令就會執行,這就是Makefile的規則,也是Makefile最核心的內容。
總體規則
1)如果這個過程沒有編譯過,那么我們的所有C文件都要編譯並被鏈接。
2)如果這個工程的某幾個C文件被修改,那么我們只編譯被修改的C文件,並列接目標程序。
3)如果這個工程的頭文件被改變了,那么我們需要編譯引用了這幾個頭文件的C文件,並鏈接目標程序。
只要我們Makefile學的好,所有這一切,只用一個make命令就可以完成。
以上的 Makefile 格式可以稍微調整,比如 ( 可以修改的更格式清楚一點 )
main: main.o stack.o maze.o
gcc main.o maze.o stack.o –o main
main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h
.PHONY : clean
clean:
-rm main *.o
.PHONY: clean ( 表示 clean 是個偽目標文件 )
其中的,clean是刪除多余文件。
#號在 Makefile中時注釋。
make 執行編譯
make clean 執行刪除執行文件和所有的中間目標文件。
make 會比較 targets 文件和 prerequisits 文件的修改日期,如果 prerequistes 文件的日期要比 targets文件的日期新,或者 target不存在的話,那么,make就會執行后續定義的命令.
這里要說明,clean, 類似C語言中的 label一樣,其冒號后什么也沒有,那么,make就不會自動去找文件的依賴性,也就不會自動執行其后所定義的命令,要執行其后的命令,就要在make命令后明顯得指出這個label的名字,這樣的方法非常有用,我們可以在一個makefile中定義不用的編譯或和編譯無關的命令,比如程序的打包,程序的備份。
注意, Makefile中的第一個 target 一定是最終目標,比如最后的可執行程序。
make 會一層一層的找文件的依賴關系。知道編譯出第一個目標文件。如果在找的過程中,出現問題,那么make 就會自動退出,並報錯。但是make只管文件依賴性,比如,編譯錯誤等等問題,make根本不理。即,如果在我找了依賴關系之后,冒號后面的文件還是不在,那我就不工作了。
變量
變量類似間接引用,比如我們有很多 .o 文件,當我們修改時,可能需要在Makefile中的很多地方都要修改,如果Makefile很大時,維護困難,但是如果我們將所有的.o文件保存在一個變量中,例如obj這個變量中,那么只要在Makefile中的一個地方修改,就可以實現全部修改。
obj = main.o kdb.o command.o display.o \ ( 這個反斜杠是換行 )
insert.o search.o files.o utils.o
這樣的話,比如,你想增加一個.o文件,那么只需要在這個地方增加就可以了。
在Makefile后邊,格式為
edit : $(obj) 在Makefile中 其實就是使用 shell 腳本,shell腳本中 $(obj) 是變量
edit : $(obj)
cc –o edit $(obj )
這樣就簡單多了。
自動推到
只要 make 看到一個.o 文件,它就會自動的把 .c 文件加載依賴關系中。所以不需要我們自己指定。類似上邊的
main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h
簡單風格 Makefile
objects = main.o kdb.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc –o edit $(objects)
$(objects): defs.h ( 全部需要引用這個頭文件 )
kdb.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
.PHONY : clean
clean :
rm edit $( objects) //刪除全部編譯文件,目的是,如果有問題,重新編譯
// 當然需要刪除以前編譯過的文件
這種簡單的風格,Makefile便的簡單了。但是依賴關系變的有點凌亂了。沒辦法,魚和熊掌不能兼得。
還是好的依賴關系比較好吧。畢竟程序都不打。頂多幾個~10幾個文件而已。
clean 都是放在文件的最后,好的風格。
.PHONY : clean
clean :
-rm edit $(objects)
Makefile總述
Makefile中 主要包括 5 個東西: 顯示規則,隱晦規則,變量定義,文件指示,注釋
1)顯示規則說明了,文件的依賴和生成的命令
2)隱晦規則,由於make有自動推到功能,可以方便我們比較粗略的寫Makefile
3)變量定義,間接,有點類似C語言中的宏
4)文件指示,包括 3 點
- 在一個Makefile中引用另一個Makefile,有點像C中的 #include
- 根據情況制定Makefile的有效部分,有點類似C中的 #if
- 定義多行命令
5)注釋,#號表示注釋,如果要用這個符號,可以使用”\#”轉義
文件名: Makefile 也可以使用 Make.linux 等等,不過在使用make命令時,要加上 make –f Make.linux
@echo 正在編譯 XXX 模塊, 當我們用 “@”字符在命令行前,那么,這個命令將不被make顯示出來。這個例子,當make執行時,會輸出”正在編譯 XXX 模塊”,但不會輸出命令。
all : ( 表示缺省的目標,就是最后目標啦,跟clean,是大家約定俗成的 )
標准
