项目管理级别的自动万能通用makefile模板:t-makefile (freetoo)

 

项目管理级别的自动万能通用makefile模板:t-makefile (freetoo)

 

t-makefile源码及示例项目下载链接(会不定期更新):

https://github.com/freetoo/t-makefile

 


一、t-makefile解决的痛点和难点

往往在一个项目工程中,目录名改变了、子目录变更位置了都需要去修改makefile,目录繁多的时候修改makefile也是一件耗时的工作。有没有一个自动的makefile呢?

对于makefile所在的当前目录及其子目录来说,自动makefile的功能实现是非常容易的事情,但难点是:

1、如何自动识别上层目录中(项目目录范围内)的公共目录

2、如何排除一些无关的目录,比如.git目录、test目录、tmp目录、doc目录等。

t-makefile正是解决了以上痛点和难点,从而达到了自动化的目的。t-makefile是一个高度自动化的项目管理级别的makefile源码,能够使您的linux c/c++项目的协同开发工作更加的便捷和高效。

 


二、t-makefile功能:

1、自动搜索源码、头文件、库文件目录并形成有效目录列表和有效文件列表

2、自动识别总makefile功能,可批量执行子目录的makefile

3、自动以目录名为TARGET文件名

4、可动态和静态混合链接成TARGET文件

5、可设置排除目录,避免搜索编译无关源码

6、目录框架灵活设定,框架内可自由移动子makefile仍具有自动功能

7、可避免链接无关符号(函数和变量),避免TARGET体积臃肿

8、支持test目录,可自动包含test工程引用到的模块源码,并能排除其它test目录

9、支持交叉编译,并自动搜索交叉编译环境下的项目库文件(.a/.so)

10、设置简单:仅需设置单个目录的名称即可(不需全路径名)

 


三、t-makefile作用域

t-makefile依赖build.mk文件(主makefle文件)放在项目根目录,若干个子Makefile分布在项目子目录下。

t-makefile的作用域是:makefile的当前目录及子其目录+上层公共目录及其子目录。

注:上层公共目录是指makefile所在的目录向上到项目根目录或build.mk文件所在的目录的每一级目录的一级子目录(由变量COMMON_DIR_NAMES指定名称)

公共目录示例:

