一个适用于 arm cortex-M3 的通用 makefile()

# shell/dos命令
MKDIR = -mkdir
RM = rm
RMFLAGS = -fR
###############################################################################
# 常量
NOTHING =
STR_NULLINE = ""
STR_MULSPACE = "           Finished --->"
STR_COMPIL = "Compiling file: "
STR_LINK   = "Linking   file: "
# NM_TARGET为最终的目标名,NM_MAP为map文件名
# SRC_TYPE为输入类型,0:SRCS为ALL_DIRC下的所有.c源文件。
#                     1:SRCS为用户给定的绝对路径的.c源文件(适用于含有多个重名.c文件的情况),
#                        要确保其使用的头文件已经加入到ALL_DIRH(nakefile用)和INC_PATH(gcc用)中
#include $(INC_MAK)
NM_TARGET = a_default
P_ADDR =
SRC_TYPE = 0
###############################################################################
# 编译链接用目录的设置:分别为链接前的.o目录,链接后的二进制目标文件目录,依赖文件目录
DIR_OBJS = objs
DIR_BINS = bins
DIR_DEPS = deps
DIR_CLEAN = $(DIR_OBJS) $(DIR_BINS) $(DIR_DEPS)
###############################################################################
# 获取工程目录下的所有目录项到CHILD_DIRS。
# INC_PATH为gcc的头文件搜索选项的一部分
CHILD_DIRS = $(shell ls -R | grep :$)
CHILD_DIRS := $(patsubst %:,%$(NOTHING),$(CHILD_DIRS))
INC_PATH := $(filter-out $(join ./ ./ ./,$(DIR_CLEAN)),$(CHILD_DIRS))
INC_PATH := $(patsubst .%,-I.%,$(INC_PATH))
CHILD_DIRS := $(filter ./%,$(CHILD_DIRS))
CHILD_DIRS := $(patsubst ./%,$(NOTHING)%,$(CHILD_DIRS))
  # vpath或者VPATH指定的路径仅适用于makefile的(模式)规则搜寻文件的情况
  # 对于gcc工具链的.h和.a(静态库),则需要另外指定包含路径,并将该路径加入到gcc命令行中
  # USER_DIRC和USER_DIRH为用户指定的非工程目录下的第三方.c和.h文件所在的目录
  # SSG_DIRC和SSG_DIRH为SSG提供的.c和.h文件所在的目录
  # USER_INC_PATH和SSG_INC_PATH为用户和SSG提供的头文件所在目录(gcc用)
  # 最终的INC_PATH的搜索路径顺序为  USER_DIRH-->SSG_DIRH-->CHILD_DIRS-->gcc的头文件目录
  #       其中,USER_DIRH和SSG_DIRH专门用于搜索include "" 类型的头文件
  # ALL_DIRC和ALL_DIRH为总的.c和.h文件所在的目录
  # 当用户目录为多个时,采用""dir1" "dir2""这种形式,比如:USER_DIRH=""E:\AGM\gcc_test\makefile_test\cm3_app1" "E:\C_code\hello\lib""
USER_DIRC =
USER_DIRH =
SSG_DIRC =
SSG_DIRH =
USER_INC_PATH = $(foreach dir,$(USER_DIRH),$(addprefix "-iquote ",$(dir)))
SSG_INC_PATH = $(foreach dir,$(SSG_DIRH),$(addprefix "-iquote ",$(dir)))
INC_PATH += $(USER_INC_PATH) $(SSG_INC_PATH)
ALL_DIRC := $(USER_DIRC) $(SSG_DIRC) $(CHILD_DIRS)
ALL_DIRH := $(USER_DIRH) $(SSG_DIRH) $(CHILD_DIRS)
ALL_DIRC := $(strip $(filter-out $(DIR_CLEAN),$(ALL_DIRC)))
ALL_DIRH := $(strip $(filter-out $(DIR_CLEAN),$(ALL_DIRH)))
vpath %.h $(ALL_DIRH)
vpath %.c $(ALL_DIRC)
vpath %.d $(DIR_DEPS)
vpath %.o $(DIR_OBJS)
vpath %.out $(DIR_BINS)
vpath %.bin $(DIR_BINS)
vpath %.hex $(DIR_BINS)
vpath %.elf $(DIR_BINS)
###############################################################################
# SRCS用户输入的.c源文件,不输入的情况下就是指工程的全部.c文件
  # SRCS_EXCLUDE为全编译时需要排除在外的.c文件
  # 如果用户输入的是路径+名称,则需要去掉路径
