博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C/C++通用Makefile
阅读量:6996 次
发布时间:2019-06-27

本文共 11091 字,大约阅读时间需要 36 分钟。

        最近的项目又回到了Linux上运行,这就需要在Linux下编译项目,写Makefile针对习惯了Windows的程序员来说是一件痛苦的事,如果有一个通用的Makefile该多好啊,本着这样的目的,我再次研究了一下Makefile,写出了一个实用的通用Makefile,该Makefile在Windows以及Linux平台下作了一些简单测试,未发现问题,如果大家在使用过程中发现有问题可以联系我。话不多说,直接上代码:

#################################################################################  C/C++通用Makefile##  作者:Witton Bell         E_Mail:witton@163.com##  版本V1.0 (2017/02/23)#		初始版本,可以生成App,Share以及Static库等等#  版本V1.1 (2017/02/28)#		添加预预编译头的支持,将生成的中间文件放在debug或者release目录下#  版本V1.2 (2017/03/12)#		优化以及fixed:修改头文件后,不会编译##  一个项目只需要在顶层目录配置一个Makefile,不需要各个目录单独配置,简单方便实用#  原文链接:http://blog.csdn.net/witton/article/details/56670748 #  最新文件下载地址:https://code.csdn.net/snippets/2259925##  功能说明:#  1.支持Windows以及Linux下的可执行文件(App)、动态库(Share)以及静态库(Static)的生成#  2.支持生成Map文件,Bin文件以及十六进制文件#  3.支持C/C++的预编译头,以加快编译速度,包括同时存在C与C++预编译头的情况#  4.生成的中间以及目标代码会指定存放在debug或者release目录下#  5.支持生成进度显示################################################################################# 可以修改的区域# 目标文件的名字(必须指定)TARGETNAME := test#目标类型可以是APP, STATIC或者SHAREDTARGETTYPE := APP#配置类型可以是Debug或者ReleaseCONFIG ?= Debug# C 预编译头文件,支持带路径PCH_H =# C++ 预编译头文件,支持带路径PCH_X_H =#源文件目录列表,可以填多个目录,如:src1 src2 ../src#如果没填写则默认为当前目录SRC_ROOT_DIRS :=#排除的目录列表,需要带上相对路径EXCLUDE_DIRS :=#排除的文件列表,需要带上相对路径EXCLUDE_FILES :=#头文件所在目录列表INCLUDE_DIRS :=#库文件所在目录列表LIBRARY_DIRS :=#公共库文件名列表LIBRARY_NAMES := #公共宏定义PREPROCESSOR_MACROS :=#各种编译链接参数#汇编编译参数ASFLAGS := -f win64#ld链接参数LDFLAGS := -Wl,-gc-sections#公共编译参数,根据情况作修改COMMONFLAGS := -g -ffunction-sections#额外的库文件EXTERNAL_LIBS := #工具集,Windows下最好是填写绝对路径,并且路径中需要使用/分隔CC := g:/TDM-GCC-64/bin/gccCXX := g:/TDM-GCC-64/bin/g++LD := $(CXX)ASM := "G:/Program Files (x86)/nasm/nasm.exe"AR := arOBJCOPY := objcopyCP := cpMKDIR = mkdirRM = rm -rfECHO = echoSHELL = /bin/sh#根据配置类型填写不同的参数ifeq ($(CONFIG), Debug)	PREPROCESSOR_MACROS += DEBUG	LIBRARY_NAMES += 	ADDITIONAL_LINKER_INPUTS := 	MACOS_FRAMEWORKS := 	LINUX_PACKAGES := 	CFLAGS := -O0	CXXFLAGS := -O0else	PREPROCESSOR_MACROS +=	LIBRARY_NAMES += 	ADDITIONAL_LINKER_INPUTS := 	MACOS_FRAMEWORKS := 	LINUX_PACKAGES := 	CFLAGS := -O3	CXXFLAGS := -O3endif#需要编译的源文件的扩展名列表SRC_EXTS := .c .cpp .cc .cxx .c++ .s .S .asm#如果是在Linux下编译,需要打开此开关#IS_LINUX_PROJECT := 1#如果需要生成Map文件,需要打开此开关#GENERATE_MAP_FILE := 1#如果生成Bin文件,需要打开此开关#GENERATE_BIN_FILE := 1#如果生成十六进制文件,需要打开此开关#GENERATE_IHEX_FILE := 1#是否显示详细的命令行#SHOW_CMD_DETAIL := 1#可修改区域结束,以下区域不建议修改,除非特别了解其含义#======================华丽的分割线=============================#小写函数to_lowercase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))BINARYDIR := $(call to_lowercase,$(CONFIG))ifeq ($(BINARYDIR),)error:	$(error Invalid configuration, please check your inputs)endif#如果没配置源文件目录,则默认为当前目录ifeq ($(SRC_ROOT_DIRS),)	SRC_ROOT_DIRS = .endifdefine walk$(wildcard $(addprefix $(1)/*, $(SRC_EXTS))) $(foreach e, $(wildcard $(1)/*), $(call walk, $(e)))endef#匹配所有源文件SOURCEFILES := $(foreach e, $(SRC_ROOT_DIRS), $(call walk, $(e)))#匹配所有需要排除的源文件EXCLUDE_SOURCE := $(foreach e, $(EXCLUDE_DIRS), $(call walk, $(e)))EXCLUDE_FILES += $(EXCLUDE_SOURCE)EXTERNAL_LIBS_COPIED := $(foreach lib, $(EXTERNAL_LIBS),$(BINARYDIR)/$(notdir $(lib)))#设置C预编译相关变量ifneq ($(PCH_H),)PCH = $(PCH_H).gchPCH_FLAGS := -Winvalid-pch -include $(BINARYDIR)/$(PCH_H)PCH_FILE := $(BINARYDIR)/$(PCH)endif#设置C++预编译相关变量ifneq ($(PCH_X_H),)PCH_X = $(PCH_X_H).gchPCH_X_FLAGS := -Winvalid-pch -include $(BINARYDIR)/$(PCH_X_H)PCH_X_FILE := $(BINARYDIR)/$(PCH_X)endifSTART_GROUP := -Wl,--start-groupEND_GROUP := -Wl,--end-groupINCLUDE_DIRS += .#处理头文件目录CFLAGS += $(addprefix -I,$(INCLUDE_DIRS))CXXFLAGS += $(addprefix -I,$(INCLUDE_DIRS))#处理宏定义CFLAGS += $(addprefix -D,$(PREPROCESSOR_MACROS))CXXFLAGS += $(addprefix -D,$(PREPROCESSOR_MACROS))ASFLAGS += $(addprefix -D,$(PREPROCESSOR_MACROS))#处理框架CFLAGS += $(addprefix -framework ,$(MACOS_FRAMEWORKS))CXXFLAGS += $(addprefix -framework ,$(MACOS_FRAMEWORKS))LDFLAGS += $(addprefix -framework ,$(MACOS_FRAMEWORKS))#处理库目录LDFLAGS += $(addprefix -L,$(LIBRARY_DIRS))CFLAGS += $(COMMONFLAGS)CXXFLAGS += $(COMMONFLAGS)LDFLAGS += $(COMMONFLAGS)ifeq ($(GENERATE_MAP_FILE),1)LDFLAGS += -Wl,-Map=$(BINARYDIR)/$(basename $(TARGETNAME)).mapendifLIBRARY_LDFLAGS = $(addprefix -l,$(LIBRARY_NAMES))ifeq ($(IS_LINUX_PROJECT),1)ifeq ($(TARGETTYPE),SHARED)TempName = $(addsuffix .so,$(basename $(TARGETNAME)))TARGETNAME := $(TempName)endif	RPATH_PREFIX := -Wl,--rpath='$$ORIGIN/../	LIBRARY_LDFLAGS += $(EXTERNAL_LIBS)	LIBRARY_LDFLAGS += -Wl,--rpath='$$ORIGIN'	LIBRARY_LDFLAGS += $(addsuffix ',$(addprefix $(RPATH_PREFIX),$(dir $(EXTERNAL_LIBS))))		#如果是Linux下的共享库(Share)项目,则需要添加-fPIC参数,以实现位置无关代码	ifeq ($(TARGETTYPE),SHARED)		CFLAGS += -fPIC		CXXFLAGS += -fPIC		ASFLAGS += -fPIC		LIBRARY_LDFLAGS += -Wl,-soname,$(TARGETNAME)	endif		ifneq ($(LINUX_PACKAGES),)		PACKAGE_CFLAGS := $(foreach pkg,$(LINUX_PACKAGES),$(shell pkg-config --cflags $(pkg)))		PACKAGE_LDFLAGS := $(foreach pkg,$(LINUX_PACKAGES),$(shell pkg-config --libs $(pkg)))		CFLAGS += $(PACKAGE_CFLAGS)		CXXFLAGS += $(PACKAGE_CFLAGS)		LIBRARY_LDFLAGS += $(PACKAGE_LDFLAGS)	endifelse	LIBRARY_LDFLAGS += $(EXTERNAL_LIBS)ifeq ($(TARGETTYPE),APP)TempName = $(addsuffix .exe,$(basename $(TARGETNAME)))TARGETNAME := $(TempName)endififeq ($(TARGETTYPE),SHARED)TempName = $(addsuffix .dll,$(basename $(TARGETNAME)))TARGETNAME := $(TempName)endifendifLIBRARY_LDFLAGS += $(ADDITIONAL_LINKER_INPUTS)#静态库都是以.a为后缀ifeq ($(TARGETTYPE),STATIC)TempName = $(addsuffix .a,$(basename $(TARGETNAME)))TARGETNAME := $(TempName)endififeq ($(STARTUPFILES),)	all_source_files := $(SOURCEFILES)else	all_source_files := $(STARTUPFILES) $(filter-out $(STARTUPFILES),$(SOURCEFILES))endifdefine HandlePath$(foreach x,$(foreach x,$(foreach x,$(subst //,/,$(1)),$(subst ../,*/,$(x))),$(subst ./,,$(x))),$(subst */,../,$(x)))endefAllSource := $(call HandlePath, $(all_source_files))AllExcludeSource := $(call HandlePath, $(EXCLUDE_FILES))Source := $(filter-out $(AllExcludeSource),$(AllSource))CompileObjs := $(foreach x,$(SRC_EXTS),$(patsubst %$(x),%.o,$(filter %$(x),$(Source))))all_objs := $(foreach x,$(CompileObjs),$(BINARYDIR)/$(x))ASM_EXT := .s .S .asmCompileCObjs := $(foreach x,$(filter-out $(ASM_EXT),$(SRC_EXTS)),$(patsubst %$(x),%.d,$(filter %$(x),$(Source))))all_Cobjs := $(foreach x,$(CompileCObjs),$(BINARYDIR)/$(x))DEPS := $(all_Cobjs:.o=.d)revert0 = $(2) $(1)define revert$(foreach x,$(DEPS),$(eval TempStep = $(call revert0, $(TempStep),$(x)))) $(TempStep)endefAllStep := $(call revert,$(DEPS))AllStep += $(CompileObjs)WordNum := $(words $(AllStep))ProgressInfo := $(foreach x,$(AllStep),$(eval Counter += A)$(addsuffix .$(words $(Counter)), $(basename $(x))))define FindProgress$(foreach x,$(ProgressInfo),$(if $(filter $(basename $(x)),$(1)),$(subst .,,$(suffix $(x))),))endefdefine ShowProgress$(strip $(call FindProgress,$(basename $(1))))/$(WordNum)endefIS_GCC_ASM :=ifneq ($(filter $(ASM),$(CXX)),)IS_GCC_ASM = 1elseifneq ($(filter $(ASM),$(CC)),)IS_GCC_ASM = 1endifendififeq ($(IS_GCC_ASM),1)CompileA 	:= $(ASM) $(CFLAGS) $(ASFLAGS) -celseCompileA 	:= $(ASM) $(ASFLAGS)endifCompileC 	:= $(CC) $(PCH_FLAGS) $(CFLAGS) -cCompileCXX	:= $(CXX) $(PCH_X_FLAGS) $(CXXFLAGS) -cifneq ($(SHOW_CMD_DETAIL),)define CompileSrc	@$(MKDIR) -p $(BINARYDIR)/$(subst ../,__/, $(dir $(1)))	@$(ECHO) -n [$(call ShowProgress,$(2))]	$(3) $(2) -o $(subst ../,__/, $(1))endefelsedefine CompileSrc	@$(MKDIR) -p $(BINARYDIR)/$(subst ../,__/, $(dir $(1)))	@$(ECHO) [$(call ShowProgress,$(2))] Compile $(2)	@$(3) $(2) -o $(subst ../,__/, $(1))endefendifdefine CompileCDep	@$(MKDIR) -p $(subst ../,__/, $(dir $(1)))	@$(ECHO) [$(call ShowProgress,$(BINARYDIR)/$(2))] Generate $(1)	@$(CC) -MM $(CFLAGS) $(2) > $(BINARYDIR)/temp	@$(ECHO) -n $(subst ./,, $(dir $(1))) > $(1)	@$(CC) -MM $(CFLAGS) $(2) >> $(1)endefdefine CompileCXXDep	@$(MKDIR) -p $(subst ../,__/, $(dir $(1)))	@$(ECHO) [$(call ShowProgress,$(BINARYDIR)/$(2))] Generate $(1)	@$(CXX) -MM $(CXXFLAGS) $(2) > $(BINARYDIR)/temp	@$(ECHO) -n $(subst ./,, $(dir $(1))) > $(1)	@$(CXX) -MM $(CXXFLAGS) $(2) >> $(1)endefPRIMARY_OUTPUTS :=ifeq ($(GENERATE_BIN_FILE),1)PRIMARY_OUTPUTS += $(BINARYDIR)/$(basename $(TARGETNAME)).binendififeq ($(GENERATE_IHEX_FILE),1)PRIMARY_OUTPUTS += $(BINARYDIR)/$(basename $(TARGETNAME)).ihexendififeq ($(PRIMARY_OUTPUTS),)PRIMARY_OUTPUTS := $(BINARYDIR)/$(TARGETNAME)endif.PHONY: all clean.SUFFIXES:all: $(PRIMARY_OUTPUTS)	@$(RM) $(BINARYDIR)/temp	@$(ECHO) Built OK.$(BINARYDIR)/$(basename $(TARGETNAME)).bin: $(BINARYDIR)/$(TARGETNAME)	@$(OBJCOPY) -O binary $< $(subst ../,__/, $@)$(BINARYDIR)/$(basename $(TARGETNAME)).ihex: $(BINARYDIR)/$(TARGETNAME)	@$(OBJCOPY) -O ihex $< $(subst ../,__/, $@) ifeq ($(TARGETTYPE),APP)$(BINARYDIR)/$(TARGETNAME): $(all_objs) $(EXTERNAL_LIBS)	@$(ECHO) Link App $(subst ../,__/, $@)	@$(LD) -o $(subst ../,__/, $@) $(LDFLAGS) $(START_GROUP) $(subst ../,__/, $(all_objs)) $(LIBRARY_LDFLAGS) $(END_GROUP)endififeq ($(TARGETTYPE),SHARED)$(BINARYDIR)/$(TARGETNAME): $(all_objs) $(EXTERNAL_LIBS)	@$(ECHO) Link Share lib $(subst ../,__/, $@)	@$(LD) -shared -o $(subst ../,__/, $@) $(LDFLAGS) $(START_GROUP) $(subst ../,__/, $(all_objs)) $(LIBRARY_LDFLAGS) $(END_GROUP)endififeq ($(TARGETTYPE),STATIC)$(BINARYDIR)/$(TARGETNAME): $(all_objs)	@$(ECHO) Link Static lib $(subst ../,__/, $@)	@$(AR) -r $(subst ../,__/, $@) $(subst ../,__/, $^)endifclean:	@$(RM) $(BINARYDIR)$(BINARYDIR):	@$(MKDIR) $(BINARYDIR)#Makefile的生成规则#生成依赖文件$(BINARYDIR)/%.d : %.c	$(call CompileCDep,$@,$<)$(BINARYDIR)/%.d : %.cpp	$(call CompileCXXDep,$@,$<)$(BINARYDIR)/%.d : %.cxx	$(call CompileCXXDep,$@,$<)$(BINARYDIR)/%.d : %.cc	$(call CompileCXXDep,$@,$<)$(BINARYDIR)/%.d : %.c++	$(call CompileCXXDep,$@,$<)#C文件的生成规则$(BINARYDIR)/%.o : %.c $(PCH_FILE)	$(call CompileSrc,$@,$<,$(CompileC))#C++的.cpp文件的生成规则$(BINARYDIR)/%.o : %.cpp $(PCH_X_FILE)	$(call CompileSrc,$@,$<,$(CompileCXX))#C++的.cc文件的生成规则$(BINARYDIR)/%.o : %.cc $(PCH_X_FILE)	$(call CompileSrc,$@,$<,$(CompileCXX))#C++的.cxx文件的生成规则$(BINARYDIR)/%.o : %.cxx $(PCH_X_FILE)	$(call CompileSrc,$@,$<,$(CompileCXX))#C++的.c++文件的生成规则$(BINARYDIR)/%.o : %.c++ $(PCH_X_FILE)	$(call CompileSrc,$@,$<,$(CompileCXX))#Asm的.S文件生成规则$(BINARYDIR)/%.o : %.S	$(call CompileSrc,$@,$<,$(CompileA))#Asm的.s文件生成规则$(BINARYDIR)/%.o : %.s	$(call CompileSrc,$@,$<,$(CompileA))#Asm的.asm文件生成规则$(BINARYDIR)/%.o : %.asm	$(call CompileSrc,$@,$<,$(CompileA))ifneq ($(PCH_H),)#C预编译头文件的生成规则 $(BINARYDIR)/$(PCH) : $(PCH_H)	@$(MKDIR) -p $(subst ../,__/, $(dir $@))	@$(ECHO) Precompiled C header $<	@$(CC) $(CFLAGS) $> $^ -o $(subst ../,__/, $@)	@$(CP) $(PCH_H) $(BINARYDIR)/$(PCH_H)endififneq ($(PCH_X_H),)#C++预编译头文件的生成规则 $(BINARYDIR)/$(PCH_X) : $(PCH_X_H)	@$(MKDIR) -p $(subst ../,__/, $(dir $@))	@$(ECHO) Precompiled C++ header $<	@$(CXX) $(CXXFLAGS) $> $^ -o $(subst ../,__/, $@)	@$(CP) $(PCH_X_H) $(BINARYDIR)/$(PCH_X_H)endififndef NODEPifneq ($(DEPS),)sinclude $(DEPS)endifendif#生成规则结束
最终的运行结果如下图所示:

祝玩得开心!

转载于:https://www.cnblogs.com/witton/p/6868958.html

你可能感兴趣的文章
BZOJ2440:[中山市选2011]完全平方数(莫比乌斯函数)
查看>>
有关xerosploit运行报错问题的有效解决方案
查看>>
ABP官方文档翻译 1.4 启动配置
查看>>
js框架简明
查看>>
Java volatile 关键字
查看>>
http 头信息详解
查看>>
计算机图形学(OpenGL版)-OpenGL基本几何图元
查看>>
Oracle 12C 新特性之表分区带 异步全局索引异步维护(一次add、truncate、drop、spilt、merge多个分区)...
查看>>
Mybatis动态SQL生成
查看>>
javascript 正则表达式学习
查看>>
关于Asp.Net中避免用户连续多次点击按钮,重复提交表单的处理
查看>>
js页面刷新一次
查看>>
坑人的运算符
查看>>
spring security custom-filter with java configuration 验证码验证
查看>>
01、BootstrapperShell
查看>>
Automation Test in Maya Plugin Development
查看>>
DRM 简介
查看>>
idea编译时JDK版本变化
查看>>
搭建LoadRunner中的场景(一) 创建场景
查看>>
蓄水池算法
查看>>