Makefile 描述了整個工程中所有文件的編譯順序、編譯規則。而make工具則可以對我們的Makefile規則進行解釋執行。Makefile文件的規則包含了目標文件和依賴文件之間的依賴關係 以及更新此規則 所需要的命令:
目標文件:依賴文件
命令
其中,命令前是Tab不是空格,否則make會報錯。
首先,上一段Hello World的代碼:
/* test.c */
#include <stdio.h>
int main(){
printf("hello world\n");
return 0
}
通常情況下,可以使用GCC對這段代碼進行編譯鏈接:gcc test.c -o test,然後執行./test 即可預期輸出 hello world。 同時,我們也可以通過makefile實現工程的自動化編譯。
test:test.o #依賴關係 1 :目標文件 test,依賴文件是test.o
cc test.o -o test #命令1: 將編譯輸出的test.o文件鏈接成目標可執行文件test
test.o:test.c #依賴關係 2 :目標文件 test.o,依賴文件是test.c
cc -c test.c -o test.o #命令2: 把源文件編譯成二進制目標代碼 test.o
clean: #規則3: 沒有任何依賴關係只有執行命令的目標被稱爲 僞目標
rm test.o test #命令3: 清除編譯生成的所有文件
make命令的方式是:make -f makefile文件名 ,也可以直接執行 make,make工具會默認使用名稱爲makefile或Makefile的文件進行解釋執行。在上述makefile文件中,存在兩個依賴關係,make 會把 第一個規則的目標 當做 整個工程的最終目標,即 test ;同時,make 會比較每一條規則 目標文件 及其依賴文件的修改時間,決定 這條規則的命令是否執行,如本例中當我們修改了 test.c 文件時,make會首先執行命令2去生成test.o 文件,而最終目標文件test 也會因test.o 的修改時間改變而重新鏈接;
多文件的Makefile例子
實際開發過程中,一個項目會包含很多源代碼文件或庫文件。這時候,我們需要對多文件同時進行編譯鏈接,下面是一個多文件Makefile的例子,代碼的目錄結構如下:
├── client.c
├── server.c
├── config.h
└── makefile
具體代碼可見 http://blog.csdn.net/qq524425141/article/details/51340787,針對這個工程,編寫了 Makefile。
all:client server
@echo make completed #編譯完成提示一下,使用"@"防止回顯
client:client.c config.h
gcc client.c -o client
server:server.c config.h
gcc server.c -o server
clean:
rm client server *.o
隨着工程包含編譯文件的增多,編寫Makefile文件變得越來越麻煩,這時候,我們就可以利用make的一些預定義變量和規則簡化makefile。如對於上面的makefile。可以稍作簡化。
all:client server
client:config.h #client的依賴文件雖然沒有指出client.c,但是 make 會進行 自動推導
gcc client.c -o $@ # 預定義變量,$@ 表示規則的目標,常見預定義變量見附錄
server:config.h
gcc server.c -o $@
clean:
rm client server
繼續簡化,最終的Makefile可以簡寫如下:
all:client server
$(all):
cc $^ -o $@ #$^ 表示所有依賴文件
clean:
-rm client server
其中,-rm 是因爲當我們 連續兩次 執行make clean後會報錯,使用-rm 可以忽略錯誤繼續執行。
多目錄下makefile編寫
同樣是上面的例子,目錄結構如下:
├── makefile
├── clientdir
│ ├── client.c
│ └── makefile
├── serverdir
│├── server.c
│└── makefile
我們對client和server程序的Makefile分別進行編譯,然後在上一級目錄編寫總的對這兩個項目同時進行編譯。這三個makefile分別如下:
#./clientdir/makefile
all:client
$(all):
gcc $<-o $@
clean:
-rm client
#./serverdir/makefile
all:server
server:
gcc server.c -o $@
clean:
rm server
all clean:
@for subdir in client server;\
do\
#echo $$subdir;\
if test -d $$subdir;\
then\
echo making $@ in $$subdir;\
(cd $$subdir && make $@) || exit 1;\
fi;\
done
執行make all 或者make即可在相應的目錄下生成目標程序,執行make clean可同時刪除目標。
make中常用的預定義變量
$* 不包含擴展名的目標文件名稱。
$+ 所有的依賴文件,以空格分開,並以出現的先後爲序,可能包含重複的依賴文件。
$< 第一個依賴文件的名稱。
$? 所有的依賴文件,以空格分開,這些依賴文件的修改日期比目標的創建日期晚。
$@ 目標的完整名稱。
$^ 所有的依賴文件,以空格分開,不包含重複的依賴文件。
$% 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱。例如,如果目標名稱爲(image.o),則 $@ 爲 ,而 $% 爲 image.o。
AR 歸檔維護程序的名稱,默認值爲 ar。
ARFLAGS 歸檔維護程序的選項。
AS 彙編程序的名稱,默認值爲 as。
ASFLAGS 彙編程序的選項。
CC C 編譯器的名稱,默認值爲 cc。
CFLAGS C 編譯器的選項。
CPP C 預編譯器的名稱,默認值爲 $(CC) -E。
CPPFLAGS C 預編譯的選項。
CXX C++ 編譯器的名稱,默認值爲 g++。
CXXFLAGS C++ 編譯器的選項。
FC FORTRAN 編譯器的名稱,默認值爲 f77。
FFLAGS FORTRAN 編譯器的選項。