############################################################
# Copyleft ©2018 freetoo(yigui-lu)
# name: t-makefile automatic makefile for ubuntu
# qq/wx: 48092788    e-mail: gcode@qq.com
# cn-help: https://blog.csdn.net/guestcode/article/details/81229127
# download: https://github.com/freetoo/t-makefile
# create: 2018-7-7
############################################################# t-makefile功能说明:
#     1、自动搜索源码、头文件、库文件目录并形成有效目录列表和文件列表
#     2、自动识别总makefile功能,可批量执行子目录的makefile
#     3、自动以目录名为TTARGET文件名
#     4、可动态和静态混合链接成TARGET文件
#     5、可设置排除目录,避免搜索编译无关源码
#     6、目录框架灵活设定,框架内可自由移动子makefile仍具有自动功能
#     7、可避免链接无关符号(函数和变量),避免TARGET体积臃肿# 使用方法(usage): 
#     1、make                             # 正常编译 
#     2、make clean                       # 清除临时文件及TARGET文件 
#     3、make INFO=1                      # 编译时打印详细信息 
#     4、make INFO=2                      # 静默编译 
#     5、make CROSS_COMPILE=...           # 交叉编译设置
#     6、make [clean] ALL=y               # 执行本目录和子目录的makefile# 自动makefile作用域(示例):
# Automatic makefile scope(demo):
#
# │───Project───│───Process───│───Module───│───Test───│
#
#	├── 01-lib
#	├── 02-com
#	├── tcp-client
#	│     ├──────── 01-lib
#	│     ├──────── 02-inc
#	│     ├──────── Module1
#	│     ├──────── Module2
#	│     │            └────────── test
#	│     │                          └──────── Makefile(test)
#	│     └──────── Makefile(Process)
#	├── tcp-server
#	├── build.mk
#	└── Makefile
#
# Makefile Scope:current directory(subdirectory) + upper common directory(subdirectory)
# The setting of the upper common directory reference variable COMMON_DIR_NAMES
#
# makefile的作用域是:当前目录及子其目录+上层公共目录及其子目录,
# 公共目录的设置参考变量COMMON_DIR_NAMES的设置。# 名词解释:
#   上层、向上:是指由makefile所在目录向系统根目录方向到build.mk文件
#             所在的目录位置的若干层目录。############################################################
# 常用设置项
############################################################
# 输出目标文件名,不设置则默认使用makefile所在的目录名
# 注意:makefile要和main.c/main.cpp文件同级目录
#TARGET ?=
TARGET ?=# 要包含的上层模块目录名列表(在makefile作用域内)
# 但要确保名称的唯一性,且为上层目录的一级目录名。
# 对于要包含的模块,makefile会为其增加宏定义用于条件编译:INC_MODULENAME
#INCLUDE_MODULE_NAMES += ModuleName
INCLUDE_MODULE_NAMES +=# 要排除的模块目录名列表(在makefile作用域内)
# 对于要排除的模块,makefile会为其增加宏定义用于条件编译:EXC_MODULENAME
#EXCLUDE_DIR_NAMES += ModuleName
EXCLUDE_MODULE_NAMES +=############################################################
# 编译设置部分(Compile setup part)
############################################################
# 设置调试编译选项(Setting the debug compilation options)
#DEBUG ?= y
DEBUG ?= y# 宏定义列表(macro definition),用于代码条件编译,不需要前面加-D,makefile会自动补上-D
#DEFS ?= DEBUG WIN32 ...
DEFS +=# C代码编译标志(C code compile flag)
#CC_FLAGS  ?= -Wall -Wfatal-errors -MMD
CC_FLAGS  ?= -Wall -Wfatal-errors -MMD# C++代码编译标志(C++ code compile flag),注:最终CXX_FLAGS += $(CC_FLAGS)()
#CXX_FLAGS ?= -std=c++11
CXX_FLAGS ?= -std=c++11# 编译静态库文件设置标志(Compiling a static library file setting flag)
#AR_FLAGS ?= -cr
AR_FLAGS ?= -cr# 链接标志,默认纯动态链接模式(Link flag, default pure dynamic link mode)
# static  mode: DYMAMIC_LDFLAG ?=        STATIC_LDFLAGS ?=
#               DYMAMIC_LDFLAG ?= ...    STATIC_LDFLAGS ?=
# dynamic mode: DYMAMIC_LDFLAG ?=        STATIC_LDFLAGS ?= ... 
# bland   mode: DYMAMIC_LDFLAG ?= ...    STATIC_LDFLAGS ?= ... 
#
# 动态链接标志(dynamic link flag)
#DYMAMIC_LDFLAGS += -lrt -lpthread
DYMAMIC_LDFLAGS ?= -lrt -lpthread
# 静态链接标志(static link flag)
#STATIC_LDFLAGS += -lrt -ldl -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
STATIC_LDFLAGS ?=# 交叉编译设置,关联设置:CROSS_COMPILE_LIB_KEY
#CROSS_COMPILE ?= arm-linux-gnueabihf-
#CROSS_COMPILE ?= /usr/bin/arm-linux-gnueabihf-
CROSS_COMPILE ?=# 交叉编译链库文件的关键字变量设置,用于识别交叉编译链的库文件
# 例如项目中有同样功能的库文件libcrc.a和libarm-linux-gnueabihf-crc.a,
# makefile会根据CROSS_COMPILE_LIB_KEY的设置来选择相应的库文件。
#CROSS_COMPILE_LIB_KEY ?= arm-linux-gnueabihf-
CROSS_COMPILE_LIB_KEY ?= arm-linux-gnueabihf-############################################################
# 项目规划初期设置
############################################################
# 项目根目录名,不设置则自动以build.mk文件目录为准,如果也没有build.mk文件
# 则自动以makefile所在文件为准。
# PROJECT_ROOT_DIR_NAME ?= tmf-demo
PROJECT_ROOT_DIR_NAME ?=# 测试目录的目录名称,makefile会排除在搜索范围之外(makefile所在目录例外)
#TEST_DIR_NAME ?= test
TEST_DIR_NAME ?= test# 临时目录的目录名称,makefile会排除在搜索范围之外
# 编译时临时文件(.o/.d等文件)所在的目录,如果不设置则默认为tmp
#TMP_DIR ?= tmp
TMP_DIR ?= tmp# 要包含的上层公共目录名列表,包含库目录、头文件目录等的目录名
#COMMON_DIR_NAMES += lib inc include com common \
#					01-lib 01-inc 01-include 01-com 01-common \
#					02-lib 02-inc 02-include 02-com 02-common \
#					03-lib 03-inc 03-include 03-com 03-common
COMMON_DIR_NAMES ?= lib inc include com common \01-lib 01-inc 01-include 01-com 01-common \02-lib 02-inc 02-include 02-com 02-common \03-lib 03-inc 03-include 03-com 03-common# 头文件目录名列表,INC_DIR_NAMES是COMMON_DIR_NAMES的子集,
# 一旦设置了本变量,makefile只将其及其子目录加入编译参数-I中。
# 如果不设置,makefile会自动搜含有头文件的目录加入编译参数-I中。
#INC_DIR_NAMES ?= inc include 01-inc 01-include 02-inc 02-include 03-inc 03-include
INC_DIR_NAMES ?=# 要排除的目录名列表,比如文档目录、备份目录等
#EXCLUDE_DIR_NAMES += .git tmp temp doc docs bak
EXCLUDE_DIR_NAMES ?= .git tmp temp doc docs bak############################################################
# TARGET后置处理及杂项设置
############################################################
# makefile所在目录的全路径名称
CUR_DIR ?= $(shell pwd)
# makefile所在的目录名称
CUR_DIR_NAME := $(notdir $(CUR_DIR))# 如果是test目录,SRC_DIR则向上跳一层
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))SRC_DIR := $(shell dirname $(CUR_DIR))
elseSRC_DIR := $(CUR_DIR)
endif# 如果没有手动设置TARGET,则设置为makefile所在的目录名称
ifeq ($(TARGET),)TARGET := $(notdir $(SRC_DIR))ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))TARGET := $(TARGET)_$(TEST_DIR_NAME)endififneq ($(CROSS_COMPILE),)ifneq ($(CROSS_COMPILE_LIB_KEY),)TARGET := $(TARGET:lib%=lib$(CROSS_COMPILE_LIB_KEY)%)endifendif
endif# 是编译exec文件还是库文件
IS_LIB_TARGET := $(suffix $(TARGET))
# 目标文件是库文件?
ifneq ($(IS_LIB_TARGET),)IS_LIB_TARGET := $(shell if [ $(IS_LIB_TARGET) = .a ] || [ $(IS_LIB_TARGET) = .so ]; then echo y; fi;)
endififeq ($(IS_LIB_TARGET),y)# 补充lib前缀TARGET := $(if $(findstring lib,$(TARGET)),$(TARGET),lib$(TARGET))TMP_TARGET := $(basename $(TARGET))
elseTMP_TARGET := $(TARGET)
endif# 查找main文件
MAIN_FILE := $(shell find $(CUR_DIR) -maxdepth 1 -type f -iname 'main.c' -o -type f -iname 'main.cpp')
# 无main文件也不是编译库文件,则认为是总makefile功能
ifeq ($(MAIN_FILE)$(IS_LIB_TARGET),)TARGET :=MAKE_SUB := y
endif
# 入口参数ALL表示手动设置总makefile功能
ifeq ($(ALL),y)MAKE_SUB := y
endif# 编译信息显示设置,1:为全部显示,2:仅显示步骤项,其它:静默无显示
ifeq ($(INFO),1)BUILD_INFO=STEP_INFO=@echo
else ifeq ($(INFO),2)BUILD_INFO=@STEP_INFO=@true
elseBUILD_INFO=@STEP_INFO=@echo
endif# 文件目录操作变量
RM      := rm -rf
MKDIR   := mkdir -p
MAKE    := make############################################################
# 编译定义项及编译设置项的后置处理(非常用项,修改需谨慎)
############################################################# c/c++编译器名称,默认为gcc,有cpp文件则被自动改为g++
CC  := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
AR  := $(CROSS_COMPILE)ar
# 默认链接器是gcc,如果有cpp文件makefile会自动设置为g++
ifeq ($(suffix $(MAIN_FILE)),.cpp)LD := $(CXX)
elseLD := $(CC)
endif# 宏定义列表
# 转大写,+INC前缀
tmp := $(shell echo $(INCLUDE_MODULE_NAMES) | tr '[a-z]' '[A-Z]')
DEFS := $(DEFS) $(tmp:%=INC_%)
# 转大写,+EXC前缀
tmp := $(shell echo $(EXCLUDE_MODULE_NAMES) | tr '[a-z]' '[A-Z]')
DEFS := $(DEFS) $(tmp:%=EXC_%)
DEFS := $(DEFS:%=-D%)# C代码编译设置标志
CC_FLAGS += $(DEFS)
ifeq ($(DEBUG), y)CC_FLAGS += -ggdb -rdynamic -g
elseCC_FLAGS += -O2 -s
endif
# 不使用到的符号不链接到目标文件中
CC_FLAGS += -ffunction-sections -fdata-sections# 链接标志和链接库设置(除TOP_MODULE_DIRS目录下的*.a和*.so文件之外的链接库设置)
# STATIC_LIB_FILES和DYNAMIC_LIB_FILES变量是makefile作用域里面的.a和.so文件列表,请一定保留
DYMAMIC_LDFLAGS := $(strip $(DYMAMIC_LDFLAGS))
STATIC_LDFLAGS := $(strip $(STATIC_LDFLAGS))
ifeq ($(DYMAMIC_LDFLAGS)$(STATIC_LDFLAGS),$(DYMAMIC_LDFLAGS))# 纯动态链接模式#LDFLAGS ?= -Wl,--as-needed -lrt -lpthread $(DYNAMIC_LIB_FILES) $(STATIC_LIB_FILES)LDFLAGS ?= $(DYNAMIC_LIB_FILES) $(STATIC_LIB_FILES) $(DYMAMIC_LDFLAGS)
else ifeq ($(DYMAMIC_LDFLAGS)$(STATIC_LDFLAGS),$(STATIC_LDFLAGS))# 纯静态链接模式#LDFLAGS ?= -static -lrt -Wl,--whole-archive -lpthread -Wl,--no-whole-archive $(STATIC_LIB_FILES)LDFLAGS ?= -static $(STATIC_LIB_FILES) $(STATIC_LDFLAGS)
else# 动态静态混合链接模式# 模板:LDFLAGS = -Wl,-Bstatic ... $(STATIC_LIB_FILES) -Wl,--as-needed -Wl,-Bdynamic ... $(DYNAMIC_LIB_FILES)#LDFLAGS ?= -Wl,-Bstatic -lpthread $(STATIC_LIB_FILES) -Wl,--as-needed -Wl,-Bdynamic -lrt $(DYNAMIC_LIB_FILES)LDFLAGS ?= -Wl,-Bstatic $(STATIC_LIB_FILES) $(STATIC_LDFLAGS) -Wl,-Bdynamic $(DYNAMIC_LIB_FILES) $(STATIC_LDFLAGS)
endif
LDFLAGS += -Wl,--gc-sections# 编译动态库设置项
ifeq ($(suffix $(TARGET)),.so)CC_FLAGS += -fPICLDFLAGS += -shared
endif# 最终CXX_FLAGS包含CC_FLAGS
CXX_FLAGS += $(CC_FLAGS)# 检查编译so文件时,是否是错误设置为静态链接标志
CHECK_LDFLAGS := $(if $(findstring static,$(LDFLAGS)),'Error: build file(*.so) not use static flag',)############################################################
# 文件和路径搜索部分(非常用项,修改需谨慎)
############################################################
INCLUDE_MODULE_NAMES := $(strip $(INCLUDE_MODULE_NAMES))
EXCLUDE_MODULE_NAMES := $(strip $(EXCLUDE_MODULE_NAMES))
COMMON_DIR_NAMES := $(strip $(COMMON_DIR_NAMES))
EXCLUDE_DIR_NAMES := $(strip $(EXCLUDE_DIR_NAMES))
SPACE :=
SPACE:= $(SPACE) $(SPACE)# 如果是总makefile
ifneq ($(MAKE_SUB),)# 不包含test目录名的排除目录名的列表tmp := $(subst $(SPACE),\\\|,$(strip $(EXCLUDE_DIR_NAMES)))# 执行make clean命令的makefile所在目录列表,包含test目录MF_CLEAN_DIRS := $(dir $(shell find . -type f -iname Makefile | grep -v $(tmp)))MF_CLEAN_DIRS := $(foreach dir,$(MF_CLEAN_DIRS),$(shell if [ ! $(dir) = ./ ]; then echo $(dir); fi;))
endif# 要排除的目录名列表
EXCLUDE_DIR_NAMES += $(EXCLUDE_MODULE_NAMES) $(TEST_DIR_NAME)
EXCLUDE_DIR_NAMES := $(subst $(SPACE),\\\|,$(strip $(EXCLUDE_DIR_NAMES)))
# 如果是总makefile
ifneq ($(MAKE_SUB),)# 执行make命令的makefile所在目录列表,不包含test目录MF_MAKE_DIRS := $(dir $(shell find . -type f -iname Makefile | grep -v $(EXCLUDE_DIR_NAMES)))MF_MAKE_DIRS := $(foreach dir,$(MF_MAKE_DIRS),$(shell if [ ! $(dir) = ./ ]; then echo $(dir); fi;))
endif# 如果没设置临时,默认等于tmp
ifeq ($(TMP_DIR),)TMP_DIR := tmp
endif# build.mk文件所在目录,如果没有build.mk则等于当前目录BUILDMK_DIR ?= $(shell result=$(CUR_DIR); \for dir in $(strip $(subst /, ,$(CUR_DIR))); \do \dirs=$$dirs/$$dir; \if [ -f $$dirs/build.mk ]; then \result=$$dirs; \fi; \done; \echo $$result; \)# 项目根目录全路径名称
ifneq ($(PROJECT_ROOT_DIR_NAME),)PROJECT_ROOT_DIR := $(shell result=$(BUILDMK_DIR); \for dir in $(strip $(subst /, ,$(CUR_DIR))); \do \dirs=$$dirs/$$dir; \if [ $$dir = $(PROJECT_ROOT_DIR_NAME) ]; then \result=$$dirs; \break; \fi; \done; \echo $$result; \)
elsePROJECT_ROOT_DIR := $(BUILDMK_DIR)
endif# 向上搜索COMMON_DIR_NAMES指定名称的公共目录,库文件编译除外
ifeq ($(IS_LIB_TARGET),)
ifneq ($(PROJECT_ROOT_DIR),)COMMON_DIR_NAMES += $(INCLUDE_MODULE_NAMES)tmp := $(strip $(subst /, ,$(subst $(PROJECT_ROOT_DIR),,$(SRC_DIR))))tmp := $(shell Dirs=$(PROJECT_ROOT_DIR); \echo $$Dirs; \for dir in $(tmp); \do \Dirs=$$Dirs/$$dir; \echo $$Dirs; \done; \)COMMON_DIRS := $(shell \for dir in $(tmp); \do \for name in $(COMMON_DIR_NAMES); \do \if [ -d $$dir/$$name ];then \echo $$dir/$$name; \fi; \done; \done; \)
endif
endif# 所有文件列表
SRC_DIRS += $(SRC_DIR)
tmp := $(COMMON_DIRS) $(filter-out $(COMMON_DIRS:%=%%),$(SRC_DIRS))
ALL_FILES := $(shell find $(tmp)  \-type f -name '*.h' -o -type f -name '*.hpp' \-o -type f -name '*.c' -o -type f -name '*.cpp' \-o -type f -name '*.a' -o -type f -name '*.so' \| grep -vw 'main.c\|main.cpp' \| grep -vw $(EXCLUDE_DIR_NAMES))
EXCLUDE_DIR_NAMES :=
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))ALL_FILES += $(shell find $(CUR_DIR) -type f -name '*.h' -o -type f -name '*.hpp' \-o -type f -name '*.c' -o -type f -name '*.cpp' \-o -type f -name '*.a' -o -type f -name '*.so' \| grep -vw 'main.c\|main.cpp\|'$(TMP_DIR))
endif# 所有库文件
LIB_FILES := $(filter %.a %.so,$(ALL_FILES))
ifneq ($(LIB_FILES),)# 库文件列表ifneq ($(IS_LIB_TARGET),)LIB_FILES := $(filter $(CUR_DIR)%,$(LIB_FILES))tmp := $(TMP_TARGET:lib%=%)LIB_FILES := $(filter-out $(CUR_DIR)/%$(tmp).a $(CUR_DIR)/%$(tmp).so,$(LIB_FILES))endif  # 所有库文件目录LIB_DIRS += $(sort $(dir $(LIB_FILES)))LIB_DIRS := $(strip $(LIB_DIRS))LIB_OUT_DIRS := $(LIB_DIRS:%=%%)LOAD_LIB_PATH := $(sort $(dir $(filter %.so,$(LIB_FILES))))# 库文件列表LIB_FILES := $(notdir $(LIB_FILES))# 如果是交叉编译,则使用交叉编译链的库文件并排除同名的非交叉编译链的库文件ifneq ($(CROSS_COMPILE),)ifneq ($(CROSS_COMPILE_LIB_KEY),)tmp := $(filter lib$(CROSS_COMPILE_LIB_KEY)%,$(LIB_FILES))tmp := $(subst $(CROSS_COMPILE_LIB_KEY),,$(tmp))LIB_FILES := $(filter-out $(tmp),$(LIB_FILES))endifelse# 不是交叉编译链,排除交叉编译链的库文件LIB_FILES := $(filter-out lib$(CROSS_COMPILE_LIB_KEY)%,$(LIB_FILES))endif# 静态库文件列表STATIC_LIB_FILES := $(filter %.a,$(LIB_FILES))STATIC_LIB_FILES := $(STATIC_LIB_FILES:lib%.a=-l%)# 动态库文件列表DYNAMIC_LIB_FILES := $(filter %.so,$(LIB_FILES))LIB_FILES :=DYNAMIC_LIB_FILES := $(DYNAMIC_LIB_FILES:lib%.so=-l%)
endif # ifneq ($(LIB_FILES),)# 源文件目录及obj文件列表
tmp := $(filter %.c %.cpp,$(ALL_FILES))
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
OBJ_FILES := $(filter $(CUR_DIR)%,$(tmp))
tmp := $(filter-out $(CUR_DIR)%,$(tmp))
endif
ifneq ($(LIB_DIRS),)# 过滤译库文件(.a/.so)的源码文件tmp := $(filter-out $(LIB_OUT_DIRS),$(tmp))
endif
# .o文件列表
TMP_DIR := $(TMP_DIR)/
OBJ_FILES += $(tmp)
OBJ_FILES := $(OBJ_FILES:%.c=$(TMP_DIR)%.o)
OBJ_FILES := $(OBJ_FILES:%.cpp=$(TMP_DIR)%.o)
MAIN_FILE := $(MAIN_FILE:%.c=$(TMP_DIR)%.o)
MAIN_FILE := $(MAIN_FILE:%.cpp=$(TMP_DIR)%.o)
ifeq ($(OBJ_FILES),)TMP_TARGET := $(TARGET)
endif# 头文件所在目录
tmp := $(sort $(dir $(filter %.h %.hpp,$(ALL_FILES))))
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
INC_DIRS += $(filter $(CUR_DIR)%,$(tmp))
tmp := $(filter-out $(CUR_DIR)%,$(tmp))
endif
# 如果指定头文件目录名,则过滤掉其它的目录
ifneq ($(INC_DIR_NAMES),)tmp := $(foreach item,$(tmp),\$(shell \isfind=n; \for name1 in $(subst /, ,$(item)); \do \for name2 in $(INC_DIR_NAMES); \do \if [ $$name1 = $$name2 ]; then \isfind=y; \break; \fi; \done; \if [ $$isfind = y ]; then \break; \fi; \done; \if [ $$isfind = y ]; then \echo $(item); \fi; \) \)
else
# 头文件默认和库文件一起放或者放inc目录下ifneq ($(LIB_DIRS),)tmp2 := $(LIB_DIRS:%=%inc/)tmp2 := $(tmp2:%=%%) $(LIB_OUT_DIRS)tmp2 := $(filter $(tmp2),$(tmp))
# 过滤译库文件(.a/.so)的其它头文件的目录tmp2 += $(filter-out $(LIB_OUT_DIRS),$(tmp))tmp := $(sort $(tmp2))tmp2 :=endif
endif
ALL_FILES :=
INC_DIRS := $(strip $(INC_DIRS)) $(tmp)
tmp :=
INC_DIRS := $(INC_DIRS:%=-I%)# 所有库目录
LIB_DIRS := $(LIB_DIRS:%=-L%)# *.c/*/cpp文件搜索的目录,用于编译设置
#VPATH := $(SRC_DIRS)# 临时库文件,将所有.o文件合并为一个临时.a文件,再和main.o文件链接,
# 避免链接进无用符号造成TARGET文件体积臃肿。
ifneq ($(OBJ_FILES),)TMP_LIB_TARGET := libtmp.aTMP_LIB_DIRS := -L$(TMP_DIR) $(TMP_LIB_TARGET:lib%.a=-l%)TMP_LIB_TARGET := $(TMP_DIR)$(TMP_LIB_TARGET)
endif############################################################
# 链接成最终文件
############################################################
all: FIRST_EXEC $(TARGET)FIRST_EXEC:
ifdef DEB@echo '**************************************'@echo 'PROJECT_ROOT_DIR:'$(PROJECT_ROOT_DIR)@echo '**************************************'@echo 'TARGET:'$(TARGET)@echo '**************************************'@echo 'CUR_DIR:'$(CUR_DIR)@echo '**************************************'@echo 'SRC_DIR:'$(SRC_DIR)@echo '**************************************'@echo 'COMMON_DIRS:'$(COMMON_DIRS)@echo '**************************************'@echo 'LIB_DIRS:'$(LIB_DIRS)@echo '**************************************'@echo 'STATIC_LIB_FILES:'$(STATIC_LIB_FILES)@echo '**************************************'@echo 'DYNAMIC_LIB_FILES:'$(DYNAMIC_LIB_FILES)@echo '**************************************'@echo 'INC_DIRS:'$(INC_DIRS)@echo '**************************************'@echo 'OBJ_FILES:'$(OBJ_FILES)@echo '**************************************'
endif
#*********************************************
# 总makefile模式,编译子目录下的所有makefile
ifneq ($(MF_MAKE_DIRS),)$(STEP_INFO) '[step] submakefile is making...'@for dir in $(MF_MAKE_DIRS); do $(MAKE) -C $$dir; done;$(STEP_INFO) '[step] submakefile make done'
endif#*********************************************
# 生成exec程序
$(TMP_TARGET): $(TMP_LIB_TARGET) $(MAIN_FILE)
ifeq ($(INFO),1)@echo '**************************************'
endif$(STEP_INFO) '[step] Building exec file: '$@$(BUILD_INFO)$(LD) $(MAIN_FILE) $(LIB_DIRS) $(TMP_LIB_DIRS) $(LDFLAGS) -o $@
ifneq ($(LOAD_LIB_PATH),)
# 如果调用到.so文件,请执行以下命令设置库文件的搜索路径变量:LD_LIBRARY_PATH@echo '**********************************************************'@echo@echo 'Please execute the following command to load the LIB path, if you use it(.so):'@echo 'LD_LIBRARY_PATH=$(LOAD_LIB_PATH) && export LD_LIBRARY_PATH'@echo
endif#*********************************************
# 生成临时静态库文件
$(TMP_LIB_TARGET): $(OBJ_FILES)
ifeq ($(INFO),1)@echo '**************************************'
endif$(STEP_INFO) '[step] Building temp static lib file: '$@$(BUILD_INFO)$(AR) $(AR_FLAGS) -o $@ $^#*********************************************
# 生成静态库文件
$(TMP_TARGET).a: $(OBJ_FILES)
ifeq ($(INFO),1)@echo '**************************************'
endif$(STEP_INFO) '[step] Building static lib file: '$@$(BUILD_INFO)$(AR) $(AR_FLAGS) -o $@ $^#*********************************************
# 生成动态库文件
$(TMP_TARGET).so: $(OBJ_FILES)
ifeq ($(INFO),1)@echo '**************************************'
endif$(STEP_INFO) '[step] Building dynamic lib file: '$@
ifneq ($(CHECK_LDFLAGS),)@echo $(CHECK_LDFLAGS)
endif$(BUILD_INFO)$(LD) -o $@ $^ $(LIB_DIRS) $(LDFLAGS) $(DYNC_FLAGS)#*********************************************
# 编译c代码文件
$(TMP_DIR)%.o: %.c
ifeq ($(INFO),1)@echo '**************************************'
endif$(STEP_INFO) '[step] Compiling c file: '$<@$(MKDIR) $(dir $@)$(BUILD_INFO)$(CC) $(CC_FLAGS) -c $< -o $@ $(INC_DIRS)#*********************************************
# 编译c++代码文件
$(TMP_DIR)%.o: %.cpp
ifeq ($(INFO),1)@echo '**************************************'
endif$(STEP_INFO) '[step] Compiling cpp file: '$<@$(MKDIR) $(dir $@)$(BUILD_INFO)$(CXX) $(CXX_FLAGS) -c $< -o $@ $(INC_DIRS)#*********************************************
# 头文件关联
-include $(OBJ_FILES:.o=.d)############################################################
# 清理临时文件
############################################################
clean:
ifneq ($(MF_CLEAN_DIRS),)
# 总makefile模式$(STEP_INFO) '[step] submakefile cleaning...'@for dir in $(MF_CLEAN_DIRS); do $(MAKE) -C $$dir clean; done;$(STEP_INFO) '[step] submakefile cleaned'
endif
#*********************************************
# 不删除库目标文件
ifeq ($(IS_LIB_TARGET),)@if [ -f $(TARGET) ]; then $(RM) -f $(TARGET); fi;
endif
# 子makefile模式,删除临时目录@if [ -d $(TMP_DIR) ]; then $(RM) -r $(TMP_DIR); fi;@echo '[step] cleaned'.PHONY: all clean

 

关键字: make makefile shell find grep wildcard notdir patsubst findstring wordlist suffix foreach gcc g++ c++11 嵌入脚本 静态链接库 动态链接库 静态动态混合编译链接 语法 内嵌函数 函数嵌套执行 替换字符串 判断字符串相等 遍历数组  执行shell脚本 循环 逻辑与 逻辑或  查找文件  搜索文件目录 获取目录名 获取文件名

 

转载请注明出处!

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部