Linux下通用的Makefile

####################################################
# Generic makefile
# for compiling and linking C++ projects on Linux 
####################################################
### 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的命令行;

<target> : <dependency> <dependency> ...
(tab)<command>
(tab)<command>
 .
 .
 .

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 <files>語句

include表示把<files>的內容包含進來;

$(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級優化;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章