在Linux下做開發難免要接觸makefile,整個項目的構建都依賴於它。100個developer有100種makefile的寫法,在一個較大
的項目中,各種各樣的makefile無論在開發、後期維護還是整個系統的持續整合都是一個負擔。
有幸參與重構一個遺留系統的makefile,以下是一些心得和一個makefile模板。
重構目的:
1.清晰易懂、容易維護
2.方便系統的持續整合
重構原則:
1.子模組makefile模板化
2.外部依賴、通用宏定義集中化
3.中間和最終輸出集中,便於系統構建
下面是總結出的一個makefile模板,我在日常的開發中都用它,其中加入了詳細的注釋。
#Get the ROOT_PATH which common files located, assuming this makefile located in $(ROOT_PATH)/src/sub_module<br />ROOT_PATH = $(shell cd ../..; pwd) </p><p>#Where define the path of third party modules<br />include $(ROOT_PATH)/path </p><p>#Where define common macros such as CC=gcc, CXX=g++ and so on<br />include $(ROOT_PATH)/common </p><p>#Set target output path and the path of intermidiate object<br />#The path macros should include in $(ROOT_PATH)/path<br />OUT_PATH = $(OUTPUT_PATH)/submodule<br />OBJ_PATH = $(TMPOBJ_PATH)/submodule<br />TARGET = $(OUT_PATH)/targe </p><p>#If the targe is share object then set corresponding flags<br />#which should define in $(ROOT_PATH)/common<br />CFLAGS += $(CFLAGS_SO)<br />LDFLAGS += $(LDFLAGS_SO)<br />#Custom Predefines<br />CFLAGS += -DXXXXXXXX<br />CFLAGS += -DYYYYYYYY<br />#Dependent header files<br />#The path macros should include in $(ROOT_PATH)/path<br />CFLAGS += -I. /<br /> -I$(XXXX_INC) /<br /> -I$(YYYY_INC) /<br /> -I$(ZZZZ_INC)<br />#Dependent libraries<br />#The path macros should include in $(ROOT_PATH)/path<br />LDFLAGS += -L$(XXXX_LIB) -lxxxx /<br /> -L$(YYYY_LIB) -lyyyy </p><p>#Set CPP source directory<br />CPP_SRCDIR = .<br />#Or set specific CPP Source files<br />ADDITIONAL_CPP_SOURCES = /<br /> $(PATH_A)/a.cpp /<br /> $(PATH_B)/b.cpp </p><p>#Traverse every directory in $(CPP_SRCDIR), and find every cpp file<br />CPP_SOURCES = $(foreach d,$(CPP_SRCDIR),$(wildcard $(d)/*.cpp) ) $(ADDITIONAL_CPP_SOURCES)<br />#Traverse every cpp file in $(CPP_SOURCES) and get corresponding object file(.o)<br />CPP_OBJFILES = $(patsubst %.cpp,$(OBJ_PATH)/%.o,$(notdir $(CPP_SOURCES))) </p><p>#Set C source directory<br />C_SRCDIR =<br />#Or set specific C Source files<br />ADDITIONAL_C_SOURCES = /<br /> $(PATH_A)/a.c /<br /> $(PATH_B)/b.c </p><p>#C Source files<br />C_SOURCES = $(foreach d,$(C_SRCDIR),$(wildcard $(d)/*.c) ) $(ADDITIONAL_C_SOURCES)<br />C_OBJFILES = $(patsubst %.c,$(OBJ_PATH)/%.o,$(notdir $(C_SOURCES))) </p><p>#Set vpath where to find these types of files<br />vpath %.cpp $(dir $(CPP_SOURCES))<br />vpath %.c $(dir $(C_SOURCES))<br />vpath %.o $(OBJ_PATH) </p><p>#The first target to be executed<br />all: target </p><p>target: $(TARGET) </p><p>#Static dependecy pattern<br />#$(OBJ_PATH)/%.o define the pattern of target and %.c or %.cpp is the final dependency<br />$(C_OBJFILES): $(OBJ_PATH)/%.o: %.c<br /> -mkdir -p $(OBJ_PATH)<br /> $(CXX) -c $(CFLAGS) -o $@ $< </p><p>$(CPP_OBJFILES): $(OBJ_PATH)/%.o: %.cpp<br /> -mkdir -p $(OBJ_PATH)<br /> $(CXX) -c $(CFLAGS) -o $@ $< </p><p>$(TARGET): $(CPP_OBJFILES) $(C_OBJFILES)<br /> -mkdir -p $(OUT_PATH)<br /> $(CXX) -o $@ $^ $(LDFLAGS) </p><p>clean:<br /> -rm -rf $(OBJ_PATH)<br /> -rm -f $(TARGET)