您的位置:首页 > 其它

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

2017-03-13 17:40 531 查看
# 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)

这是原来做项目的时候写的,结果老板对开源的东西不感冒。

还有一份 cmd 下如何动态调用的说明,如果有人感兴趣的话,可以联系我(3073504973)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gcc GNU makefile