当前位置: 首页 > 工具软件 > Nuclei > 使用案例 >

1.3 nuclei sdk Makefile分析

莫英喆
2023-12-01

Make 命令

make PROGRAM=application/baremetal/helloworld SOC=gd32vf103 BOARD=gd32vf103c_longan_nano all

1. 根目录Makefile

# 默认代码编译路径
PROGRAM :=baremetal/helloworld

# help信息
.PHONY: __help
__help:
    @echo "Help about Build/Run/Debug/Clean Nuclei SDK Application"
    @echo "make [PROGRAM=/path/to/app]  help                        Show Build System Help Message"
    @echo "make [EXTRA_APP_ROOTDIRS=/path/to/extraapps] cleanall    Clean all the applications"
    @echo "Examples:"
    @echo "make PROGRAM=application/baremetal/helloworld all"
    @echo "make PROGRAM=application/baremetal/helloworld SOC=gd32vf103 BOARD=gd32vf103v_rvstar clean all"
    @echo "make -k cleanall"
    @echo "make -k SOC=gd32vf103 BOARD=gd32vf103v_rvstar cleanall"
    @echo "make -k EXTRA_APP_ROOTDIRS=soc_testcases cleanall"

# wildcard可以判读编译代码的路径是否存在,不存在返回空
VALID_PROGRAM=$(wildcard $(PROGRAM))
# 判断编译代码中是否有Makefile文件
VALID_PROGRAM_MAKEFILE=$(wildcard $(PROGRAM)/Makefile)

# make的时候,只有下面的这些命令是有效的
# Valid SDK Rules accepted by build system
VALID_SDK_RULES := all info help bin size dasm upload run_openocd run_gdb clean debug

# 指定app源码的根目录
# Default root directories to search
APP_ROOTDIRS := application test
# Extra application root directories passed by make
# 其他app 源码根目录,适合放玩家自己的app
EXTRA_APP_ROOTDIRS ?=

# TOTAL_ROOTDIRS中记录所有的app根目录
# get all the root directories for applications
TOTAL_ROOTDIRS := $(APP_ROOTDIRS) $(EXTRA_APP_ROOTDIRS)

# 字面意思就是默认的搜索模式
# 实质就是在要搜索的路径下面加上这些
# 比如搜索app/
# 那么就会搜索app/* app/*/* app/*/*/* ...
# Default search patterns
SEARCH_PATTERNS := * */* */*/* */*/*/*

# 首先说一下foreach函数 $(foreach <var>,<list>,<text>)
# 把list中的单词逐一取出放到参数var所指定的变量中,然后执行text包含的表达式
# addprefix函数就是添加前缀 $(addprefix fixstring,string1 string2 ...)
# 其中fixstring表示要添加的前缀,逗号后则是要添加前缀的字符串
# 所以这里就是分别取出application test作为前缀application/ test/
# 最后编程 application/* application/*/* ...
# test也一样
# 以上信息保存到PROGS_TO_SEARCH

PROGS_TO_SEARCH := $(foreach rootdir, $(TOTAL_ROOTDIRS), $(addprefix $(rootdir)/, $(SEARCH_PATTERNS)))

# sort函数是排序函数 $(sort LIST)
# 给字串“LIST”中的单词以首字母为准进行排序(升序),并取掉重复
# dir函数 $(dir Names)
# 从文件名序列Name中取出目录部分,也就是最后一个/之前的部分
# 比如$(dir src/test.c) 这里返回的就是 src/
# 总的意思就是application/* application/*/* 找到这些路径下面的makefile
# 并进行一个升序排序,升序后返回其所在的目录的路径
PROGS_makefile := $(foreach progdir, $(PROGS_TO_SEARCH), $(sort $(dir $(wildcard $(progdir)/makefile))))

# 这里同上面一样,不过找的是Makefile文件
PROGS_Makefile := $(foreach progdir, $(PROGS_TO_SEARCH), $(sort $(dir $(wildcard $(progdir)/Makefile))))

