Makefile的編寫
開始使用Linux程式設計時,一個很讨厭的問題就是如何寫Makefile檔案,由于在Linux下不像在Windows下那麼熟悉,有那麼多好的軟體(也許是對Linux孤陋寡聞了)。雖然象Kylix和Anjuta這樣的內建編譯環境,但是Kylix太大太慢,用它編寫console程式不亞于高射炮打蚊子——大材小用,而Anjuta又太不穩定,況且字型有那麼難看。不說了,還是言歸正傳,看看Makefile該如何編寫。
1. 簡單的GCC文法:
如果你隻有一個檔案(或者隻有幾個檔案),那麼就可以不寫Makefile檔案(當然有Makefile更加友善),用gcc直接編譯就行了。在這裡我們隻介紹幾個我經常用的幾個參數,第一是 “-o”,它後面的參數表示要輸出的目标檔案,再一個是 “-c”,表示僅編譯(Compile),不連接配接(Make),如果沒有”-c”參數,那麼就表示連接配接,如下面的幾個指令:
gcc –c test.c,表示隻編譯test.c檔案,成功時輸出目标檔案test.o
gcc –c test.c –o test.o ,與上一條指令完全相同
gcc –o test test.o,将test.o連接配接成可執行的二進制檔案test
gcc –o test test.c,将test.c編譯并連接配接成可執行的二進制檔案test
gcc test.c –o test,與上一條指令相同
gcc –c test1.c,隻編譯test1.c,成功時輸出目标檔案test1.o
gcc –c test2.c,隻編譯test2.c,成功時輸出目标檔案test2.o
gcc –o test test1.o test2.o,将test1.o和test2.o連接配接為可執行的二進制檔案test
gcc –c test test1.c test2.c,将test1.o和test2.o編譯并連接配接為可執行的二進制檔案test
注:如果你想編譯cpp檔案,那麼請用g++,否則會有類似如下莫名其妙的錯誤:
cc3r3i2U.o(.eh_frame+0x12): undefined reference to `__gxx_personality_v0’......
還有一個參數是”-l”參數,與之緊緊相連的是表示連接配接時所要的連結庫,比如多線程,如果你使用了pthread_create函數,那麼你就應該在編譯語句的最後加上”-lpthread”,”-l”表示連接配接,”pthread”表示要連接配接的庫,注意他們在這裡要連在一起寫,還有比如你使用了光标庫curses,那麼呢就應該在後面加上”-lcurses”,比如下面的寫法:
gcc –o test test1.o test2.o –lpthread –lcurses
當然gcc的參數我感覺有幾百個,不過我們平時在x86機器上用的就這麼些,況且這裡也不是GCC教程,是以,就此打住。
2. Makefile基本文法
我這裡沒有Makefile的詳細設計書,隻是憑着看别人的Makefile檔案和一些網上的參考資料,作一些簡單的介紹(我自己了解的,不對的地方還請各位老大們指出,鄙人将不甚感激)
2.1 目标:
大家在看别人使用Makefile檔案時肯定經常見到有的人常用make all, make install, make clean等指令,同樣隻有一個Makefile檔案,那麼all、install、clean參數是如何控制Makefile檔案的運作呢(這句話有問題,但我不知道該怎麼說,大家能看懂我的意思,就放我一馬吧)?在這裡,如果向上面的指令如果能夠正确運作的話,那麼在Makefile檔案裡一定有這樣的幾行,他們的開始一定是
all: ×××××××
×××××××××××
install: ××××××
×××××××××××
clean: ×××××××××
×××××××××××
當然也不盡然,因為all,install,clean我們可以用其他的變量來代替,但是着了我們就簡單起見,就下定論了,各位别怪。
在上面提到的all,install,clean等就是我們所說的目标。make all指令,就告訴make我們将執行all所指定的目标。為了便于了解Make程式的流程,我們給大家看一個與gcc毫無關系的Makefile檔案:
# #表示Makefile檔案中的注釋,下面是Makefile檔案的具體内容
all:
@echo you have typed command “make all”
clean:
@echo you have typed command “make clean”
install:
@ehco you have typed command “make
$@”
#Makefile檔案結束
注意在這裡,all:、clean:、install:行要頂格些,而所有的@echo前要加tab鍵來跳格縮進。下面是運作結果:
[[email protected] test]#cat Makefile
# #表示Makefile檔案中的注釋,下面是Makefile檔案的具體内容
all:
@echo you have typed command “make all”
clean:
@echo you have typed command “make clean”
install:
@ehco you have typed command “make
$@”
[[email protected] test]#make all
you have typed command “make all”
[[email protected] test]#make clean
you have typed command “make clean”
[[email protected] test]#make
installyou have typed command “make
install”
[[email protected] test]#
不知大家注意到沒有,我們在Makefile檔案裡有一個符号
$@,其中$表示變量名,其後的要當作變量來解釋,$@是Makefile預先定義的一個變量,表示目标指令,比如在上面的檔案裡屬于install目标,那麼$@就表示install,同樣,如果你将clean目标下面的加引号的”make clean”換為:”make $@”,那麼指令make clean的輸出與原來是一摸一樣的。大家可以下來試試。
2.2 依賴
我們現在提出這樣一個問題:我如何用一個make指令将替代所有的make all, make install,make clean指令呢?當然我們可以象剛才那樣寫一個Makefile檔案:
[[email protected] test]#cat Makefile
# #表示Makefile檔案中的注釋,下面是Makefile檔案的具體内容
all:
@echo you have typed command “make all”
clean:
@echo you have typed command “make clean”
install:
@ehco you have typed command “make
$@”
doall:
@echo you have typed command “make
$@l”
@echo you have typed command “make all”
@echo you have typed command “make clean”
@ehco you have typed command “make
install”
[[email protected] test]#make doall
you have typed command “make
doall”
you have typed command “make all”
you have typed command “make clean”
you have typed command “make
install”
[[email protected] test]#
在這裡,doall:目标有4調語句,他們都是連在一起并都是由tab鍵開始的。當然,這樣能夠完成任務,但是太笨了,我們這樣來寫:
[[email protected] test]#cat Makefile
# #表示Makefile檔案中的注釋,下面是Makefile檔案的具體内容
all:
@echo you have typed command “make all”
clean:
@echo you have typed command “make clean”
install:
@ehco you have typed command “make
$@”
doall: all clean install
@echo you have typed command “make
$@l”
[[email protected] test]#make doall
you have typed command “make all”
you have typed command “make clean”
you have typed command “make
install”
you have typed command “make
doall”
[[email protected] test]#
相信大家已經看清了doall:的運作方式,它先運作all目标,然後運作clean目标,然後是install,最後是自己本身的目标,并且每個$@還是保持着各自的目标名稱。
在這裡,我們稱all, clean, install為目标doall所依賴的目标,簡稱為doall的依賴。也就是你要執行doall,請先執行他們(all, clean, install),最後在執行我的代碼。
注意依賴一定是Makefile裡面的目标,否則你非要運作,結局是注定的:
[[email protected] test]#cat Makefile
all:
@echo you have typed command “make all”
xxx: all WAHAHA:
[[email protected] test]make xxx
you have typed command “make all”
make: *** No rule to make target ‘WAHAHA’, needed by `xxx’,
Stop.
【輕松一下】我們能否利于“互相依賴”來作弄一下make?
[[email protected] test]#cat Makefile
tar1: tar2
tar2: tar1
@echo this line cann’t be shown on you screen!
[[email protected] test]make tar1
make: Circular tar2 <- tar1 dependency dropped.
呵呵,騙不了的
3.實戰:
有了上面的說明,我們就可以開始寫一些弱智一些地Makefile檔案了。比如我們有如下的檔案:
tmp/
+---- include/
| +---- f1.h
| +----f2.h
+----f1.c
+----f2.c
+---main.c
其中f1.c中#include “include/f1.h”,f2.c中#include”include/f2.h”,main.c中又#include”include/f1.h”, #include”include/f2.h”,主函數在main.c中,要将他們聯合起來編譯為目标為testmf的檔案,我們就可以按下面的方式寫(當然是弱智的):
[[email protected] test]#cat Makefile
main: main.o f1.o f2.o
gcc –o testmf main.o f1.o f2.o
f1.o: f1.c
gcc –c –o file1.o file1.c
f2.o: f2.c
gcc –c –o file2.o file2.c
main.o
gcc –c –o main.o main.c
clean:
rm –rf f1.o f2.o main.o testmf
[[email protected] test]make
gcc –c –o main.o main.c
gcc –c –o file1.o file1.c
gcc –c –o file2.o file2.c
gcc –o testmf main.o f1.o f2.o
[[email protected] test]ls
f1.c
f1.of2.c
f2.omain.c
main.oinclude/ testmf
如果你的程式沒有問題的話,就應該可以執行了./testmf
大家可能發現問題了:對目标檔案f1.o f2.o和main.o,他們的寫法是如此的類似,我們能夠将他們一塊寫?有的,不過今天沒時間了,以後再寫吧。