这一节我们来研究一下上一节中makefile存在的问题:
第一个问题导致了项目的文件夹不能移动,一旦移动则编译失败。
这样可以使得工程文件夹随意移动。
顶层makefile改动后的部分程序如下:
第35、36行我们通过命令行变量将路径传到模块makefile中,因此,模块makefile中的这两个相应的写死的路径可以删掉了。
模块makefile怎么知道配置文件的位置呢?
工程makefile的重构:
重构后的目录如下:
每个模块下有makefile文件,顶层工程也有一个makefile文件。mod-cfg.mk和mod-rule.mk都是和模块makefile相关的。
顶层makefile:
1 include pro-cfg.mk 2 include cmd-cfg.mk 3 include pro-rule.mk
cmd-cfg.mk:
1 AR := ar 2 ARFLAGS := crs 3 4 CC := gcc 5 LFLAGS := 6 CFLAGS := -I$(DIR_INC) -I$(DIR_COMMON_INC) 7 8 ifeq ($(DEBUG),true) 9 CFLAGS += -g 10 endif 11 12 MKDIR := mkdir 13 RM := rm -fr
pro-cfg.mk:
1 MODULES := common \ 2 module \ 3 main 4 5 MOD_CFG := mod-cfg.mk 6 MOD_RULE := mod-rule.mk 7 CMD_CFG := cmd-cfg.mk 8 9 DIR_BUILD := build 10 DIR_COMMON_INC := common/inc 11 12 APP := app.out
pro-rule.mk:
1 .PHONY : all compile link clean rebuild 2 3 DIR_PROJECT := $(realpath .) 4 DIR_BUILD_SUB := $(addprefix $(DIR_BUILD)/, $(MODULES)) 5 MODULE_LIB := $(addsuffix .a, $(MODULES)) 6 MODULE_LIB := $(addprefix $(DIR_BUILD)/, $(MODULE_LIB)) 7 8 9 APP := $(addprefix $(DIR_BUILD)/, $(APP)) 10 11 all : compile $(APP) 12 @echo "Success! Target ==> $(APP)" 13 14 compile : $(DIR_BUILD) $(DIR_BUILD_SUB) 15 @echo "Begin to compile ..." 16 @set -e; \ 17 for dir in $(MODULES); \ 18 do \ 19 cd $$dir && \ 20 $(MAKE) all \ 21 DEBUG:=$(DEBUG) \ 22 DIR_BUILD:=$(addprefix $(DIR_PROJECT)/, $(DIR_BUILD)) \ 23 DIR_COMMON_INC:=$(addprefix $(DIR_PROJECT)/, $(DIR_COMMON_INC)) \ 24 CMD_CFG:=$(addprefix $(DIR_PROJECT)/, $(CMD_CFG)) \ 25 MOD_CFG:=$(addprefix $(DIR_PROJECT)/, $(MOD_CFG)) \ 26 MOD_RULE:=$(addprefix $(DIR_PROJECT)/, $(MOD_RULE)) && \ 27 cd .. ; \ 28 done 29 @echo "Compile Success!" 30 31 link $(APP) : $(MODULE_LIB) 32 @echo "Begin to link ..." 33 $(CC) -o $(APP) -Xlinker "-(" $^ -Xlinker "-)" $(LFLAGS) 34 @echo "Link Success!" 35 36 $(DIR_BUILD) $(DIR_BUILD_SUB) : 37 $(MKDIR) $@ 38 39 clean : 40 @echo "Begin to clean ..." 41 $(RM) $(DIR_BUILD) 42 @echo "Clean Success!" 43 44 rebuild : clean all
模块相关的文件:
mod-cfg.mk:
1 DIR_SRC := src 2 DIR_INC := inc 3 4 TYPE_INC := .h 5 TYPE_SRC := .c 6 TYPE_OBJ := .o 7 TYPE_DEP := .dep
mode-rule.mk:
1 .PHONY : all 2 3 MODULE := $(realpath .) 4 MODULE := $(notdir $(MODULE)) 5 DIR_OUTPUT := $(addprefix $(DIR_BUILD)/, $(MODULE)) 6 7 OUTPUT := $(MODULE).a 8 OUTPUT := $(addprefix $(DIR_BUILD)/, $(OUTPUT)) 9 10 SRCS := $(wildcard $(DIR_SRC)/*$(TYPE_SRC)) 11 OBJS := $(SRCS:$(TYPE_SRC)=$(TYPE_OBJ)) 12 OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_OUTPUT)/%, $(OBJS)) 13 DEPS := $(SRCS:$(TYPE_SRC)=$(TYPE_DEP)) 14 DEPS := $(patsubst $(DIR_SRC)/%, $(DIR_OUTPUT)/%, $(DEPS)) 15 16 vpath %$(TYPE_INC) $(DIR_INC) 17 vpath %$(TYPE_INC) $(DIR_COMMON_INC) 18 vpath %$(TYPE_SRC) $(DIR_SRC) 19 20 -include $(DEPS) 21 22 all : $(OUTPUT) 23 @echo "Success! Target ==> $(OUTPUT)" 24 25 $(OUTPUT) : $(OBJS) 26 $(AR) $(ARFLAGS) $@ $^ 27 28 $(DIR_OUTPUT)/%$(TYPE_OBJ) : %$(TYPE_SRC) 29 $(CC) $(CFLAGS) -o $@ -c $(filter %$(TYPE_SRC), $^) 30 31 32 $(DIR_OUTPUT)/%$(TYPE_DEP) : %$(TYPE_SRC) 33 @echo "Creating $@ ..." 34 @set -e; \ 35 $(CC) $(CFLAGS) -MM -E $(filter %$(TYPE_SRC), $^) | sed 's,\(.*\)\.o[ :]*,$(DIR_OUTPUT)/\1$(TYPE_OBJ) $@ : ,g' > $@
module文件夹下的makefile:
1 include $(MOD_CFG) 2 3 # Custmization Begin 4 # 5 # DIR_SRC := src 6 # DIR_INC := inc 7 # 8 # TYPE_INC := .h 9 # TYPE_SRC := .c 10 # TYPE_OBJ := .o 11 # TYPE_DEP := .dep 12 # 13 # Custmization End 14 15 include $(CMD_CFG) 16 17 include $(MOD_RULE)
main文件夹下的makefile:
1 include $(MOD_CFG) 2 3 # Custmization Begin 4 # 5 # DIR_SRC := src 6 # DIR_INC := inc 7 # 8 # TYPE_INC := .h 9 # TYPE_SRC := .c 10 # TYPE_OBJ := .o 11 # TYPE_DEP := .dep 12 # 13 # Custmization End 14 15 include $(CMD_CFG) 16 17 include $(MOD_RULE)
common文件夹下的makefile:
1 include $(MOD_CFG) 2 3 # Custmization Begin 4 # 5 # DIR_SRC := src 6 # DIR_INC := inc 7 # 8 # TYPE_INC := .h 9 # TYPE_SRC := .c 10 # TYPE_OBJ := .o 11 # TYPE_DEP := .dep 12 # 13 # Custmization End 14 15 include $(CMD_CFG) 16 17 include $(MOD_RULE)
mod-cfg.mk全局配置文件是通用的配置,也许有一些模块有特殊的配置,需要特殊配置的时候我们只需要去模块的makefile中改动即可,或者覆盖掉通用配置中的一些变量。
小结:
参考:
狄泰软件学院视频教程