# 将makefile和Makefile所在目录进行升序排序
PROGS_DIRS := $(sort $(PROGS_makefile) $(PROGS_Makefile))
# 将有makefile和Makefile的目录加上__CLEAN__的前缀
# 比如之前application/baremetal/demo_dsp/
# 加上前缀后变成 __CLEAN__application/baremetal/demo_dsp/
CLEAN_DIRS_RULES := $(addprefix __CLEAN__, $(PROGS_DIRS))

# 如果要编译的源码下面找不到Makefile
ifeq ($(VALID_PROGRAM_MAKEFILE), )
# 则指定一个默认的app
APP_PROGRAM=application/$(PROGRAM)
# 判断新的app是否存在
VALID_PROGRAM=$(wildcard $(APP_PROGRAM))
# 新的app存在的话是不是有Makefile
VALID_PROGRAM_MAKEFILE=$(wildcard $(APP_PROGRAM)/Makefile)
# 如果新的app还是没有Makefile,则打印下面的信息
ifeq ($(VALID_PROGRAM_MAKEFILE), )
$(error No valid Makefile in $(PROGRAM) directory! please check!)
endif
endif

# 如果make的时候输入的是cleanall
cleanall: $(CLEAN_DIRS_RULES)

# cleanall的动作
# $(patsubst <pattern>,<replacement>,<text>)
# 模式字符串替换函数——patsubst
# 找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)
# 是否符合模式<pattern>,如果匹配的话,则以<replacement>替换
# 以$(patsubst %.c,%.o,$(dir))为例,patsubst把$(dir)中的变量符合
# 后缀是.c的全部替换成.o
# 这里就是对每个有Makefile和makefile的目录执行 make -C xxxx clean
$(CLEAN_DIRS_RULES):
    make -C $(patsubst __CLEAN__%, %, $@) clean

# 如果不是cleanall其是有效的命令,则执行下面的操作
# 比如是all
# 则对要编译的源码执行 make -C xxxx all
$(VALID_SDK_RULES):
    make -C $(VALID_PROGRAM) $@

2. 源码选择application/baremetal/helloworld Makefile如下

# 要编译生成的目标名字是helloworld
TARGET = helloworld

# 指定sdk的根目录
NUCLEI_SDK_ROOT = ../../..

# SRCDIRS这里指定源码路径是 当前 . 和 src目录
SRCDIRS = . src 

# 同上
INCDIRS = . inc 

# 编译相关忽略
COMMON_FLAGS := -O2 

# 导入Makefile.base
include $(NUCLEI_SDK_ROOT)/Build/Makefile.base

3. 分析Makefile.base

# 指定sdk的Build路径
NUCLEI_SDK_BUILD = $(NUCLEI_SDK_ROOT)/Build
# Include your local and global makefile variables
# SOC, DOWNLOAD, PFLOAT, NEWLIB etc.
# Makefile.global should be placed in $(NUCLEI_SDK_ROOT)/Build
# Makefile.local should be placed together with application Makefile in your own application folder
# Sample content for this Makefile.local or Makefile.global
# SOC ?= demosoc
# DOWNLOAD ?= ilm

# 这里解释一下Makefile中的 = := ?= += 这些东西
#
# = 最普通的赋值,这个赋值容易搞错,注意这个值是最后被指定的值
# 举例:
#   VIR_A = 1
#   VIR_B = $(VIR_A) 2
#   VIR_A = 3
# 经过赋值操作后,VIR_B的值是3 2,而不是 1 2
# 这里就是最后指定的值的意思
#
# := 直接赋值,且赋予的是当前位置的值
# 举例:
#   VIR_A = 1
#   VIR_B = $(VIR_A) 2
#   VIR_A = 3
# 经过赋值操作后,VIR_B的值是 1 2
#
# ?= 表示如果该变量没有被赋值,则赋予等号后的值
# 举例:
#   VIR_A ?= 1
#   如果make的时候传入VIR_A=2
#   或者之前有定义 VIR_A := 2
# 那么VIR_A值为2,否则为1
#
# += 表示将等号后的值添加到前面的变量上
# 举例:
#   VIR_A := 1
#   VIR_A += 2
# 那么VIR_A的值为 1 2
#

# 这里会去helloworld下面找Makefile.local
# 以及Build下面找Makefile.global
# 如果有的话,找到后记录在EXTRA_MKS
EXTRA_MKS := $(wildcard Makefile.local $(NUCLEI_SDK_BUILD)/Makefile.global)

