?? makefile編寫.txt
字號:
c 也會被推導出來,于是,我們的makefile再也不用寫得這么復雜。我們的是新的makefi
le又出爐了。
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
.PHONY : clean
clean :
rm edit $(objects)
這種方法,也就是make的“隱晦規則”。上面文件內容中,“.PHONY”表示,clean是個偽
目標文件。
2006-12-8 17:11 #1
ReTurner.D
版主
精華 31
積分 917
帖子 1756
水位 2750
技術分 92
來自 江蘇鹽城
狀態 離線 六、另類風格的makefile
即然我們的make可以自動推導命令,那么我看到那堆[.o]和[.h]的依賴就有點不爽,那么
多的重復的[.h],能不能把其收攏起來,好吧,沒有問題,這個對于make來說很容易,誰
叫它提供了自動推導命令和文件的功能呢?來看看最新風格的makefile吧。
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
.PHONY : clean
clean :
rm edit $(objects)
這種風格,讓我們的makefile變得很簡單,但我們的文件依賴關系就顯得有點凌亂了。魚
和熊掌不可兼得。還看你的喜好了。我是不喜歡這種風格的,一是文件的依賴關系看不清
楚,二是如果文件一多,要加入幾個新的.o文件,那就理不清楚了。
七、清空目標文件的規則
每個Makefile中都應該寫一個清空目標文件(.o和執行文件)的規則,這不僅便于重編譯
,也很利于保持文件的清潔。這是一個“修養”(呵呵,還記得我的《編程修養》嗎)。
一般的風格都是:
clean:
rm edit $(objects)
更為穩健的做法是:
.PHONY : clean
clean :
-rm edit $(objects)
前面說過,.PHONY意思表示clean是一個“偽目標”,。而在rm命令前面加了一個小減號的
意思就是,也許某些文件出現問題,但不要管,繼續做后面的事。當然,clean的規則不要
放在文件的開頭,不然,這就會變成make的默認目標,相信誰也不愿意這樣。不成文的規
矩是——“clean從來都是放在文件的最后”。
上面就是一個makefile的概貌,也是makefile的基礎,下面還有很多makefile的相關細節
,準備好了嗎?準備好了就來。
Makefile 總述
———————
一、Makefile里有什么?
Makefile里主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和注釋。
1、顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由Makefile的書寫
者明顯指出,要生成的文件,文件的依賴文件,生成的命令。
2、隱晦規則。由于我們的make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地
簡略地書寫Makefile,這是由make所支持的。
3、變量的定義。在Makefile中我們要定義一系列的變量,變量一般都是字符串,這個有點
你C語言中的宏,當Makefile被執行時,其中的變量都會被擴展到相應的引用位置上。
4、文件指示。其包括了三個部分,一個是在一個Makefile中引用另一個Makefile,就像C
語言中的include一樣;另一個是指根據某些情況指定Makefile中的有效部分,就像C語言
中的預編譯#if一樣;還有就是定義一個多行的命令。有關這一部分的內容,我會在后續的
部分中講述。
5、注釋。Makefile中只有行注釋,和UNIX的Shell腳本一樣,其注釋是用“#”字符,這個
就像C/C++中的“//”一樣。如果你要在你的Makefile中使用“#”字符,可以用反斜框進
行轉義,如:“\#”。
最后,還值得一提的是,在Makefile中的命令,必須要以[Tab]鍵開始。
二、Makefile的文件名
默認的情況下,make命令會在當前目錄下按順序找尋文件名為“GNUmakefile”、“makef
ile”、“Makefile”的文件,找到了解釋這個文件。在這三個文件名中,最好使用“Mak
efile”這個文件名,因為,這個文件名第一個字符為大寫,這樣有一種顯目的感覺。最好
不要用“GNUmakefile”,這個文件是GNU的make識別的。有另外一些make只對全小寫的“
makefile”文件名敏感,但是基本上來說,大多數的make都支持“makefile”和“Makefi
le”這兩種默認文件名。
當然,你可以使用別的文件名來書寫Makefile,比如:“Make.Linux”,“Make.Solaris
”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file
”參數,如:make -f Make.Linux或make --file Make.AIX。
三、引用其它的Makefile
在Makefile使用include關鍵字可以把別的Makefile包含進來,這很像C語言的#include,
被包含的文件會原模原樣的放在當前文件的包含位置。include的語法是:
include <filename>
filename可以是當前操作系統Shell的文件模式(可以保含路徑和通配符)
在include前面可以有一些空字符,但是絕不能是[Tab]鍵開始。include和<filename>可以
用一個或多個空格隔開。舉個例子,你有這樣幾個Makefile:a.mk、b.mk、c.mk,還有一
個文件叫foo.make,以及一個變量$(bar),其包含了e.mk和f.mk,那么,下面的語句:
include foo.make *.mk $(bar)
等價于:
include foo.make a.mk b.mk c.mk e.mk f.mk
make命令開始時,會把找尋include所指出的其它Makefile,并把其內容安置在當前的位置
。就好像C/C++的#include指令一樣。如果文件都沒有指定絕對路徑或是相對路徑的話,m
ake會在當前目錄下首先尋找,如果當前目錄下沒有找到,那么,make還會在下面的幾個目
錄下找:
1、如果make執行時,有“-I”或“--include-dir”參數,那么make就會在這個參數
所指定的目錄下去尋找。
2、如果目錄<prefix>/include(一般是:/usr/local/bin或/usr/include)存在的話
,make也會去找。
如果有文件沒有找到的話,make會生成一條警告信息,但不會馬上出現致命錯誤。它會繼
續載入其它的文件,一旦完成makefile的讀取,make會再重試這些沒有找到,或是不能讀
取的文件,如果還是不行,make才會出現一條致命信息。如果你想讓make不理那些無法讀
取的文件,而繼續執行,你可以在include前加一個減號“-”。如:
-include <filename>
其表示,無論include過程中出現什么錯誤,都不要報錯繼續執行。和其它版本make兼
容的相關命令是sinclude,其作用和這一個是一樣的。
四、環境變量 MAKEFILES
如果你的當前環境中定義了環境變量MAKEFILES,那么,make會把這個變量中的值做一個類
似于include的動作。這個變量中的值是其它的Makefile,用空格分隔。只是,它和inclu
de不同的是,從這個環境變中引入的Makefile的“目標”不會起作用,如果環境變量中定
義的文件發現錯誤,make也會不理。
但是在這里我還是建議不要使用這個環境變量,因為只要這個變量一被定義,那么當你使
用make時,所有的Makefile都會受到它的影響,這絕不是你想看到的。在這里提這個事,
只是為了告訴大家,也許有時候你的Makefile出現了怪事,那么你可以看看當前環境中有
沒有定義這個變量。
五、make的工作方式
GNU的make工作時的執行步驟入下:(想來其它的make也是類似)
1、讀入所有的Makefile。
2、讀入被include的其它Makefile。
3、初始化文件中的變量。
4、推導隱晦規則,并分析所有規則。
5、為所有的目標文件創建依賴關系鏈。
6、根據依賴關系,決定哪些目標要重新生成。
7、執行生成命令。
1-5步為第一個階段,6-7為第二個階段。第一個階段中,如果定義的變量被使用了,那么
,make會把其展開在使用的位置。但make并不會完全馬上展開,make使用的是拖延戰術,
如果變量出現在依賴關系的規則中,那么僅當這條依賴被決定要使用了,變量才會在其內
部展開。
當然,這個工作方式你不一定要清楚,但是知道這個方式你也會對make更為熟悉。有了這
個基礎,后續部分也就容易看懂了。
書寫規則
————
規則包含兩個部分,一個是依賴關系,一個是生成目標的方法。
在Makefile中,規則的順序是很重要的,因為,Makefile中只應該有一個最終目標,其它
的目標都是被這個目標所連帶出來的,所以一定要讓make知道你的最終目標是什么。一般
來說,定義在Makefile中的目標可能會有很多,但是第一條規則中的目標將被確立為最終
的目標。如果第一條規則中的目標有很多個,那么,第一個目標會成為最終的目標。make
所完成的也就是這個目標。
好了,還是讓我們來看一看如何書寫規則。
一、規則舉例
foo.o : foo.c defs.h # foo模塊
cc -c -g foo.c
看到這個例子,各位應該不是很陌生了,前面也已說過,foo.o是我們的目標,foo.c和de
fs.h是目標所依賴的源文件,而只有一個命令“cc -c -g foo.c”(以Tab鍵開頭)。這個
規則告訴我們兩件事:
1、文件的依賴關系,foo.o依賴于foo.c和defs.h的文件,如果foo.c和defs.h的文件
日期要比foo.o文件日期要新,或是foo.o不存在,那么依賴關系發生。
2、如果生成(或更新)foo.o文件。也就是那個cc命令,其說明了,如何生成foo.o這
個文件。(當然foo.c文件include了defs.h文件)
二、規則的語法
targets : prerequisites
command
...
或是這樣:
targets : prerequisites ; command
command
...
targets是文件名,以空格分開,可以使用通配符。一般來說,我們的目標基本上是一個文
件,但也有可能是多個文件。
command是命令行,如果其不與“target:prerequisites”在一行,那么,必須以[Tab鍵]
開頭,如果和prerequisites在一行,那么可以用分號做為分隔。(見上)
prerequisites也就是目標所依賴的文件(或依賴目標)。如果其中的某個文件要比目標文
件要新,那么,目標就被認為是“過時的”,被認為是需要重生成的。這個在前面已經講
過了。
如果命令太長,你可以使用反斜框(‘\’)作為換行符。make對一行上有多少個字符沒有
限制。規則告訴make兩件事,文件的依賴關系和如何成成目標文件。
一般來說,make會以UNIX的標準Shell,也就是/bin/sh來執行命令。
三、在規則中使用通配符
如果我們想定義一系列比較類似的文件,我們很自然地就想起使用通配符。make支持三各
通配符:“*”,“?”和“[...]”。這是和Unix的B-Shell是相同的。
波浪號(“~”)字符在文件名中也有比較特殊的用途。如果是“~/test”,這就表示當前
用戶的$HOME目錄下的test目錄。而“~hchen/test”則表示用戶hchen的宿主目錄下的tes
t目錄。(這些都是Unix下的小知識了,make也支持)而在Windows或是MS-DOS下,用戶沒
有宿主目錄,那么波浪號所指的目錄則根據環境變量“HOME”而定。
通配符代替了你一系列的文件,如“*.c”表示所以后綴為c的文件。一個需要我們注意的
是,如果我們的文件名中有通配符,如:“*”,那么可以用轉義字符“\”,如“\*”來
表示真實的“*”字符,而不是任意長度的字符串。
好吧,還是先來看幾個例子吧:
clean:
rm -f *.o
上面這個例子我不不多說了,這是操作系統Shell所支持的通配符。這是在命令中的通
配符。
print: *.c
lpr -p $?
touch print
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -