TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)

2007年8月20日 星期一

如何寫作makefile

在Unix系統上編譯tarball時,通常需要三步驟:
./configure
make
make install
這中間的make指令便是利用makefile來處理編譯步驟。
Makefile的概念非常像是批次檔,但是它有更強大的能力。
make會查閱每一步驟所需要的檔案,如果沒有便執行指令以產生該檔案,如果已經是最新狀態,就直接跳到下個步驟。撰寫者只要了解原始碼的編譯步驟,就可以依序寫好指令,如此只要有Makefile,不管是誰只要鍵入make就可以成功編譯出檔案。
以最簡單的單一檔案來說,編譯指令應該如下:
gcc helloworld.c -o helloworld
這樣會把helloworld.c編譯為helloworld這個執行檔。
而若要寫為makefile,可以這麼寫:
all: helloworld
	gcc helloworld.c -o helloworld
檔名存為Makefile或是makefile都可以[?],這就是最簡單的makefile。
上面的意義為,要完成all這個目標,需要helloworld這個檔案,如果找不到它,就執行gcc helloworld.c -o helloworld這個指令。
注意,all是個關鍵字,良好的makefile都要有一個all,因為這是預設執行目標。
且一定要用tab縮排,否則它不會認目標底下的指令。換行符號也請用Unix的換行符。
若是要編譯多個檔案呢?比方說現在有三個檔案:application.c, interface.h, implementation.c,application.c引用了interface.h的函式,而implementation.c則是interface.h的實作。
先來看一下平常編譯該怎麼編:
gcc -c application.c
gcc -c implementation.c
gcc implementation.o application.o -o result
這樣編譯出來的result就是可執行檔。
所以來整理一下:result檔需要implementation.o和application.o這兩個檔案,而這兩個檔案分別需要implementation.c和application.c,如此一來就會變成:
all: result
result: implementation.o application.o
	gcc implementation.o application.o -o result
implementation.o: implementation.c
	gcc -c implementation.c
application.o: application.c
	gcc -c application.c
意即:欲完成all需要先完成result目標,欲完成result需要先完成implementation.o和application.o這兩個目標,而要達成implementation.o和application.o則分別需要implementation.c和application.c這兩個檔案。
你也可以選擇只執行其中一個目標,像是make application.o就只會產生application.o檔。
總而言之,makefile的基本型式是:
target: required file or target
	commands to complete this target
底下不限定有多少行指令,只要有用tab縮排即可。
而且目標也不一定要有前置目標,如果執行的目標沒有前置目標的話,代表目標底下的命令一定會執行。
如果你覺得太長,想省略一點,也可以用萬用符號[?]
all: result
result: *.o
	gcc *.o -o result
*.o: *.c
	gcc -c *.c
這個版本可以跟上面的版本達到相同的效果,不過當然有點危險就是了。
當然不只能用來編譯,也許你會希望能夠有清掉過程檔的功能:
all: result clean
result: *.o
	gcc *.o -o result
*.o: *.c
	gcc -c *.c
clean:
	rm -f *.o
這樣在下完make之後會立刻把所有的.o檔清除,或是也可以用make clean除掉。
也許你在編譯完成之後都會執行一次該程式來測試,那麼也可以這麼寫:
all: result clean
result: *.o
	gcc *.o -o result
*.o: *.c
	gcc -c *.c
clean:
	rm -f *.o
test: result input.txt
	./result <input.txt
如此只要輸入make test就會自動執行測試。
當找不到input.txt時,make會自動停止並回報錯誤,因為文件中找不到如何生成input.txt的資訊。
儘管make沒有明定什麼目標該做什麼事,但是在約定成俗的目標上,請按照慣例:
make all要用來生成所有程式。
make install要用來安裝程式。
make clean要用來清除暫時檔。
其他經常用的目標也請不要逆天。
當然這只是最最簡單的makefile,其他如關鍵字聲明之類的,可以去翻make的文件;而automake這套程式可以幫助你生成大型專案的makefile,不過我笨,不會用(汗)。

沒有留言:

張貼留言