# strip去掉空格函数 $(strip STRINT) 
# 去掉字串(若干单词,使用若干空字符分割) “STRINT”开头和结尾的
# 空字符,并将其中多个连续空字符合并为一个空字符。 
# 举例:
#   STR =        a    b c      
#   LOSTR = $(strip $(STR)) 
# 结果是"a b c"
# 这里判断如果找到了Makefile.local和Makefile.global
# 那么将其包含进来
ifneq ("$(strip $(EXTRA_MKS))", "") 
$(info Obtaining addtional make variables from $(EXTRA_MKS))
include $(EXTRA_MKS)
endif

# 下面的注释比较清晰,这里就不再汉语分析
# Variables could be passed in make command
# NOTE: CORE and BOARD are defined in Makefile.soc.$(SOC)
# BOARD and SOC name should always be lower-case
## Available choices:
## The name of sub directories in $(NUCLEI_SDK_ROOT)/SoC/
SOC ?= demosoc
## Available choices:
## ilm: Program will be download into ilm/ram and run directly in ilm/ram, program lost when poweroff
## flash: Program will be download into flash, when running, program will be copied to ilm/ram and run in ilm/ram
## flashxip: Program will to be download into flash and run directly in Flash
DOWNLOAD ?= ilm 
## If SIMULATION=1, it means the program is optimized for hardware simulation environment
SIMULATION ?= 0
## If V=1, it will display compiling message in verbose including compiling options
V ?=
## If SILENT=1, it will not display any compiling messsage
SILENT ?=

# Variables should be defined in Application Makefile
## Available choices:
## The name of sub directories in $(NUCLEI_SDK_ROOT)/OS/
RTOS ?=
## If PFLOAT=1, it will enable float point print when using nano newlib
PFLOAT ?= 0
## If NEWLIB=nano, it will use nano newlib, otherwise it will use normal newlib
NEWLIB ?= nano
## If NOGC=1, it will not gc any sections during compiling to save code size
NOGC ?=

# 这里指定soc和rtos的路径
# Directories for SoC and RTOS chosen
NUCLEI_SDK_SOC = $(NUCLEI_SDK_ROOT)/SoC/$(SOC)
NUCLEI_SDK_RTOS = $(NUCLEI_SDK_ROOT)/OS/$(RTOS)

## Include GNU Make Standard Library
## Website: http://gmsl.sourceforge.net/
# GNU Make 标准库 (GMSL) 是使用本机 GNU Make功能实现的函数集合,
# 这些功能提供列表和字符串操作、整数运算、关联数组、堆栈和调试工具
# 这里用到再说
include $(NUCLEI_SDK_BUILD)/gmsl/gmsl

# 下面分别分析 Makefile.misc Makefile.conf Makefile.rules
include $(NUCLEI_SDK_BUILD)/Makefile.misc
include $(NUCLEI_SDK_BUILD)/Makefile.conf
include $(NUCLEI_SDK_BUILD)/Makefile.rules

3.1 Makefile.misc

