原理 在linux平臺下編譯由多個源碼文件或目錄組成的項目工程時,需要編寫make腳本即Makefile文件來編譯,當項目工程寵大時,這種方式比單純地使用gcc命令行方便快捷,且易于維護。由于具體工程的源碼文件數(shù)量的多少及名稱的不同,因此編寫一個較為通用的Makefile文件,來實現(xiàn)編譯各種不同的工程,具有重要的參考意義和價值。本文展示了通用Makefile.in文件及其應用示例。Makefile.in文件,顧名思義,內(nèi)部實現(xiàn)用的,應由外部具體的Makefile文件提供具體的命令行參數(shù)來調(diào)用,它包括exe,static,share三個規(guī)則目標,因此支持可執(zhí)行文件、動態(tài)庫和靜態(tài)庫三種工程的編譯,而每種工程又支持debug和release兩種版本,默認為release版本,在編譯時會自動創(chuàng)建debug或release目錄來存放所有中間文件*.o和*.d。在其腳本源碼中,詳見下面實現(xiàn),小寫變量為內(nèi)部所有,大寫變量為make命令行提供的參數(shù),目前支持以下幾種命令行參數(shù):
1)輸出名稱:OUT_NAME,對于庫工程,內(nèi)部自動添加lib前綴
2)輸出路徑:OUT_PATH, 末尾反斜杠/可有可無 3)源碼路徑:SRC_PATH, 末尾反斜杠/可有可無 4)依賴動態(tài)庫路徑:SHARE_PATH,不帶庫名稱的路徑, 末尾反斜杠/可有可無 5)依賴動態(tài)庫名稱:SHARE_LIB,不帶庫路徑的名稱,內(nèi)部自動添加-l前綴
6)依賴靜態(tài)庫路徑:STATIC_PATH,不帶庫名稱的路徑, 末尾反斜杠/可有可無 7)依賴靜態(tài)庫路徑:STATIC_LIB,不帶庫路徑的名稱
8)預定義宏:MACROS,內(nèi)部自動添加-D前綴
9)編譯模式:MODE,表示編譯成debug或release版本
關(guān)于頭文件包含的支持,這里沒有提供命令行參數(shù),在內(nèi)部它固定為SRC_PATH、/usr/include和/usr/local/include三個路徑,對于大多數(shù)的工程,應該夠用了。
實現(xiàn)
1
#Makefile.in
2
3
inc_path := $(SRC_PATH) /usr/include /usr/local/include
4
inc_path := $(addprefix -I,$(inc_path))
5
override SHARE_PATH += /usr/lib /usr/local/lib
6
override SHARE_PATH := $(addprefix -L,$(SHARE_PATH))
7
override SHARE_LIB := $(if $(SHARE_LIB),$(addprefix -l,$(SHARE_LIB)))
8
override STATIC_PATH := $(patsubst %/,%,$(STATIC_PATH))
9
override STATIC_LIB := $(if $(STATIC_PATH),$(if $(STATIC_LIB),$(addprefix $(STATIC_PATH)/,$(STATIC_LIB))))
10
override SRC_PATH := $(patsubst %/,%,$(SRC_PATH))
11
override MACROS := $(addprefix -D,$(MACROS))
12
13
cxxflags := -Wall $(MACROS)
14
15
ifeq ($(MODE),debug)
16
cxxflags += -g
17
tmp_path := $(SRC_PATH)/debug
18
else
19
cxxflags += -O2 -DNDEBUG
20
tmp_path := $(SRC_PATH)/release
21
endif
22
23
lib_name := $(addprefix lib,$(OUT_NAME))
24
25
srcs := $(wildcard $(SRC_PATH)/*.c) $(wildcard $(SRC_PATH)/*.cpp)
26
deps := $(patsubst %.c,%.d,$(patsubst %.cpp,%.d,$(srcs)))
27
deps := $(foreach dep,$(deps),$(notdir $(dep)))
28
deps := $(addprefix $(tmp_path)/,$(deps))
29
30
objs := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(srcs)))
31
objs := $(foreach obj,$(objs),$(notdir $(obj)))
32
objs := $(addprefix $(tmp_path)/,$(objs))
33
34
share_name := $(tmp_path)/$(lib_name).so
35
static_name := $(tmp_path)/$(lib_name).a
36
exe_name := $(tmp_path)/$(OUT_NAME)
37
38
override MACROS := $(if $(MACROS),$(addprefix -D,$(MACROS)))
39
40
.PHONY: exe lib static share clean config
41
42
arflags := -rc
43
44
define MKDIR
45
if [ ! -d $(tmp_path) ]; then \
46
mkdir $(tmp_path);\
47
fi
48
endef
49
50
config:
51
@$(MKDIR)
52
53
exe: config $(exe_name)
54
55
lib: config static share
56
57
static: $(static_name)
58
59
share: $(share_name)
60
61
$(exe_name): $(objs)
62
@echo "Linking to execute ($@ : $(objs))."
63
$(CXX) -o $@ $(objs) $(SHARE_PATH) $(SHARE_LIB) $(STATIC_LIB)
64
@cp $(exe_name) $(OUT_PATH)
65
66
$(static_name): $(objs)
67
@echo "Archive to static library ($@ [$(objs)])."
68
$(AR) $(arflags) $@ $(objs)
69
@cp $(static_name) $(OUT_PATH)
70
71
$(share_name): $(objs)
72
@echo "Linking to shared library ($@ [$(objs)])."
73
$(CXX) $(cxxflags) -o $@ $(objs) -fPIC -shared
74
@cp $(share_name) $(OUT_PATH)
75
76
$(tmp_path)/%.o: $(SRC_PATH)/%.cpp $(tmp_path)/%.d
77
@echo "Compile $@ ($<)."
78
$(CXX) $(cxxflags) $(inc_path) -c $< -o $@
79
80
$(tmp_path)/%.d: $(SRC_PATH)/%.cpp
81
@echo "Compile $@ ($<)."
82
$(CXX) $(cxxflags) -MM $< -o $@.$$$$; \
83
sed 's,\($*\)\.o[ :]*,\1.o $@:, g' < $@.$$$$ > $@; \
84
rm -f $@.$$$$
85
86
-include $(deps)
87
88
clean:
89
$(RM) $(objs) $(deps) $(share_name) $(static_name) $(exe_name)
應用
這里假設有兩個源碼子目錄netcomm和server,前者為動態(tài)庫netcomm工程,后者為主程序server工程,它依賴netcomm庫,每個目錄下都有其自己的Makefile,這個用于編譯單個模塊或主程序,它們的父目錄為src,在這個目錄下有兩個Makefile文件,一個是Makefile.in,這個就是上面講到的通用內(nèi)部Makefile;另一個是Makefile,這個用來聯(lián)編所有的模塊和主程序。
先來看下netcomm的Makefile文件內(nèi)容,如下所示
1
path := SRC_PATH=. OUT_PATH=../../output
2
3
.PHONY: all debug release clean
4
5
all: debug release
6
7
debug:
8
$(MAKE) -f ../Makefile.in lib MODE=debug OUT_NAME=netcommd $(path)
9
10
release:
11
$(MAKE) -f ../Makefile.in lib MODE=release OUT_NAME=netcomm $(path)
12
13
clean:
14
$(MAKE) -f ../Makefile.in clean MODE=debug OUT_NAME=netcommd $(path)
15
$(MAKE) -f ../Makefile.in clean MODE=release OUT_NAME=netcomm $(path)
再看下server的Makefile文件內(nèi)容,如下所示
1
macros := MACROS="_USE_MEM_POOL=1"
2
3
path := SRC_PATH=. OUT_PATH=../../output SHARE_PATH=../../output
4
5
.PHONY: all debug release clean
6
7
all: debug release
8
9
debug:
10
$(MAKE) -f ../Makefile.in exe MODE=debug OUT_NAME=serverd SHARE_LIB="netcommd" $(macros) $(path)
11
12
release:
13
$(MAKE) -f ../Makefile.in exe MODE=release OUT_NAME=server SHARE_LIB="netcomm" $(macros) $(path)
14
15
clean:
16
$(MAKE) -f ../Makefile.in clean MODE=debug OUT_NAME=serverd $(path)
17
$(MAKE) -f ../Makefile.in clean MODE=release OUT_NAME=server $(path)
最后看下src的Makefile文件內(nèi)容,如下所示
1
.PHONY: all release debug clean
2
3
all: debug release
4
5
debug:
6
$(MAKE) debug -C netcomm
7
$(MAKE) debug -C server
8
9
release:
10
$(MAKE) release -C netcomm
11
$(MAKE) release -C server
12
13
clean:
14
$(MAKE) clean -C netcomm
15
$(MAKE) clean -C server 以上所有腳本代碼,在make 3.81下測試通過。
posted on 2012-08-16 19:29
春秋十二月 閱讀(3513)
評論(3) 編輯 收藏 引用 所屬分類:
System