#AX := $(shell ls -R $(ALL_DIRC)| grep \\\.c$)
#BX = $(shell echo $(AX))
SRCS_EXCLUDE =
SRCS := $(shell ls -R $(ALL_DIRC)| grep \\\.c$)
#或者SRCS := $(shell ls -R | grep '\'\.c$$),3-6个\和1-3个$都可以
SRCS := $(filter-out $(SRCS_EXCLUDE),$(SRCS))
#
# 中间代码.o、最终目标、依赖项的名称及路径。默认情况下,最终代码为elf格式
ifeq ($(MAKECMDGOALS), just_link)
OBJS := $(shell ls -R $(DIR_OBJS)| grep \\\.o$)
else
OBJS = $(notdir $(SRCS:.c=.o))
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(notdir $(SRCS:.c=.d))
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
endif


BINS = $(NM_TARGET).elf
BINS :=$(addprefix $(DIR_BINS)/, $(BINS))
MAPS := $(NM_TARGET).map
MAPS := $(addprefix $(DIR_BINS)/, $(MAPS))
###############################################################################
# PATH_TOOLCHAIN的路径最后需要为"/"
PATH_TOOLCHAIN =
CROSS_COMPILE ?= arm-none-eabi-
OPTS_CPU ?= -mcpu=cortex-m3 -mthumb -nostartfiles
OPTS_DIAG ?= -Wall -Wextra
OPTS_CLIB ?= --specs=nano.specs
OPTS_LDS ?= -T sections.lds


ifeq ($(SRC_TYPE),0)
OPTS_INC := $(INC_PATH)
endif
ifeq ($(SRC_TYPE),1)
OPTS_INC :=$(addprefix -I,$(INC_PATH))
endif


