#*************************************************************************
#  **
#  ** File         : Makefile
#  ** Abstract     : This is the introduction to the document
#  ** Author       : wr
#  ** mail         : 791314247@q.com
#  ** Created Time : 2020年11月22日 星期日 11时58分06秒
#  ** copyright    : COPYRIGHT(c) 2020
#  **
#  ************************************************************************/

#当由用户传入的参数V等于1时，条件为真，输出编译信息，当V不等于1时禁止信息
ifneq ($(V),1)
Q := @
else
Q :=
endif

#以下项目需用户根据需要更改
# 是否将debug信息编译进.elf文件，默认打开
DEBUG   := 1
# 选择优化等级:
# 1. gcc中指定优化级别的参数有：-O0、-O1、-O2、-O3、-Og、-Os、-Ofast。
# 2. 在编译时，如果没有指定上面的任何优化参数，则默认为 -O0，即没有优化。
# 3. 参数 -O1、-O2、-O3 中，随着数字变大，代码的优化程度也越高，不过这在某种意义上来说，也是以牺牲程序的可调试性为代价的。
# 4. 参数 -Og 是在 -O1 的基础上，去掉了那些影响调试的优化，所以如果最终是为了调试程序，可以使用这个参数。不过光有这个参数也是不行的，这个参数只是告诉编译器，编译后的代码不要影响调试，但调试信息的生成还是靠 -g 参数的。
# 5. 参数 -Os 是在 -O2 的基础上，去掉了那些会导致最终可执行程序增大的优化，如果想要更小的可执行程序，可选择这个参数。
# 6. 参数 -Ofast 是在 -O3 的基础上，添加了一些非常规优化，这些优化是通过打破一些国际标准（比如一些数学函数的实现标准）来实现的，所以一般不推荐使用该参数。
# 7. 如果想知道上面的优化参数具体做了哪些优化，可以使用 gcc -Q --help=optimizers 命令来查询，比如下面是查询 -O3 参数开启了哪些优化：
OPT     := -Og
# 输出文件的名称，默认为main
TARGET  := main
# 链接文件的名称
LDNAME  := fm33lc02x_flash.ld
# 启动文件的名称
START_FILE_NAME := startup_fm33lc0xx.s
# 芯片型号，用于Jlink仿真调试、下载
CHIP    := FM33LC02X

# 编译器定义
CC      := arm-none-eabi-gcc
SZ      := arm-none-eabi-size
OBJCOPY := arm-none-eabi-objcopy
GDB     := arm-none-eabi-gdb
BIN     := $(OBJCOPY) -O binary -S
HEX     := $(OBJCOPY) -O ihex

#################### CFLAGS Config Start ##########################
CPU = -mcpu=cortex-m0
#FPU = -mfpu=fpv4-sp-d16
#FLOAT-ABI = -mfloat-abi=hard
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

#搜索所有的h文件,并输出携带-I的.h文件路径
C_INCLUDES = $(addprefix -I,$(sort $(dir $(shell find ./ -type f -iname "*.h"))))
#所有的头文件路径
# C_INCLUDES =  \
# -I$(shell pwd)/libraries/FM33LC0xx_LL_Driver/Inc \
# -I$(shell pwd)/libraries/FM33LC0xx_LL_Driver/CMSIS/Device/FM/FM33xx/Include \


C_DEFS =  \
-DFM33LC0XX \
-DUSE_FULL_ASSERT \
-D_DLIB_FILE_DESCRIPTOR

#编译参数
CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
#开关警告
CFLAGS += -Wall

 #当开启DEBUG功能时携带DEBUG参数
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif

#自动生成依赖文件
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
#################### CFLAGS Config End ##########################

#链接文件名称和所在路径
LDSCRIPT = $(shell find -type f -iname $(LDNAME))
# libraries
LIBS = -lc -lm -lnosys 
LIBDIR = 
#链接指令集
#LDFLAGS  = $(MCU) -T$(LDSCRIPT) -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=test.map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group
LDFLAGS  = $(MCU) -T$(LDSCRIPT) -specs=nano.specs $(LIBDIR) $(LIBS) -Wl,-Map=build/$(TARGET).map,--cref -Wl,--gc-sections

#搜索启动文件路径
START_FILE_SOURCES = $(shell find ./ -type f -iname $(START_FILE_NAME))
#删除原来的启动文件后缀名，并添加新的后缀名.o
START_FILE_OBJ = $(addsuffix .o, $(basename $(START_FILE_NAME)))


#搜索所有的c文件,并输出携带绝对路径的.c文件
C_SOURCES = $(shell find ./ -type f -iname "*.c")
#将.c替换为.o
C_OBJ     = $(C_SOURCES:%.c=%.o)

