欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

分享一个支持多目录层级的通用型Makefile配置文件

程序员文章站 2022-07-02 15:34:14
...

  一、介绍

         结合自己工程实践中的经验及参考网上资料,制作了一个通用型的Makefile配置文件,以求快速适配各种项目。

        该Makefile支持自动头文件依赖处理、进度显示、根据终端开启/关闭多颜色区分显示。

        整体划分为以下几个部分;
配置区
    完成工程基本配置,如工程根目录、目标文件、目标目录、缓存目录、代码、头文件、库文件等目录以及链接项
编译配置处理区
    设定DEFINES、CPPFLAGS、CXX等配置
编译目标准备(勿动)
    获取工程所需C 、C++源码、.o文件
目标
    生成目标的规则,
    ${TARGET}:    $(PRE_OBJS) ${OBJFILE_C} ${OBJFILE_CXX}
    @$(call ECHO_LINKING,CXX,[email protected]);sleep 0.2
    ${CXX}  -g  -fPIC -shared -o [email protected]  $(OBJFILE_C) $(OBJFILE_CXX)  $(LDFLAGS)  ${LDLIBS}     修改此处具体生成规则以适配生成动态库、可执行文件等
    @$(call ECHO_BUILT,[email protected])
编译准备
    生成目标目录、缓存目录

  二、使用

        1.设定配置项,加入工程各项目录等配置

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         = -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,[email protected]);sleep 0.2
	${CXX}  -g  -fPIC -shared -o [email protected]  $(OBJFILE_C) $(OBJFILE_CXX)  $(LDFLAGS)  ${LDLIBS}
	@$(call ECHO_BUILT,[email protected])

  三、编译

        支持命令:

        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,[email protected]);sleep 0.2
	${CXX}  -g  -fPIC -shared -o [email protected]  $(OBJFILE_C) $(OBJFILE_CXX)  $(LDFLAGS)  ${LDLIBS}
	@$(call ECHO_BUILT,[email protected])
######################################################################################################################
#建立头文件与目标之间的关联
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 [email protected]
	@rm -f [email protected]; \
	$(CC) -MM $(CPPFLAGS) $< > [email protected]$$$$; \
	sed -e 's,^.*:,$(OBJSDIR)$*.o [email protected]:,g'  < [email protected]$$$$ > [email protected]; \
	rm -f [email protected]$$$$

$(OBJSDIR).%.d : %.cpp
	@echo create [email protected]
	@rm -f [email protected]; \
	$(CXX) -MM $(CPPFLAGS) $< > [email protected]$$$$; \
	sed -e 's,^.*:,$(OBJSDIR)$*.o [email protected]:,g'  < [email protected]$$$$ > [email protected]; \
	rm -f [email protected]$$$$

${OBJSDIR}%.o:	%.cpp
	@$(call ECHO_BUILDING,CXX,[email protected]);sleep 0.2
	${CXX}  -g ${CXXFLAGS}  -c   $< -o [email protected]
${OBJSDIR}%.o:	%.c
	@$(call ECHO_BUILDING,C,[email protected]);sleep 0.2
	${CC}  -g ${CFLAGS}   -c   $< -o [email protected]


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) )