# 注意这里用一些变量代码了一些func操作
## Small Functions ##
get_csrcs = $(foreach subdir, $(1), $(wildcard $(subdir)/*.c $(subdir)/*.C))
get_asmsrcs = $(foreach subdir, $(1), $(wildcard $(subdir)/*.s $(subdir)/*.S))
get_cxxsrcs = $(foreach subdir, $(1), $(wildcard $(subdir)/*.cpp $(subdir)/*.CPP))
check_item_exist = $(strip $(if $(filter 1, $(words $(1))),$(filter $(1), $(sort $(2))),))


# 对于windows 这里忽略
###
# For Windows, in Win9x, COMSPEC is defined, WinNT, ComSpec is defined
###
ifdef ComSpec
    WINCMD:=$(ComSpec)
endif
ifdef COMSPEC
    WINCMD:=$(COMSPEC)
endif

ifneq "$(WINCMD)" ""
ifneq "$(findstring /cygdrive/,$(PATH))" ""
    HOST_OS:=Cygwin
else
    HOST_OS:=Windows
endif
else
# 这里才是非windows的情况
# shell uname, ubuntu下返回linux
    HOST_OS:=$(shell uname)
endif

##
# Define one space
##
# nullstring值为一个空格
nullstring=
space=$(nullstring) # one space

# 定义一些变量
RM=rm -rf 
RMD=rm -rf 
ECHO=echo
CP=cp -rf 
MKD = mkdir -p
PS=/$(nullstring)
NULL=/dev/null

## Check OS ##
## Check OS == Windows ##
ifeq "$(HOST_OS)" "Windows"
    PS=\$(nullstring)
    NULL=NUL
    DOS_CMD=$(WINCMD) /C
    # when OS is windows, force SHELL to be cmd
    # or if in your evironment path there is
    # a mingw shell, the make process will go wrong
    SHELL:=$(WINCMD)
endif

## Check OS == Linux ##
ifeq "$(HOST_OS)" "Linux"
    PS=/$(nullstring)
    NULL=/dev/null
endif

## Check OS == Darwin ##
ifeq "$(HOST_OS)" "Darwin"
    PS=/$(nullstring)
    NULL=/dev/null
endif

# V是在Makefile.base中定义的
# @符合的作用
# 如果将‘@’添加到命令行前,这个命令将不被make回显出来
# 注意是命令不被回显
# 举例:
#   @echo  --compiling module----
# 屏幕输出 --compiling module----
# 没有@
# 屏幕输出 echo  --compiling module----
## MAKEFILE COMPILE MESSAGE CONTROL ##
ifeq ($(V),1)
    Q=
else
    Q=@
endif

# SILENT 沉默的意思
# 就是以后使用下面的命令打印还是不打印的效果
## Suppress All Message ##
ifeq ($(SILENT), 1)
    TRACE_CREATE_DIR    =
    TRACE_COMPILE       =
    TRACE_ASSEMBLE      =
    TRACE_LINK          =
    TRACE_ARCHIVE       =
    ## Overwrite Q Value set by V option ##
    override Q=@
else
    TRACE_CREATE_DIR    = @$(ECHO) "Creating Directory : " $(@D)
    TRACE_COMPILE       = @$(ECHO) "Compiling  : " $<
    TRACE_ASSEMBLE      = @$(ECHO) "Assembling : " $<
    TRACE_LINK          = @$(ECHO) "Linking    : " $@
    TRACE_ARCHIVE       = @$(ECHO) "Archiving  : " $@
endif

3.2 Makefile.conf(1)

## NUCLEI RISCV GCC COMPILER
## NUCLEI RISCV OPENOCD
#
#!< Nuclei SDK Tools Root

# 指定交叉编译器的前缀
COMPILE_PREFIX ?= riscv-nuclei-elf-
# 以下是官方期望的sdk_tool gcc openocd的路径
# 我们都没有...
NUCLEI_SDK_TOOL_ROOT ?= $(NUCLEI_SDK_ROOT)/prebuilt_tools
NUCLEI_RISCV_GCC_ROOT ?= $(NUCLEI_SDK_TOOL_ROOT)/gcc
NUCLEI_OPENOCD_ROOT ?= $(NUCLEI_SDK_TOOL_ROOT)/openocd

# 如果gcc openocd 目录都存在,则NUCLEI_SDK_TOOL_ROOT_EXIST值为1
# 否则为0
NUCLEI_SDK_TOOL_ROOT_EXIST = 0
ifneq ($(wildcard $(NUCLEI_RISCV_GCC_ROOT)),)
ifneq ($(wildcard $(NUCLEI_OPENOCD_ROOT)),)
NUCLEI_SDK_TOOL_ROOT_EXIST = 1
endif
endif

# gcc openocd 目录都存在的情况
# 找到下面这些命令的绝对路径
ifeq ($(NUCLEI_SDK_TOOL_ROOT_EXIST),1)
CC      := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)gcc)
CXX     := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)g++)
OBJDUMP := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)objdump)
OBJCOPY := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)objcopy)
GDB     := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)gdb)
AR      := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)ar)
SIZE    := $(abspath $(NUCLEI_RISCV_GCC_ROOT)/bin/$(COMPILE_PREFIX)size)
OPENOCD := $(abspath $(NUCLEI_OPENOCD_ROOT)/bin/openocd)
else
# 由于我们不配合官方,所以走这里,都加上了前缀
CC      := $(COMPILE_PREFIX)gcc
CXX     := $(COMPILE_PREFIX)g++
OBJDUMP := $(COMPILE_PREFIX)objdump
OBJCOPY := $(COMPILE_PREFIX)objcopy
GDB     := $(COMPILE_PREFIX)gdb
AR      := $(COMPILE_PREFIX)ar
SIZE    := $(COMPILE_PREFIX)size
OPENOCD := openocd
endif

# 导入 Makefile.soc
include $(NUCLEI_SDK_BUILD)/Makefile.soc

3.2.1 Makefile.soc

# 我们传入的soc是gd32vf103

ifeq ($(SOC),hbird)
$(warning SOC hbird is renamed to demosoc since Nuclei SDK 0.3.1, please use SOC=demosoc now)
override SOC := demosoc
endif

# 这里会导入 Makefile.soc.gd32vf103

include $(NUCLEI_SDK_BUILD)/Makefile.soc.$(SOC) 
3.2.1.1 Makfile.soc.gd32vf103
# BOARD是gd32vf103c_longan_nano
BOARD ?= gd32vf103v_rvstar
# variant 板子的变体 比如v1 v2等等
# Variant for Board or SoC
VARIANT ?=

# 这里指定CORE 和 DOWNLOAD
# override DOWNLOAD and CORE variable for GD32VF103 SoC
# even though it was set with a command argument
override CORE := n205
override DOWNLOAD := flashxip

# 记录板子路径和通用代码路径
GD32VF103_SDK_SOC_BOARD=$(NUCLEI_SDK_SOC)/Board/$(BOARD)
GD32VF103_SDK_SOC_COMMON=$(NUCLEI_SDK_SOC)/Common

# gd32vf103上没有ilm
# 而且板子gd32vf103c_longan_nano上有2种gd32vf103
# 分别是gd32vf103x8和gd32vf103xb
# 其中
#   gd32vf103x8 是64k flash + 20k ram
#   gd32vf103xb 是128k flash + 32k ram
# 手里的板子是gd32vf103xb

#no ilm on gd32vf103 SoC
ifeq ($(BOARD), gd32vf103c_longan_nano)
ifeq ($(VARIANT), lite)
LINKER_SCRIPT ?= $(GD32VF103_SDK_SOC_BOARD)/Source/GCC/gcc_gd32vf103x8_flashxip.ld
else
# 对应的链接脚本是 gcc_gd32vf103xb_flashxip.ld
LINKER_SCRIPT ?= $(GD32VF103_SDK_SOC_BOARD)/Source/GCC/gcc_gd32vf103xb_flashxip.ld
endif
else
LINKER_SCRIPT ?= $(GD32VF103_SDK_SOC_BOARD)/Source/GCC/gcc_gd32vf103_flashxip.ld
endif

# OPENCD 这里不关心
OPENOCD_CFG ?= $(GD32VF103_SDK_SOC_BOARD)/openocd_gd32vf103.cfg

# 将core值n205转换成大写U205放到CORE_UPPER中
CORE_UPPER = $(call uc, $(CORE))

RISCV_ARCH ?= rv32imac
RISCV_ABI ?= ilp32

# Extra openocd and gdb commands
GDB_UPLOAD_CMDS += -ex "monitor halt"

3.3 Makefile.conf(2)

# 删除了gdb相关的东西
...

# 列出了所有支持的下载模式
## ilm: 程序会下载到ilm/ram中直接在ilm/ram中运行,掉电程序丢失
## flash: 程序会被下载到flash中,运行时,程序会被复制到ilm/ram并在ilm/ram中运行
## flashxip: 程序将被下载到闪存中并直接在闪存中运行 
SUPPORT_DOWNLOAD_MODES=flash flashxip ilm ddr

# 之前有个gsml的东西,uc就是来自那里
# 这里的意思就是将DOWNLOAD的变量换成全部大写
# DOWNLOAD变量来自Makefile.soc 值为flashxip
# 同样这里是变成大写 FLASHXIP
DOWNLOAD_UPPER = $(call uc, $(DOWNLOAD))
# 将所有支持的模式变成大写
SUPPORT_DOWNLOAD_MODES_UPPER=$(call uc, $(SUPPORT_DOWNLOAD_MODES))

# check_item_exist是在 Makefile.misc中定义 
# $(strip $(if $(filter 1, $(words $(1))),$(filter $(1), $(sort $(2))),))
# filter 过滤函数 $(filter, )
# 以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式
# words 测试了一下 $(words xxx) 返回的是xxx中字符串的个数
# 返回符合模式的字串
# $(words  $(DOWNLOAD_UPPER)) 返回值是1
# $(filter 1, $(words $(DOWNLOAD_UPPER))) 这里就相当于从1中找1,返回1
# if函数 $(if <condition>,<then-part>,<else-part> )
# $(if 1, $(filter $(1), $(sort $(2))),)
# if条件满足了,才会执行逗号后面的语句
# 从升序后的$(SUPPORT_DOWNLOAD_MODES_UPPER)中过滤$(DOWNLOAD_UPPER)
# 其返回值就是FLASHXIP
# 最后 $(strip FLASHXIP)
# strip去掉空格函数,之前分析过
# 所以这里最后返回的就是FLASHXIP
VALID_DOWNLOAD = $(call check_item_exist, $(DOWNLOAD_UPPER), $(SUPPORT_DOWNLOAD_MODES_UPPER))

# 导入Makefile.files
include $(NUCLEI_SDK_BUILD)/Makefile.files

# 导入Makefile.rtos
include $(NUCLEI_SDK_BUILD)/Makefile.rtos

3.3.1 Makefile.files

#添加NMSIS相关头文件路径
INCDIRS += $(NUCLEI_SDK_ROOT)/NMSIS/Core/Include
C_INCDIRS +=
CXX_INCDIRS +=
ASM_INCDIRS +=

SRCDIRS +=
C_SRCDIRS +=
CXX_SRCDIRS +=
ASM_SRCDIRS +=

C_SRCS +=
CXX_SRCS +=
ASM_SRCS +=

LIBDIRS +=
# 导入Makefile.files.gd3vf103
include $(NUCLEI_SDK_BUILD)/Makefile.files.$(SOC)
3.3.1.1 Makefile.files.gd32vf103
# 添加common的头文件路径
INCDIRS += $(GD32VF103_SDK_SOC_COMMON)/Include

# 添加common源文件
C_SRCDIRS += $(GD32VF103_SDK_SOC_COMMON)/Source $(GD32VF103_SDK_SOC_COMMON)/Source/Drivers \
        $(GD32VF103_SDK_SOC_COMMON)/Source/Stubs

# 这里是usb相关的支持 不分析
ifeq ($(USB_DRV_SUPPORT), 1)
INCDIRS += $(GD32VF103_SDK_SOC_COMMON)/Include/Usb
C_SRCDIRS += $(GD32VF103_SDK_SOC_COMMON)/Source/Drivers/Usb
endif

# 添加汇编文件
ASM_SRCS += $(GD32VF103_SDK_SOC_COMMON)/Source/GCC/startup_gd32vf103.S \
        $(GD32VF103_SDK_SOC_COMMON)/Source/GCC/intexc_gd32vf103.S

# 判断是不是有效的板子
# Add extra board related source files and header files
VALID_GD32VF103_SDK_SOC_BOARD=$(wildcard $(GD32VF103_SDK_SOC_BOARD))

# 对应有效的板子
# 添加板子的头文件和源码
ifneq ($(VALID_GD32VF103_SDK_SOC_BOARD),)
INCDIRS += $(VALID_GD32VF103_SDK_SOC_BOARD)/Include
C_SRCDIRS += $(VALID_GD32VF103_SDK_SOC_BOARD)/Source
endif

3.3.2 Makefile.rtos

# 如果编译rtos比如 application/rtthread/demo
# 其Makefile 里面会设置RTOS的值
# 这里不深入分析
ifneq ($(RTOS),)
ifneq ($(wildcard $(NUCLEI_SDK_RTOS)),)
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.rtos
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.rtos.$(RTOS)
include $(NUCLEI_SDK_BUILD)/Makefile.rtos.$(RTOS)
# Define RTOS_$(RTOS) to show usage of RTOS, such as RTOS_FREERTOS
RTOS_UPPER = $(call uc, $(RTOS))
COMMON_FLAGS += -DRTOS_$(RTOS_UPPER)
endif
endif

3.4 Makefile.conf(3)

# 判断下载模式是否有效
ifeq ($(VALID_DOWNLOAD),)
$(error Download mode $(DOWNLOAD) is not supported, support modes: $(SUPPORT_DOWNLOAD_MODES))
endif

DEFAULT_RISCV_ARCH ?= rv32imac
DEFAULT_RISCV_ABI ?= ilp32

# RISC_ARCH RISC_ABI的 值是在 Makefile.soc.gd32vf103设置的

ifeq ($(RISCV_ARCH),)
$(warning RISCV_ARCH is not defined, use $(DEFAULT_RISCV_ARCH) as default)
RISCV_ARCH := $(DEFAULT_RISCV_ARCH)
endif
ifeq ($(RISCV_ABI),)
$(warning RISCV_ABI is not defined, use $(DEFAULT_RISCV_ABI) as default)
RISCV_ABI := $(DEFAULT_RISCV_ABI)
endif

# 这里和gcc编译器关联较大 最好百度
MKDEP_OPT = -MMD -MT $@ -MF $@.d

# 将所有的头文件加上 -I的前缀
C_INCLUDE_OPT = $(foreach dir,$(sort $(INCDIRS) $(C_INCDIRS)),-I$(dir))
# 同上
CXX_INCLUDE_OPT = $(foreach dir,$(sort $(INCDIRS) $(CXX_INCDIRS)),-I$(dir))
# 同上
ASM_INCLUDE_OPT = $(foreach dir,$(sort $(INCDIRS) $(ASM_INCDIRS)),-I$(dir))

# 删除gcc编译器配置相关的
...

# 同样还是编译相关的
COMMON_FLAGS += -g -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=medany \
        $(GC_CFLAGS) -fno-common -DDOWNLOAD_MODE=DOWNLOAD_MODE_$(DOWNLOAD_UPPER)

CFLAGS += $(COMMON_FLAGS) $(C_INCLUDE_OPT) $(MKDEP_OPT)
CXXFLAGS += $(COMMON_FLAGS) $(CXX_INCLUDE_OPT) $(MKDEP_OPT)
ASMFLAGS += $(COMMON_FLAGS) $(ASM_INCLUDE_OPT) $(MKDEP_OPT)

# 加上-L的前缀
LIB_OPT = $(addprefix -L, $(sort $(LIBDIRS)))

LDFLAGS += -T $(LINKER_SCRIPT) -lstdc++ -nostartfiles -Wl,-M,-Map=$(TARGET).map \
        $(GC_LDFLAGS) $(NEWLIB_LDFLAGS) --specs=nosys.specs \
        $(LIB_OPT) $(LDLIBS)

# More options needed by -flto, if not passed, will fail in linking phase
LDFLAGS += -u _isatty -u _write -u _sbrk -u _read -u _close -u _fstat -u _lseek


# 将Makefile及链接文件汇总到 COMMON_PREREQS
# Prerequesties
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.base
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.soc
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.soc.$(SOC)
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.conf
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.core
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.files
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.files.$(SOC)
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.misc
MAKEFILE_PREREQS += $(NUCLEI_SDK_BUILD)/Makefile.rules
MAKEFILE_PREREQS += $(EXTRA_MKS)
MAKEFILE_PREREQS += Makefile

LINK_PREREQS += $(LINKER_SCRIPT)

COMMON_PREREQS = $(MAKEFILE_PREREQS) $(LINK_PREREQS)

3.5 Makefile.rules

TARGET_ELF = $(TARGET).elf

# 将所有的c文件 c++文件 汇编文件 分别进行升序排列
# 注意call的使用方法是$(call variable,param1,param2,...)
# 执行的时候parame1 parame2 分别赋值给临时变量 $(1) $(2)
# 以下面这个为例 $(1) 为$(SRCDIRS) 和 $(C_SRCDIRS)
ALL_CSRCS = $(sort $(C_SRCS) $(call get_csrcs, $(SRCDIRS) $(C_SRCDIRS)))
ALL_CXXSRCS = $(sort $(CXX_SRCS) $(call get_cxxsrcs, $(SRCDIRS) $(CXX_SRCDIRS)))
ALL_ASMSRCS = $(sort $(ASM_SRCS) $(call get_asmsrcs, $(SRCDIRS) $(ASM_SRCDIRS)))

ALL_ASM_OBJS := $(ALL_ASMSRCS:=.o)
ALL_C_OBJS := $(ALL_CSRCS:=.o)
ALL_CXX_OBJS := $(ALL_CXXSRCS:=.o)

ALL_OBJS += $(ALL_ASM_OBJS) $(ALL_C_OBJS) $(ALL_CXX_OBJS)

ALL_DEPS := $(ALL_OBJS:=.d)

CLEAN_OBJS += $(TARGET).elf $(TARGET).map $(TARGET).bin $(TARGET).dump $(TARGET).dasm \
        $(TARGET).hex $(TARGET).verilog openocd.log $(ALL_OBJS) $(ALL_DEPS)
REAL_CLEAN_OBJS = $(subst /,$(PS), $(CLEAN_OBJS))

# 执行all的时候,默认编译elf文件
# Default goal, placed before dependency includes
all: info $(TARGET).elf

# include dependency files of application
ifneq ($(MAKECMDGOALS),clean)
-include $(ALL_DEPS)
endif

# 生成elf文件是一系列的命令 
$(TARGET).elf: $(ALL_OBJS)
    $(TRACE_LINK)
    $(Q)$(CC) $(CFLAGS) $(ALL_OBJS) -o $@ $(LDFLAGS)
    $(Q)$(SIZE) $@

# 对于下面几个有使用$(COMMON_PREREQS) 不理解
# 尝试删除 好像也可以,没有影响
$(ALL_ASM_OBJS): %.o: % $(COMMON_PREREQS)
    $(TRACE_ASSEMBLE)
    $(Q)$(CC) $(ASMFLAGS) -c -o $@ $<

$(ALL_C_OBJS): %.o: % $(COMMON_PREREQS)
    $(TRACE_COMPILE)
    $(Q)$(CC) $(CFLAGS) -c -o $@ $<

$(ALL_CXX_OBJS): %.o: % $(COMMON_PREREQS)
    $(TRACE_COMPILE)
    $(Q)$(CXX) $(CXXFLAGS) -c -o $@ $<

dasm: $(TARGET).elf
    $(OBJDUMP) -S -d $< > $(TARGET).dump
    $(OBJDUMP) -d $< > $(TARGET).dasm
    $(OBJCOPY) $< -O ihex $(TARGET).hex
    $(OBJCOPY) $< -O verilog $(TARGET).verilog

# 生成bin文件的在这里
bin: $(TARGET).elf
    $(OBJCOPY) $< -O binary $(TARGET).bin

size: $(TARGET).elf
    $(Q)$(SIZE) $<

upload: $(TARGET).elf
    @$(ECHO) "Download and run $<" 
   $(GDB) $< -ex "set remotetimeout 240" \
    -ex "target remote $(GDBREMOTE)" \
    $(GDB_UPLOAD_ARGS) $(GDB_UPLOAD_CMDS)

run_openocd:
    @$(ECHO) "Start openocd server"
    $(OPENOCD) $(OPENOCD_PORT_ARGS) $(OPENOCD_ARGS)

run_gdb: $(TARGET).elf
    @$(ECHO) "Run gdb to connect openocd server and debug"
    $(GDB) $< $(GDB_ARGS) $(GDB_CMDS)

debug: $(TARGET).elf
    @$(ECHO) "Download and debug $<"
    $(GDB) $< -ex "set remotetimeout 240" \
    -ex "target remote $(GDBREMOTE)"

clean:
    @$(ECHO) "Clean all build objects"
    $(Q)$(RM) $(REAL_CLEAN_OBJS)
 类似资料: