linux編程——makefile檔案
今天我想說說這個makefile檔案了,makefile檔案?原來在windows平台上我還真沒有弄過這個東東,其實也是有的,只是我們沒有接觸到罷了。
makefile檔案,是個什麼東西?有什麼用?怎麼來寫?這就是我要說的。
我們都清楚,用傳統C、C++語言開發一個程式,都要經曆這幾個步驟:編輯——編譯——串連,串連成功就可運行了。在windows平台,這幾個步驟都是在開發工具的協助下自動完成的,所以大家體會不是很深刻。而在linux平台,這個流程需要我們自己來走(這句話說的不是很正確,現在在linux上已經有一些開發工具)。恩,看來makefile檔案與這個流程有關,對,是密切相關。
我們舉個例子,在linux終端上列印個“hello world!”。
我的機子上是redhat9.0,編譯器使用g++3.0。
先編輯一個main.cpp檔案,內容如下:
#include <iostream>
int main (int argc, char **argv) {
printf("hello, world!/n");
return 0;
}
編輯好了,應該進行編譯了,從終端進入代碼檔案所在目錄,執行以下這條命令:
#g++ -Wall -o2 -c main.cpp
#號是命令提示字元,關於g++命令的用法和各個參數的意義請大家參考其它書籍,在這裡不對這個做過多說明。
這條命令執行後,目錄中就多了個main.o檔案了,這個檔案的出現說明了很些問題,對於我們開發人員,最關心的一個問題就是:我們的原始碼沒有語法錯誤!如果有語法錯誤,那編譯器就會把錯誤資訊列印到終端視窗上,沒的說,去修改代碼去,修改完了儲存再運行以上命令。
編譯通過了,這可是不小的一步啊,接著就是串連了,執行以下這條命令:
#g++ main.o -o main.exe
這條命令是把main.o串連成mian.exe,在實際項目中,一個可運行檔案要由很多.o檔案和作業系統提供的其他庫檔案一起串連而成,不象我們這裡這麼簡單。這時目錄中會出現一個main.exe檔案,查看該檔案的屬性,可看到它有運行屬性,對了,這就是我們最終想要的可執行檔了。值得注意的是,這裡的main.exe檔案名稱是任意指定的,系統不會因為我們加個exe尾碼就給它賦予運行屬性,也不會因為沒有exe尾碼就隨便取消該有的運行屬性。
好了,運行該檔案:
#./main.exe
斷行符號後就可看到列印到終端上的“hello world!”了。
現在我有一些函數放在另一個檔案中,在main.cpp檔案中要使用這幾個函數,比如說另外的代碼檔案分別為funtion.h和function.cpp檔案,在main.cpp檔案中要包含funtion.h檔案(#include "function.h"),然後
執行以下命令:
#g++ -Wall -o2 -c function.cpp
#g++ -Wall -o2 -c main.cpp
當function.o檔案和main.o檔案都存在時,進行串連
#g++ main.o function.o -o main.exe
現在,新的main.exe檔案就串連好了。
如果funtion.h和function.cpp檔案中的內容有改變,那將要重新編譯funtion.o檔案,依賴funtion.h和function.cpp檔案的main.cpp檔案也需要編譯,串連就更需要做了。很煩人的,如果代碼檔案很多,依賴(包含)關係錯綜複雜,一個檔案被修改了,哪個.o檔案需要重新編譯,執行編譯操作,再串連,這個工作量單調而且乏味,還容易出錯,操作起來不現實。
怎麼辦?看!makefile檔案出現了,呵呵。
makefile檔案是一個shell檔案(linux中的叫法,相當與windows中的批次檔.bat),它記錄了代碼檔案之間這種依賴關係,哪個檔案需要重新編譯是由makefile檔案說了算的。
我們先看一個具體的makefile檔案:
#-----------------------start of makefile------------------------
CC=g++
CFLAGS=-Wall -O2 -g -D __DEBUG__
INCLUDES=-I.
LIBS=-lpthread
OBJS=Thread.o CRC32.o Ts.o TsPacketizer.o utils.o Socket.o PDG.o test_pdg.o
PROG=pdgd
%.o:%.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c $<
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $(LIBS) $(OBJS) -o $(PROG)
clean:
rm -f *.o $(PROG)
install:
cp ./pdgd /usr/sbin/
cp ./pdg_tester /etc/init.d/
chmod +x /etc/init.d/pdg_tester
#-----------------------end of makefile---------------------------
makefile檔案中以“#”開頭的行相當與注釋,不起作用。
大概做一下解釋:
CC=g++ 表示使用的編譯器為g++;
CFLAGS=-Wall -O2 指定編譯行為,-O2表示代碼最佳化程度為中等;-g表示可調試,相當於windows中的debug版本,-D和後面的參數表示定義了一個宏;
INCLUDES=-I. 表示原始碼都放在哪些目錄中,-I.表示本目錄,如果本目錄下還有個soc的目錄,則這句要寫成INCLUDES=-I. -I./soc;
LIBS=-lpthread 表示在串連時使用系統提供的串連庫,上面的工程中引入了多線程,所以要使用系統提供的lpthread串連庫;
OBJS=Thread.o CRC32.o Ts.o TsPacketizer.o utils.o Socket.o PDG.o test_pdg.o
表示我們要編譯的各個.o檔案,如果是我們前面的那個例子,要寫成OBJS=function.o main.o;
PROG=pdgd 指定串連目標檔案名,象我們上面的main.exe一樣;
%.o:%.cpp 表示.o檔案依賴於.cpp檔案,這就是我們那個依賴關係;
$(CC) $(CFLAGS) $(INCLUDES) -c $<
上面這句才是真正進行編譯的語句,在這句前面一定要留有空白(tab鍵或空格),原因是這是一個執行語句,詳細情況我也不是很清楚,不好意思;
$(PROG): $(OBJS) 表示目標檔案依賴於.o檔案;
$(CC) $(LIBS) $(OBJS) -o $(PROG)
這句是串連語句,前面要留空白。
再下面的clean:和install:不是必須的,它們是makefile檔案可有的,稱做標記。
恩,好,那這個檔案如何使用呢?
1、先寫這個檔案,儲存在原始碼所在目錄;
2、執行命令:
#make
斷行符號,哦,很自動的,我們一開始說道的編譯呀,串連呀,都自動做了,上面提到在makefile檔案中有個稱做標記的東東,只輸入make 不會執行任何標記下的語句,如果想執行哪個標記的內容,使用以下命令:
#make 標記名
如上面的:#make clean和#make install。
makefile檔案根據代碼檔案的修改時間和上次編譯時間的時間判定哪個檔案進行了修改,從而決定重新編譯哪個檔案,還有根據依賴關係決定那些檔案雖然沒有被修改但所依賴的檔案被修改而也需要重新進行編譯,所以是又省時又省力,值得採用。
關於makefile檔案我也就會這些了,寫出來大家一起進步。前幾天看到一個系統的makefile檔案,哇塞,嚇我一跳,太複雜了,看來這makefile檔案也是博大精深的,路還長著呢,好好努力吧。