#去掉终极目标的原始路径前缀并添加输出文件夹路径前缀(改变了依赖文件的路径前缀，需要重新指定搜索路径)
OBJECTS = $(addprefix build/, $(START_FILE_OBJ))
OBJECTS += $(addprefix build/,$(notdir $(C_SOURCES:.c=.o)))
#指定makefile搜索文件的路径(假如终极目标的依赖文件不携带.c文件所在的路径，
#且不指定搜索路径，makefile会报错没有规则制定目标)
vpath %.c $(sort $(dir $(C_SOURCES)))  #取出路径并去重和排序(以首字母为单位)
vpath %.s $(sort $(dir $(START_FILE_SOURCES)))
vpath %.S $(sort $(dir $(START_FILE_SOURCES)))


#指定为伪目标跳过隐含规则搜索，提升makefile的性能，并防止make时携带的参数与实际文件重名的问题
.PHONY:all cleanAll clean printf JLinkGDBServer debug download commit

all : build $(TARGET).elf $(TARGET).bin $(TARGET).hex


#链接所有的.o生成.elf文件
$(TARGET).elf : $(OBJECTS)    #build/xxxx.o
	$(Q) $(CC) $(LDFLAGS) -o $@ $^
	@echo "make $@:"
	$(Q) $(SZ) $@

#编译启动文件
build/$(START_FILE_OBJ) : $(START_FILE_NAME)
	$(Q) $(CC) -c $(CFLAGS) -x assembler-with-cpp -o $@ $<
	@echo "build $(notdir $<)"

#编译工程
build/%.o : %.c
	$(Q) $(CC) -c $(CFLAGS) -o $@ $<
	@echo "build $(notdir $<)"

build :
	mkdir build
	@echo "mkdir build"

%.bin : $(TARGET).elf
	$(Q) $(BIN) $< $@

%.hex : $(TARGET).elf
	$(Q) $(HEX) $< $@

#自动生成依赖文件
# build/%.d : %.c
# 	@set -e;rm -f $@; \
# 	$(CC) -MM $< > $@.$$$$; \
# 	sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
# 	rm -f $@.$$$$
# 	@echo "make $@"

cleanAll: clean
	$(Q)$(RM) *.elf *.hex *.bin
	$(Q)echo "clean all *.elf *.hex *.bin"; 

clean:
	$(Q)$(RM) $(shell find ./ -type f -iname "*.o")
	$(Q)$(RM) $(shell find ./ -type f -iname "*.d")
	$(Q)$(RM) $(shell find ./ -type f -iname "*.d.*")
	$(Q)$(RM) $(shell find ./ -type f -iname "*.map")
	$(Q)$(RM) $(shell find ./ -type f -iname "*.gdb")
	$(Q)echo "clean all *.o *.d *.map";

printf:
	$(Q)echo $(info $(OBJECTS))

JLinkGDBServer:
	$(Q)JLinkGDBServer -select USB -device $(CHIP) \
	-endian little -if SWD -speed 4000 -noir -LocalhostOnly

debug:
	$(Q)make
	$(Q)echo target remote localhost\:2331 > gdb.gdb
	$(Q)echo monitor reset >> gdb.gdb
	$(Q)echo monitor halt >> gdb.gdb
	$(Q)echo load >> gdb.gdb
	$(Q)echo b main >> gdb.gdb
	$(Q)echo - >> gdb.gdb
	$(Q)echo c >> gdb.gdb
	$(Q)-$(GDB) $(TARGET).elf --command=gdb.gdb 
	$(Q)$(RM) gdb.gdb

download:
	$(Q)make
	$(Q)echo "h" > jlink.jlink
	$(Q)echo "loadfile" $(TARGET).hex >> jlink.jlink
	$(Q)echo "r" >> jlink.jlink
	$(Q)echo "qc" >> jlink.jlink
	$(Q)JLinkExe -device $(CHIP) -Speed 4000 -IF SWD -CommanderScript jlink.jlink
	$(Q)$(RM) jlink.jlink

commit:
	$(Q)git add .
	$(Q)echo read -p \"Please input git commit explain:\" explain > git.so
	$(Q)echo if test -z \"\$$explain\"\; then explain=\"Normal upgrade\"\; fi >> git.so
	$(Q)echo echo \$$explain >> git.so
	$(Q)echo git commit -m \"'$$'explain\" >> git.so
	$(Q)bash ./git.so
	$(Q)$(RM) git.so
	$(Q)git push

include $(wildcard build/*.d)

