Linux下C++的通用Makefile與解析
本文給出萬能Makefile的具體實現,以及對其中的關鍵點進行解析。所謂C++萬能Makefile,即可編譯連結所有的C++程式,而只需作很少的修改。
號稱萬能Makefile,一統江湖。我對原版的Makefile做了些修改。首先揭開它的廬山真面目:
# Generic makefile - 萬能Makefile
# for compiling and linking C++ projects on Linux
# Author: George Foot Modified:Jackie Lee
### Customising
#
# Adjust the following if necessary; EXECUTABLE is the target
# executable‘s filename, and LIBS is a list of libraries to link in
# (e。g。 alleg, stdcx, iostr, etc)。 You can override these on make’s
# command line of course, if you prefer to do it that way。
#
#
EXECUTABLE := main # 可執行檔名
LIBDIR:= # 靜態庫目錄
LIBS := # 靜 態 庫 文 件 名
INCLUDES:=。 # 標頭檔案目錄
SRCDIR:= # 除了當前目錄外,其他的原始碼檔案目錄
#
# # Now alter any implicit rules‘ variables if you like, e。g。:
CC:=g++
CFLAGS := -g -Wall -O3
CPPFLAGS := $(CFLAGS)
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD
#
# # The next bit checks to see whether rm is in your djgpp bin
# # directory; if not it uses del instead, but this can cause (harmless)
# # `File not found’ error messages。 If you are not using DOS at all,
# # set the variable to something which will unquestioningly remove
# # files。
#
RM-F := rm -f
# # You shouldn‘t need to change anything below this point。
#
SRCS := $(wildcard *。cpp) $(wildcard $(addsuffix /*。cpp, $(SRCDIR)))
OBJS := $(patsubst %。cpp,%。o,$(SRCS))
DEPS := $(patsubst %。o,%。d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %。d,%。cpp,$(MISSING_DEPS)))
。PHONY : all deps objs clean veryclean rebuild info
all: $(EXECUTABLE)
deps : $(DEPS)
objs : $(OBJS)
clean :
@$(RM-F) *。o
@$(RM-F) *。d
veryclean: clean
@$(RM-F) $(EXECUTABLE)
rebuild: veryclean all
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
@$(RM-F) $(patsubst %。d,%。o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))
info:
@echo $(SRCS)
@echo $(OBJS)
@echo $(DEPS)
@echo $(MISSING_DEPS)
@echo $(MISSING_DEPS_SOURCES)
注:1)命令列前的空白符必須為一個製表符(Tab);如,@$(RM-F) *。o前不是空格,而是一個製表符;
內容解析
1。Makefile基本語法
target為要生成的目標檔案;dependency為target的依賴檔案;command為用於生成target的命令列;
(tab)
(tab)
。
。
。
2。賦值符號 := 與 =
:=與=的區別在於,符號:=表示立即展開變數值。例如:
A:=foo
B:=$(A)
A:=bar
這時,B的值仍為foo,因為它已被展開,不會再隨A的值改變而改變。
3。符號#是Makefile的註釋符號
4。wildcard函式
SRCS:=$(wildcard *。cpp) 表示列舉當前目錄中副檔名為。cpp的所有檔案,然後賦值給變數SRCS。詳細請google之。
5。patsubst函式
OBJS := $(patsubst %。cpp,%。o,$(SRCS))表示,將$(SRCS)中所有滿足模式%。cpp的字串替換為%。o。
6。filter-out函式
$(filter-out $(A),$(B))表示從B中過濾掉A中的內容,返回剩餘內容;
7。 “。PHONY”
用。PHONY修飾的target是“偽目標”,不需要生成真實的檔案;make假定phony target是已經生成的,然後更新它後邊的依賴檔案和執行它下邊的命令(command);
8。all deps objs clean veryclean rebuild info
這些都是“偽目標”。
all是第一個目標,所以輸入make時它被預設執行;all生成或更新所有*。cpp檔案對應的*。d檔案和*。o檔案,並連結所有*。o檔案生成可執行檔案$(EXECUTABLE)。
deps僅僅生成*。d檔案;。d檔案是什麼檔案?它包含了程式碼檔案的依賴資訊。
objs僅僅生成*。o檔案;。o檔案是C++程式碼編譯後的中間結果檔案,廢話!
clean用於刪除*。d檔案和*。o檔案。
veryclean刪除*。d檔案、*。o檔案,還有名為$(EXECUTABLE)的可執行檔案。
rebuild先呼叫veryclean清除結果檔案,再呼叫all重新編譯和連結。
info檢視某些資訊。
使用方法:
make deps即可執行deps;
9。ifneq。。。else。。。endif
條件語句,ifneq表示如果不想等,則。。。;
10。include
include表示把
$(DEPS)是包含依賴資訊的檔案,每個原始檔對應一個。d檔案;-include $(DEPS)表示把這些依賴資訊包含進來;
11。連結*。o檔案,生成可執行檔案
主菜來了!
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))
$(EXECUTABLE)為可執行檔名;$(OBJS)為所有。o檔名;$(CC)在這裡是g++;$(addprefix -l,$(LIBS)新增引用庫;
前面說好的*。d檔案和*。o檔案是怎麼生成的呢?貌似沒有命令指出要生成它們呀!請看隱含規則!
12。 隱含規則(Implicit rules)
$(EXECUTABLE)依賴於$(OBJS),但makefile中沒有指明$(OBJS)依賴於誰,也沒指明命令生成它們;
這時,make的隱含規則開始起作用;針對$(OBJS)中的每個目標,make自動呼叫:
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
依次生成。o檔案和。d檔案;
$<表示依賴檔案列表的第一個檔名;
$@表示目標檔名;
之所以會生成。d檔案,是由於“-MMD”這一編譯選項。為g++加上這一選項後,編譯器會生成檔案依賴資訊,並存放至。d檔案中。
每一個。cpp檔案相應地生成一個。d檔案和一個。o檔案。
13。@符號
命令列前的@符號表示不回顯命令列;
14。CFLAGS和CPPFLAGS
這兩者包含編譯選項,更詳細內容請Google之。
-g 新增gdb除錯資訊;
-Wall 提示warning資訊;
-O3 表示第3級最佳化;