本文給出萬能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級最佳化;