一、介绍
结合自己工程实践中的经验及参考网上资料,制作了一个通用型的Makefile配置文件,以求快速适配各种项目。
该Makefile支持自动头文件依赖处理、进度显示、根据终端开启/关闭多颜色区分显示。
整体划分为以下几个部分;
配置区
完成工程基本配置,如工程根目录、目标文件、目标目录、缓存目录、代码、头文件、库文件等目录以及链接项
编译配置处理区
设定DEFINES、CPPFLAGS、CXX等配置
编译目标准备(勿动)
获取工程所需C 、C++源码、.o文件
目标
生成目标的规则,
${TARGET}: $(PRE_OBJS) ${OBJFILE_C} ${OBJFILE_CXX}
@$(call ECHO_LINKING,CXX,$@);sleep 0.2
${CXX} -g -fPIC -shared -o $@ $(OBJFILE_C) $(OBJFILE_CXX) $(LDFLAGS) ${LDLIBS} 修改此处具体生成规则以适配生成动态库、可执行文件等
@$(call ECHO_BUILT,$@)
编译准备
生成目标目录、缓存目录
二、使用
1.设定配置项,加入工程各项目录等配置
根据实际情况更新完善PROJECT_ROOT 、OUTDIR、TARGET、SRC_DIR、INC_DIR、LIB_DIR、LDLIBS 。
PROGRAM_TYPE = ALL
#机器架构
MACHINE = ${shell uname -m}
#用于编译调试版本,仅用于开发时测试部分功能
#DEBUG_TEST= -DMODULE_TEST
#工程根目录
PROJECT_ROOT=../
#输出目录
OUTDIR = ${PROJECT_ROOT}bin/${MACHINE}/
#目标文件
TARGET = $(OUTDIR)libmylib.so
#临时文件目录
OBJSDIR = objs/
THIRD_PART = ${PROJECT_ROOT}thirdpart/
SRC_DIR = ${PROJECT_ROOT}src/src/
SRC_DIR += ${PROJECT_ROOT}/src/common/
SRC_DIR += ${THIRD_PART}inifile/
INC_DIR = ${PROJECT_ROOT}include/
INC_DIR += ${SRC_DIR}
INC_DIR += ${THIRD_PART}
INC_DIR += ${THIRD_PART}include/
INC_DIR += ${THIRD_PART}framework/include/
INC_DIR += ${THIRD_PART}openssl/include/
INC_DIR += ${THIRD_PART}curl/include/
INC_DIR += ${THIRD_PART}jsoncpp/include/
INC_DIR += ${THIRD_PART}qrencode/include/
LIB_DIR = ${THIRD_PART}lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}curl/lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}jsoncpp/lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}openssl/lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}qrencode/lib/linux/${MACHINE}/
2.修改编译参数
根据项目情况完善 DEFINES等参数情况。
DEFINES = -DPROGRAM=${PROGRAM_TYPE}
DEFINES += ${DEBUG_TEST}
CPPFLAGS += $(DEFINES) -fpermissive -std=c++11 -fPIC
CPPFLAGS += $(foreach incdir,${INC_DIR},-I ${incdir})
CFLAGS += $(CPPFLAGS) -pipe -g $(COMPILE_WARN)
CXXFLAGS += $(CPPFLAGS) -pipe -g $(COMPILE_WARN)
CXX = g++
CC = gcc
3.修改目标
根据情况修改目标文件规则,示例为动态库文件的生成规则。
${TARGET}: $(PRE_OBJS) ${OBJFILE_C} ${OBJFILE_CXX}
@$(call ECHO_LINKING,CXX,$@);sleep 0.2
${CXX} -g -fPIC -shared -o $@ $(OBJFILE_C) $(OBJFILE_CXX) $(LDFLAGS) ${LDLIBS}
@$(call ECHO_BUILT,$@)
三、编译
支持命令:
make 生成目标
make cdep 仅生成头文件.d依赖而不编译
make ddep 清理.d依赖文件,再次编译会自动生成
make clean 清理目标及缓存
make distclean 清理所有
以下为编译实例:
四、Makefile文件
########################################################配置区##########################################################
#项目区分
#不区分项目,包含所有项目,注意,包含多项目可能会导致单一项目需包含其他项目所需的依赖库,及项目功能实现
PROGRAM_TYPE = ALL
#机器架构
MACHINE = ${shell uname -m}
#用于编译调试版本,仅用于开发时测试部分功能
#DEBUG_TEST= -DMODULE_TEST
#工程根目录
PROJECT_ROOT=../
#输出目录
OUTDIR = ${PROJECT_ROOT}bin/${MACHINE}/
#目标文件
TARGET = $(OUTDIR)libmylib.so
#临时文件目录
OBJSDIR = objs/
THIRD_PART = ${PROJECT_ROOT}thirdpart/
SRC_DIR = ${PROJECT_ROOT}src/src/
SRC_DIR += ${PROJECT_ROOT}/src/common/
SRC_DIR += ${THIRD_PART}inifile/
INC_DIR = ${PROJECT_ROOT}include/
INC_DIR += ${SRC_DIR}
INC_DIR += ${THIRD_PART}
INC_DIR += ${THIRD_PART}include/
INC_DIR += ${THIRD_PART}framework/include/
INC_DIR += ${THIRD_PART}openssl/include/
INC_DIR += ${THIRD_PART}curl/include/
INC_DIR += ${THIRD_PART}jsoncpp/include/
INC_DIR += ${THIRD_PART}qrencode/include/
LIB_DIR = ${THIRD_PART}lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}curl/lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}jsoncpp/lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}openssl/lib/linux/${MACHINE}/
LIB_DIR += ${THIRD_PART}qrencode/lib/linux/${MACHINE}/
#指定SRCFILE_tcxx、SRCFILE_tc中无需编译的文件
excludeFile_C =
excludeFile_CXX =
#通用依赖库
LDLIBS += -lpthread -lm -lcrypto -lcurl -ljson -lpng -lqrencode
ifeq ($(PROGRAM_TYPE),ALL)
Msg_Info += "this is ALL\n"
else ifeq ($(PROGRAM_TYPE),CS1)
Msg_Info += "this is CS1\n"
#处理单一项目特有的操作
#LDLIBS += ...
#excludeFile_C =
excludeFile_CXX =$(filter-out %/file_CS1.cpp ,${wildcard ${PROJECT_ROOT}src/src/file_*.cpp } )
else ifeq ($(PROGRAM_TYPE),CS2)
Msg_Info += "this is CS2\n"
excludeFile_CXX =$(filter-out %/file_CS2.cpp ,${wildcard ${PROJECT_ROOT}src/src/file_*.cpp } )
endif
COMPILE_WARN=-w
#COMPILE_WERN=-W -Wall
#######################勿动
#非会话终端则去掉颜色特效
COLOR=$(shell tput colors)
NOCOLOR=$(shell if [ -z "$COLOR" ] || [ ${COLOR} -lt 8 ]; then echo 1; else echo 0; fi )
ifeq ($(NOCOLOR) ,0)
ECHO_PRIFX="\033[0;32m"
ECHO_PRIFX_TG="\033[1;32m"
ECHO_PRIFX_INFO="\033[1;32m"
ECHO_END="\033[0m"
endif
INFO = $(shell echo $(ECHO_PRIFX_INFO) "$(1)" $(ECHO_END) )
$(info $(call INFO,Make for PROGRAM_TYPE:${PROGRAM_TYPE}))
$(info $(call INFO,Scanning dependencies of target))
##如果没有定义ECHO,则定义新格式ECHO,以输出编译进度
ifndef ECHO_BUILDING
T := $(shell $(MAKE) $(MAKECMDGOALS) --no-print-directory \
-nrRf $(firstword $(MAKEFILE_LIST)) \
ECHO_BUILDING="COUNTTHIS" | grep -c "COUNTTHIS")
N := x
C = $(words $N)$(eval N := x $N)
#ECHO = echo $(ECHO_PRIFX)"`expr " [\`expr $C '*' 100 / $T\`" : '.*\(....\)$$'`%]"$(ECHO_END)
ECHO_BUILDING = echo $(ECHO_PRIFX)" [`expr $C '*' 100 / $T`%] Building $(1) object $(2)" $(ECHO_END)
ECHO_LINKING = echo $(ECHO_PRIFX_TG)" Linking $(1) executable $(2)" $(ECHO_END)
ECHO_BUILT = echo $(ECHO_PRIFX_TG) " Built Target $(1)." $(ECHO_END)
endif
########################################################配置处理区#########################################################
DEFINES = -DPROGRAM=${PROGRAM_TYPE}
DEFINES += ${DEBUG_TEST}
CPPFLAGS += $(DEFINES) -fpermissive -std=c++11 -fPIC
CPPFLAGS += $(foreach incdir,${INC_DIR},-I ${incdir})
CFLAGS += $(CPPFLAGS) -pipe -g $(COMPILE_WARN)
CXXFLAGS += $(CPPFLAGS) -pipe -g $(COMPILE_WARN)
CXX = g++
CC = gcc
#################勿动
LDFLAGS += $(foreach lddir,${LIB_DIR},-L ${lddir})
vpath %.cpp ${SRC_DIR}
vpath %.c ${SRC_DIR}
#待编译C/C++源码文件
SRCFILE_tcxx = $(foreach dir,${SRC_DIR},${wildcard ${dir}*.cpp })
SRCFILE_tc = $(foreach dir,${SRC_DIR},${wildcard ${dir}*.c })
###################################################编译目标准备###############################################################
#获取工程所需C 、C++源码、.o文件
SRCFILE_C = $(filter-out ${excludeFile_C} ,${SRCFILE_tc} )
SRCFILE_CXX = $(filter-out ${excludeFile_CXX} ,${SRCFILE_tcxx} )
SRCFILE = $(SRCFILE_C) $(SRCFILE_CXX)
OBJFILE_tc = $(notdir $(SRCFILE_C:%.c=/%.o))
OBJFILE_tcxx = $(notdir $(SRCFILE_CXX:%.cpp=/%.o))
OBJFILE_C = $(addprefix $(OBJSDIR), ${OBJFILE_tc})
OBJFILE_CXX = $(addprefix $(OBJSDIR), ${OBJFILE_tcxx})
###################################################目标###############################################################
${TARGET}: $(PRE_OBJS) ${OBJFILE_C} ${OBJFILE_CXX}
@$(call ECHO_LINKING,CXX,$@);sleep 0.2
${CXX} -g -fPIC -shared -o $@ $(OBJFILE_C) $(OBJFILE_CXX) $(LDFLAGS) ${LDLIBS}
@$(call ECHO_BUILT,$@)
######################################################################################################################
#建立头文件与目标之间的关联
tmp=$(basename ${SRCFILE})
Dfile = $(foreach file,${tmp},${OBJSDIR}.${notdir ${file}}.d)
EXINC = clean ddep distclean
ifneq ($(strip $(MAKECMDGOALS)),$(filter $(MAKECMDGOALS),$(EXINC)))
-include $(Dfile)
endif
ifeq ($(MAKECMDGOALS),)
-include $(Dfile)
endif
cdep :
@echo $(Dfile)
@echo make depfile ok
ddep:
rm -rf $(OBJSDIR)/.*.d
$(OBJSDIR).%.d : %.c
@echo create $@
@rm -f $@; \
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
sed -e 's,^.*:,$(OBJSDIR)$*.o $@:,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
$(OBJSDIR).%.d : %.cpp
@echo create $@
@rm -f $@; \
$(CXX) -MM $(CPPFLAGS) $< > $@.$$$$; \
sed -e 's,^.*:,$(OBJSDIR)$*.o $@:,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
${OBJSDIR}%.o: %.cpp
@$(call ECHO_BUILDING,CXX,$@);sleep 0.2
${CXX} -g ${CXXFLAGS} -c $< -o $@
${OBJSDIR}%.o: %.c
@$(call ECHO_BUILDING,C,$@);sleep 0.2
${CC} -g ${CFLAGS} -c $< -o $@
clean:
rm -rf ${TARGET}
rm -rf ${OBJSDIR}/*
all: ${TARGET}
distclean:clean ddep
rm -rf $(OBJSDIR)
info:
@echo ${Msg_Info}
rebuild: distclean all info
.PHONY:rebuild clean all ddep cdep distclean
###################################################编译准备###############################################################
#确保临时文件生成目录存在
$(shell [ ! -d $(OBJSDIR) ] && mkdir -p $(OBJSDIR) )
$(shell [ ! -d $(OUTDIR) ] && mkdir -p $(OUTDIR) )