自动万能makefile(linux ubuntu gcc/g++),让makefile的编写不在烦人

版权声明:标为原创文章的,转载请注明出处。 https://blog.csdn.net/guestcode/article/details/80530393

自动万能makefile(linux ubuntu gcc/g++),让makefile的编写不在烦人

keyword: wildcard notdir patsubst findstring wordlist suffix foreach

功能:

     1、自动以makefile的父目录名为Target文件名称
     2、自动搜索源码文件(含子目录)
     3、自动搜索头文件文件(含子目录)
     4、自动搜索搜索库文件(含子目录)
     5、无需任何设置也可以编译可执行文件
     6、可以生成.a和.so文件
 

 注意:本文件不对您的代码编译结果担负任何法律和道德责任,使用时需谨慎

另一个项目管理级别的高度自动化的makefile链接地址:

https://blog.csdn.net/guestcode/article/details/81229127

本文demo下载地址:

https://download.csdn.net/download/guestcode/10451084

#########################################################
# 名称:自动万能makefile(linux ubuntu gcc/g++)
# 作者:码客(卢益贵)
# 微信qq:48092788
# 时间:2018-5-20
# 功能:
#     1、自动以makefile的父目录名为Target文件名称
#     2、自动搜索源码文件(含子目录)
#     3、自动搜索头文件文件(含子目录)
#     4、自动搜索搜索库文件(含子目录)
#     5、无需任何设置也可以编译可执行文件
#     6、可以生成.a和.so文件
#
# 注意:本文件不对您的代码编译结果担负任何法律和道德责任,使用时需谨慎
#
#########################################################


###############################################
# 工程定义项(常用项,不设置为使用缺省值)
###############################################
# 目录名后面不需要“/”,正确的:“src”,错误的:“src/”,下同
# 输出的目标文件名,不需路径信息
Target :=

# 源文件目录,缺省为src目录,如果没有src则为当前目录
SrcDir :=

# 头文件目录,缺省为lib目录,没有lib则等于SrcDir
IncDir :=

# 库文件(*.a/*.so)和其头文件的目录,缺省依次为lib\3rdparty目录,否则为当前目录
LibDir :=

# 目标文件Target的输出目录
OutDir :=

# 临时文件目录,缺省时,SrcDir、LibDir都不为当前目录时为obj,否则为当前目录
ObjDir :=

# 调试选项,任意值为调试设置
DEBUG :=

###############################################
# 编译定义项(常用项,不设置为使用缺省值)
###############################################
# c/c++编译器名称,缺省为自动搜索,有cpp文件则为g++,否则为gcc
# CC := gcc
CC :=
# 静态库文件编译器名称,缺省为ar
AR :=

# c编译标志,编译器时gcc时设置,缺省为:-Wall -O -g
GccFlags :=

# c++编译标志,编译器时g++时设置,缺省为:-std=c++11
GxxFlags :=

# 静态库编译标志,缺省为:-cr
ArFlags :=

# 链接标志,缺省为:-lpthread -lrt
LdFlags :=


###############################################
# 工程定义项缺省值,此后为非常用项,修改需谨慎
###############################################
# 如果Target没有定义输出的目标文件名,则默认为makefile的父目录名
ifeq ($(Target), )
Target := $(shell pwd)/$(lastword $(MAKEFILE_LIST))
Target := $(shell dirname $(Target))
Target := $(notdir $(Target))
endif

# 如果没有设置OutDir,默认为当前目录
ifeq ($(OutDir), )
OutDir := .
endif

# 如果没有设置SrcDir,默认为src,如果没有src目录则为当前目录
ifeq ($(SrcDir), )
SrcDir := $(shell if [ -d src ]; then echo ./src; else echo .; fi;)
endif


# 如果没有设置IncDir,默认为inc,如果没有inc目录等于SrcDir
ifeq ($(IncDir), )
IncDir := $(shell if [ -d inc ]; then echo ./inc; else echo $(SrcDir); fi;)
endif

# 如果没有设置LibDir,缺省依次为lib\3rdparty目录,否则为当前目录
ifeq ($(LibDir), )
LibDir := $(shell if [ -d lib ]; then echo ./lib; else echo ; fi;)
endif
ifeq ($(LibDir), )
LibDir := $(shell if [ -d 3rdparty ]; then echo ./3rdparty; else echo .; fi;)
endif

# 如果没有设置临时文件目录,默认为obj
ifeq ($(ObjDir), )
ObjDir := .
ifneq ($(SrcDir), .)
ifneq ($(LibDir), .)
ObjDir := ./obj
endif
endif
endif

###############################################
# 编译定义项缺省值
###############################################
# c/c++编译器名称,缺省值
# 自动搜索源码文件后缀,有cpp的则自动设置编译器是g++,反之是gcc
ifeq ($(CC), )
tmpVar := $(shell find ./ -type f -iname *.cpp)
ifeq ($(tmpVar), )
CC := gcc
else
CC := g++
endif
endif

# 静态库编译器缺省值
ifeq ($(AR), )
AR  := ar
endif

# c编译标志缺省值,编译器时gcc时设置
ifeq ($(GccFlags), )
GccFlags  := -Wall -O -g
endif