OPTS_LIB ?=
OPTS_DEF ?=
OPTS_MAP = -Wl,-Map,$(MAPS)
debug ?= y
ifeq ($(debug), y)
OPTS_DEBUG ?= -g2
OPTS_OPTIM ?= -O2
else
OPTS_DEBUG ?=
OPTS_OPTIM ?= -Os
endif
# USER_CCFLAGS和USER_LDFLAGS为用户指定的其它一些用于编译和链接的选项
USER_CCFLAGS =
USER_LDFLAGS =
# 交叉编译工具链
TOOL_CHAIN = $(PATH_TOOLCHAIN)$(CROSS_COMPILE)
CC := $(TOOL_CHAIN)gcc
# 等价于gcc -lstdc++
LD := $(TOOL_CHAIN)g++
OBJCP := $(TOOL_CHAIN)objcopy
OBJDP := $(TOOL_CHAIN)objdump
RDELF := $(TOOL_CHAIN)readelf
OBJSZ := $(TOOL_CHAIN)size
ADR2LINE := $(TOOL_CHAIN)addr2line
CCFLAGS := $(strip $(OPTS_CPU) $(OPTS_DIAG) $(OPTS_CLIB) $(OPTS_DEBUG) $(OPTS_OPTIM) $(OPTS_INC) $(OPTS_DEF) $(USER_CCFLAGS))
LDFLAGS := $(strip $(OPTS_CPU) $(OPTS_DIAG) $(OPTS_CLIB) $(OPTS_DEBUG) $(OPTS_OPTIM) $(OPTS_LDS) $(OPTS_LIB) $(OPTS_MAP) $(USER_LDFLAGS))
###############################################################################
IHEX = $(NM_TARGET).hex
IHEX := $(addprefix $(DIR_BINS)/, $(IHEX))
IBIN = $(NM_TARGET).bin
IBIN := $(addprefix $(DIR_BINS)/, $(IBIN))
DISASSEM = $(NM_TARGET).s
DISASSEM := $(addprefix $(DIR_BINS)/, $(DISASSEM))
####################################################################################################################################
# 防止修改某些依赖文件之后,再多次make时出现修改部分和没有修改的部分交替编译而形成死循环的情况。
# 比如:两个文件 foo.c和main.c,1)执行make 2)修改foo.c 3)执行make 4)执行make 5)执行make......
# 正常的情况是:步骤3)会编译foo.c,步骤4)和5)都不会执行任何编译操作
# 但如果没有下面的代码,则可能出现:步骤4)编译main.c,步骤5)编译foo.c...,然后会交替编译多次。
ifeq ("$(wildcard $(DIR_DEPS))", "")
DEPS_DIR_DEPS := $(DIR_DEPS)
endif
ifeq ("$(wildcard $(DIR_OBJS))", "")
OBJS_DIR_OBJS := $(DIR_OBJS)
endif
ifeq ("$(wildcard $(DIR_BINS))", "")
BINS_DIR_BINS := $(DIR_BINS)
endif
###############################################################################
FILE_DEL = $(addsuffix /*,$(DIR_CLEAN))
####################################################################################################################################
# make all .c or .cpp
.PHONY: ALL just_compile just_link mk_ihex mk_bin mk_size mk_deassem addr2line clean
ALL: $(BINS)
@$(MAKE) --no-print-directory mk_size
###############################################################################
# 如果包含时,不存在
ifneq ($(MAKECMDGOALS), clean)
-include $(DEPS)
endif
# 三个文件夹objs、bins和deps,只有需要时才创建(展开后为三个目标):
  #  调用目标$(BINS)时,会先查看目录bins是否存在,不存在时会调用该条规则
  #  调用目标$(DIR_OBJS)/%.o时,会先查看目录objs是否存在,不存在时会调用该条规则
  #  调用目标$(DIR_DEPS)/%.d时,会先查看目录deps是否存在,不存在时会调用该条规则
$(DIR_CLEAN):
@echo "Creating directory $@ ..."
@$(MKDIR) $@
###############################################################################
  # 生成elf目标文件的规则(因为目标只有一个所以这样写)
$(BINS): $(BINS_DIR_BINS) $(OBJS)
@echo  $(STR_LINK) $(notdir $(filter %.o, $^)) ...
@$(LD) $(LDFLAGS)  -o $@ $(filter %.o, $^)
@echo  $(STR_MULSPACE)$@
  # 由.c文件生成.o文件的规则,最好不要把目标写成$(OBJS)。只有%才是模式规则
$(DIR_OBJS)/%.o: $(OBJS_DIR_OBJS) %.c
@echo  $(STR_COMPIL) $(notdir $(filter %.c, $^)) ...
@$(CC) $(CCFLAGS)  -o $@ -c $(filter %.c, $^)
@echo  $(STR_MULSPACE)$@
# @echo $(filter %.c, $^)
# 先决条件为:1)DIR_DEPS目录存在;2)寻找对应的.c文件。生成的.d文件与对应的.c文件重名
$(DIR_DEPS)/%.d: $(DEPS_DIR_DEPS) %.c
@echo "Making $@ ..."
# @echo $(filter %.c, $^)
@set -e;\
$(RM) $(RMFLAGS) $@ ; \
$(CC) -MM $(OPTS_INC) $(filter %.c, $^) > $@.$$$$ ; \
sed 's,\($*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.$$$$ > $@ ; \
$(RM) $(RMFLAGS) $@.$$$$
###############################################################################
just_compile: $(OBJS)
# @echo $(words $(SRCS))
# @echo $(SRCS)
# @echo $(dir $(SRCS))
# @echo $(ALL_DIRH)
# @echo "Just compiling $(filter %.o, $^) ..."
###############################################################################
just_link: $(BINS)
# @echo "Just linking $(filter %.o, $^) ..."
@$(MAKE) --no-print-directory mk_size
###############################################################################
mk_ihex: $(IHEX)
@echo ....................$^ has created 
$(IHEX): $(BINS_DIR_BINS) $(BINS)
@$(OBJCP) -g -S -O ihex $(filter %.elf, $^) $@
@echo intel hex format file : $@ creating...
###############################################################################
mk_bin: $(IBIN)
@echo ....................$^ has created
$(IBIN): $(BINS_DIR_BINS) $(BINS)
@echo binary file : $@ creating...
@$(OBJCP) -g -S -O binary $(filter %.elf, $^) $@
###############################################################################
mk_size: $(BINS_DIR_BINS) $(BINS)
@echo $(STR_NULLINE) 
@echo program size of $(notdir $(BINS)):
@$(OBJSZ) -B $(BINS)
###############################################################################
mk_deassem: $(DISASSEM)
@echo disassembled file $^ has created
$(DISASSEM): $(BINS_DIR_BINS) $(BINS)
@echo $(filter %.elf, $^) is disassembling...
@$(OBJDP) -D -S $(BINS) > $(DISASSEM)
###############################################################################
addr2line: $(BINS_DIR_BINS) $(BINS)
$(ADR2LINE) -fpae $(BINS) $(P_ADDR)
clean:

@$(RM) $(RMFLAGS)v $(DIR_CLEAN)

猜你喜欢

转载自blog.csdn.net/fdcp123/article/details/61922948