自动万能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