# c++编译标志缺省值,编译器时g++时设置
ifeq ($(GxxFlags), )
GxxFlags := -std=c++11
endif

# 编译标志缺省值,最终使用CFlags来配置编译选项
ifeq ($(CC), gcc)
CFlags := $(GccFlags)
else
CFlags := $(GxxFlags)
endif

# 静态库编译标志缺省值
ifeq ($(ArFlags), )
ArFlags := -cr
endif

# 链接标志缺省值
ifeq ($(ArFlags), )
LdFlags := -lpthread -lrt
endif

# 生成动态库时设置
ifeq ($(suffix $(Target)), .so)
CFlags += -fPIC
LdFlags += -shared
endif

ifneq ($(DEBUG), )
CFlags += -ggdb -rdynamic
else
CFlags += -O2 -s
endif


###############################################
# 自动搜索关联文件,从此处开始至结束,不建议修改
###############################################
# c/cpp文件源码文件搜索的目录,用于编译设置
VPATH := $(shell find $(SrcDir) -type d)

# 临时文件(*.o)列表,每个*.c/*.cpp对应一个*.o文件,用于链接设置
ifeq ($(CC), gcc)
ObjFiles := $(shell find $(LibDir) -type f -iname *.c) #如果库中有源码文件
ifneq ($(ObjFiles), )
VPATH += $(shell find $(LibDir) -type d)
endif
ObjFiles += $(shell find $(SrcDir) -type f -iname *.c)
else
ObjFiles := $(shell find $(LibDir) -type f -iname *.c -o -iname *.cpp) #如果库中有源码文件
ifneq ($(ObjFiles), )
VPATH += $(shell find $(LibDir) -type d)
endif
ObjFiles += $(shell find $(SrcDir) -type f -iname *.c -o -iname *.cpp)
endif
ObjFiles := $(notdir $(ObjFiles))            #去掉目录信息
ObjFiles := $(ObjFiles:%.c=$(ObjDir)/%.o)    #每个*.c对应一个*.o文件,并设置输出到临时目录ObjDir
ObjFiles := $(ObjFiles:%.cpp=$(ObjDir)/%.o)  #每个*.cpp对应一个*.o文件,并设置输出到临时目录ObjDir

# *.a/*.so文件列表,用于链接设置
LibFiles := $(shell find $(LibDir) -type f -iname *.a -o -iname *.so)
LibFiles := $(notdir $(LibFiles))    #去掉目录信息
LibFiles := $(LibFiles:lib%.a=-l%)   #每个*.a库文件名前加-l参数标志,去掉后缀.a和前缀lib
LibFiles := $(LibFiles:lib%.so=-l%)  #每个*.so库文件名前加-l参数标志,去掉后缀.so和前缀lib

# 所有include包含的*.h文件所在的目录列表,用于编译设置
IncDirs := $(shell find $(IncDir) -type d) #*.c/*.cpp文件所在目录,默认每个*.c/*.cpp对应一个*.h文件

# *.a/*.so和它们的定义文件*.h所在的目录列表,用于链接设置
LibDirs := $(shell find $(LibDir) -type d)
IncDirs += $(LibDirs)
LibDirs := $(LibDirs:%=-L%) #每个目录名前加-I参数标志

IncDirs := $(IncDirs:%=-I%) #每个目录名前加-I参数标志

###############################################
# 链接成最终文件
###############################################
all:$(Target)
$(Target): $(ObjFiles)
	@echo "\nlinking file: "$(Target)
ifneq ($(OutDir), .)
	$(shell if [ ! -d $(OutDir) ]; then mkdir $(OutDir); fi;)
endif
ifeq ($(suffix $(Target)), .a)
	$(AR) $(ArFlags) -o $(OutDir)/$(Target) $^
else
	$(CC) $(CFlags) $^ $(LibDirs) $(LibFiles) -o $(OutDir)/$(Target) $(LdFlags)
endif

###############################################
# 编译成obj文件
###############################################
# 编译c源码文件,生成.o文件
$(ObjDir)/%.o:%.c
ifneq ($(ObjDir), .)
	$(shell if [ ! -d $(ObjDir) ]; then mkdir $(ObjDir); fi;)
endif
	@echo "\ncompiling file: "$<
	$(CC) $(CFlags) -c $< -o $@ $(IncDirs)

$(ObjDir)/%.o:%.cpp
ifneq ($(ObjDir), .)
	$(shell if [ ! -d $(ObjDir) ]; then mkdir $(ObjDir); fi;)
endif
	@echo "\ncompiling file: "$<
	$(CC) $(CFlags) -c $< -o $@ $(IncDirs)

###############################################
# 清理临时文件
###############################################
clean:
ifeq ($(ObjDir), .)
	@rm -f *.o
else
	$(shell if [ -d $(ObjDir) ]; then rm -r $(ObjDir);fi;)
endif
ifeq ($(OutDir), .)
	@rm -f $(Target)
else
	$(shell if [ -d $(OutDir) ]; then rm -r $(OutDir);fi;)
endif
	@echo "cleaned"

.PHONY: all clean

猜你喜欢

转载自blog.csdn.net/guestcode/article/details/80530393