makefile脚本需要修改的地方

NOTE:
此篇文章由VSCode+arm-none-eabi-gcc交叉编译+Makefile构建+OpenOCD(基于STM32标准库的保姆级教程)派生而来,对makefile脚本需要修改的地方作补充说明。
一些修改说明:

TARGET = F401CCU6_demo

修改生成的xxx.elf、xxx.hex、xxx.bin、xxx.map文件名称。例如上述的F401CCU6_demo,会在build文件夹中生成

在这里插入图片描述

DEBUG = 1
# optimization
# /*
# 编译选项:优化等级
# -O0:无任何优化,
# -O1:1级优化,
# -O2: 2级优化,
# -Os: 2.5级优化,
# -O3: 最高级优化。
# -Og:优化调试体验。 -Og启用不会干扰调试的优化。 它是标准编辑 - 编译 - 调试周期可以选择的优化级别,提供合理的优化级别,同时保持快速编译和良好的调试体验。
# */
OPT = -Og

代码优化等级更改。

嵌入式领域中,在正式发行代码版本时,会严格区分Release和Debug版本:Debug版本一般用于开发人员内部开发调试;Release版本一般发布给外部的市场客户,此时的Release版本代码往往就会设置代码优化等级,目的是为了将MCU的RAM和Flash资源利用最大化以及优化客户体验(Tips:代码优化过后,可能会出现一些玄学一样的bug!!!

CPU = -mcpu=cortex-m4

FPU = -mfpu=fpv4-sp-d16

FLOAT-ABI = -mfloat-abi=hard

MCU = $(CPU) $(FPU) $(FLOAT-ABI) -mthumb -mthumb-interwork

编译选项参数设置,需要根据不同MCU型号修改

C_DEFS =  \
-DUSE_STDPERIPH_DRIVER \
-DSTM32F401xx

宏定义展开设置,需要根据不同MCU型号修改

C_SOURCES =  \
$(wildcard ./CMSIS/Source/*.c) \
$(wildcard ./Core/Src/*.c) \
$(wildcard ./STM32F4xx_StdPeriph_Driver/src/*.c) \
$(wildcard ./User/Src/*.c)

使用通配符 wildcard 匹配文件夹下的所有源文件。修改为你工程目录中需要参与编译的源文件路径。

ASM_SOURCES = $(wildcard ./startup_s/*.s)

使用通配符 wildcard 匹配文件夹下的MCU汇编启动文件。修改为你工程目录中需要参与编译的启动文件路径。

C_INCLUDES =  \
-ICore/Inc \
-ICMSIS/Include \
-ISTM32F4xx_StdPeriph_Driver/inc \
-IUser/Inc

匹配文件夹下的所有头文件。修改为你工程目录中需要参与编译的头文件路径。

LDSCRIPT = ./link_script/STM32F401CCUx_FLASH.ld

匹配文件夹下的MCU链接脚本。修改为你工程目录中参与链接的链接脚本路径。

Makefile脚本内容:

##########################################################################################################################
# File automatically-generated by tool: [projectgenerator] version: [4.2.0-B44] date: [Fri Jul 05 19:24:39 CST 2024]
##########################################################################################################################

# ------------------------------------------------
# Generic Makefile (based on gcc)
#
# ChangeLog :
#	2017-02-10 - Several enhancements + project update mode
#   2015-07-22 - first version
# ------------------------------------------------

# SHELL = cmd

######################################
# target-------编译生成目标烧写软件的名称
######################################
TARGET = F401CCU6_demo

######################################
# building variables
######################################
# debug build
# /*
# 编译选项:是否debug模式,如果DEBUG=1,则可以后续使用调试软件gdb等工具进行在线调试
# 如果DEBUG=0,则不能支持在线调试,
# 且DEBUG=1,生成的文件比DEBUG=0大,因为里面包含了调试信息。
# */
DEBUG = 1

# optimization
# /*
# 编译选项:优化等级
# -O0:无任何优化,
# -O1:1级优化,
# -O2: 2级优化,
# -Os: 2.5级优化,
# -O3: 最高级优化。
# -Og:优化调试体验。 -Og启用不会干扰调试的优化。 它是标准编辑 - 编译 - 调试周期可以选择的优化级别,提供合理的优化级别,同时保持快速编译和良好的调试体验。
# */
OPT = -Og

#######################################
# paths
#######################################
# Build path
# /*
# 编译路径: 生成的编译文件保存在build文件夹中,
# 这样做的好处是工程框架比较清晰,且清除编译文件比较简单。
# */
BUILD_DIR = build

######################################
# source-------工程所有需要编译的C文件: 指定需要编译的C文件名称相对路径
######################################
# C sources
C_SOURCES =  \
$(wildcard ./CMSIS/Source/*.c) \
$(wildcard ./Core/Src/*.c) \
$(wildcard ./STM32F4xx_StdPeriph_Driver/src/*.c) \
$(wildcard ./User/Src/*.c)

# ASM sources
# 工程所有需要编译的汇编文件: 指定需要编译的汇编文件名称相对路径
# ASM_SOURCES =  
# ASM_SOURCES += $(wildcard ./startup_s/*.s)
ASM_SOURCES = $(wildcard ./startup_s/*.s)

# ASM sources
ASMM_SOURCES =

#######################################
# binaries
#######################################
# /*
# 工程使用编译的类型: arm-none-eabi-是基于arm芯片开发的编译器,
# none表示无操作系统,eabi表示交叉编译器,即在linux上编译嵌入式arm芯片的代码
# 生成可烧写文件。
# */
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
# /*
# 编译器路径宏:表示arm-none-eabi-gcc在linux中调用是否需要带路径,
# 一般情况安装好arm-none-eabi-gcc后,系统将安装的可执行程序路径放在了系统的环境变量中,
# 无需要路径即可执行,所以GCC_PATH不用宏定义。
# */
ifdef GCC_PATH#如果定义了GCC_PATH的本地路径,则进行本地索引编译
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else#否则索引环境变量的路径编译
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

#######################################
# CFLAGS
#######################################
# cpu
# 编译选型:CPU类型,STM32芯片的内核是cortex-m4,指定该内核对应的寄存器库
CPU = -mcpu=cortex-m4

# fpu
# 编译选型:FPU浮点计算器,STM32F4xx支持浮点运算来做DSP
FPU = -mfpu=fpv4-sp-d16

# float-abi
# 编译选型:浮点计算类型,设定硬件浮点运算,还可选型纯软件浮点计算,或者结合形式
FLOAT-ABI = -mfloat-abi=hard

# mcu
# 编译MCU总选项:M4内核,支持浮点运算,浮点计算采用硬件浮点计算器,指定生成thumb精简指令集,【默认不开启:允许编译器进行ARM指令和Thumb指令的相互调用】
# MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
MCU = $(CPU) $(FPU) $(FLOAT-ABI) -mthumb -mthumb-interwork

# macros for gcc
# AS defines
# 汇编编译宏定义:该Makefile宏定义将在汇编代码中有效
AS_DEFS =

# C defines
# C文件编译宏定义:该Makefile宏定义将在C代码中有效
C_DEFS =  \
-DUSE_STDPERIPH_DRIVER \
-DSTM32F401xx

# AS includes----------汇编头文件路径:编译过程中文件内的头文件搜索路径
AS_INCLUDES =

# C includes--------C文件的头文件路径:编译过程中文件内的头文件搜索路径
C_INCLUDES =  \
-ICore/Inc \
-ICMSIS/Include \
-ISTM32F4xx_StdPeriph_Driver/inc \
-IUser/Inc
# compile gcc flags

# 汇编编译选型:s汇编文件编译成Obj文件需要的设置选项
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

# C编译选型:C文件编译成Obj文件需要的设置选项
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

# Debug模式下的C编译选型:仅仅在开启DEBUG模式下有效
# -g -gdwarf-2是调试选项,其中-g表示在生成的文件中添加调试信息,-gdwarf-2表示调试信息的格式为DWARF,版本号为2。调试信息将在对应的GDB(比如arm-none-eabi-gdb)中使用。
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif

# Generate dependency information
# /*
# C文件自动依赖关系 :-MMD -MP -MF"$(@:%.o=%.d)"
# 自动生成.d文件,里面保存了对应的源文件C代码中包含的非标准库的头文件路径和名称,
# 生成.d文件的目的是产生C文件生成obj的依赖文件,
# 当关联的头文件发生变化时,触发make重新生成obj文件。
# -MMD等同于-MM -MF,-MM表示依赖的头文件(不包括标准头文件夹,-M则是所有头文件),
# -MF生成依赖文件。
# */
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

#######################################
# LDFLAGS
#######################################
# link script
# /*
# 可执行文件链接脚本:  STM32F401CCUx_FLASH.ld
# 文件中详细给出了芯片的RAM和ROM片区分类区间与大小,
# 代码、全局变量、常数、堆栈等的分配区间。
# */
# LDSCRIPT = STM32F103VETx_FLASH.ld
LDSCRIPT = ./link_script/STM32F401CCUx_FLASH.ld

# libraries
# 编译选型: 依赖的标准库
# -lc:链接libc库(ANSI C标准);-lm:链接libm库(数学函数库)
LIBS = -lc -lm -lnosys
# 编译选型: 依赖的指定路径库,.a库文件(window中的lib文件需要转换成.a文件才能识别)
LIBDIR =
# 链接工具的总选项: 
# MCU 芯片类型,
# -u_printf_float显式启用浮点数打印。-u_scanf_float显式启用浮点数输入
# specs:Specifying Subprocesses缩写,子进程。
# -specs=nano.specs链接精简版C库,nan0.specs将-lc替换成-lc_nano,用精简C库newlib-nano替代标准C库glibc/newlib,减少.elf体量。
# -T$(LDSCRIPT)依赖的可执行文件链接脚本,
# $(LIBDIR) 标准库文件 , $(LIBS) 指定库文件 ,
# -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref 生成map文件 ,
# -Wl,--gc-sections 链接使用的分段方式,需要配合C文件/汇编生成obj的时候同样选型分段方式,好处是链接的时候源文件中的未使用变量和未调用# 函数将不会被链接到elf文件中,最终可执行文件elf会很精简。
# --no-warn-rwx-segments:消除 LOAD segment with RWX permissions 警告
LDFLAGS = $(MCU) -flto -u_printf_float -u_scanf_float -specs=nano.specs -specs=nosys.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections,--print-memory-usage,--no-warn-rwx-segments

# default action: build all
# Makefile总目标: 这是伪目标,在第一依赖关系位置,输入make指令时必定执行该目标
# 可执行文件elf , hex 和 bin 是arm的常用烧写文件

all: version $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

# 在正式编译前输出 gcc 版本信息。
version:
	$(CC) --version
# build/LED_Toggle.elf
# build/LED_Toggle.hex
# build/LED_Toggle.bin

#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
# /*
# 指定C文件的搜索路径: $(sort $(dir $(C_SOURCES)))
# $(dir $(C_SOURCES)):所有源文件只保留文件路径,
# sort:对所有路径排序 ,‘d g a’ -> 'a d g'
# */
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMM_SOURCES:.S=.o)))
vpath %.S $(sort $(dir $(ASMM_SOURCES)))

OBJ_DIR = obj
# /*
# 通配符(%)指定所有c文件编译成OBJ文件:
# $(BUILD_DIR)/%.o: 生成OBJ文件的路径固定不变,在BUILD_DIR文件夹,
# %.c:依赖源文件C文件,地址未指定,Makefile将在本地目录和vpath %c目录下搜索源文件,
# Makefile :Makefile文件自己也是生成obj文件的依赖文件,Makefile文件变化时会重新编译,
# | $(BUILD_DIR): 竖线左边的依赖文件是正常依赖文件,竖线右边的依赖文件是命令提前的依赖文件,即BUILD_DIR会自动执行,编译生成OBJ前生成build文件夹。
# -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)):生成临时中间文件
# -c:仅编译不链接 $<:第一个依赖文件即C文件   $@ 目标文件
# */
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) 
	@$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
	@echo $(notdir $(<:.c=.o))
# /*
# 通配符(%)指定所有汇编文件编译成OBJ文件:
# $(BUILD_DIR)/%.o: 生成OBJ文件的路径固定不变,在BUILD_DIR文件夹,
# %.c:依赖源文件C文件,地址未指定,Makefile将在本地目录和vpath %c目录下搜索源文件,
# Makefile :Makefile文件自己也是生成obj文件的依赖文件,Makefile文件变化时会重新编译,
# | $(BUILD_DIR): 竖线坐标的依赖文件是正常依赖文件,竖线右边的依赖文件是命令提前的依赖文件,
# -c:仅编译不链接 $<:第一个依赖文件即C文件   $@ 目标文件
# */
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
	@$(AS) -c $(CFLAGS) $< -o $@
	@echo $(notdir $(<:.s=.o))
$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
	@$(AS) -c $(CFLAGS) $< -o $@
	@echo $(notdir $(<:.S=.o))
# 生成可执行文件ELF文件:依赖于所有OBJECTS文件
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	@$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	@echo linking...
	$(SZ) $@
	rm -fR $(BUILD_DIR)/$(OBJ_DIR)
	mkdir $(BUILD_DIR)/$(OBJ_DIR)
# 生成HEX文件:依赖于elf文件和build文件夹
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(HEX) $< $@
# 生成BIN文件:依赖于elf文件和build文件夹	
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(BIN) $< $@	
	mv -f $(BUILD_DIR)/*.o $(BUILD_DIR)/$(OBJ_DIR)/
	mv -f $(BUILD_DIR)/*.d $(BUILD_DIR)/$(OBJ_DIR)/
	mv -f $(BUILD_DIR)/*.lst $(BUILD_DIR)/$(OBJ_DIR)/
# 生成build文件夹:伪指令。通过上面的优先依赖关系生成
$(BUILD_DIR):
	mkdir $@

#######################################
# clean up
#######################################
# /* 清除编译结果:将build文件中所有文件和子文件夹删除。*/
clean:
# Linux下的makefile语法(请使用xpack-windows-build-tools二进制发行工具包中的make.exe(GNU Make))
	rm -fR ./$(BUILD_DIR)/*

# Window CMD终端的语法(请反注释本makefile脚本顶部的  SHELL=cmd  ,虽然这样同样可以清除build目录,但是会导致构建工程失败,暂未找到原因)
#	rmdir /q /s $(BUILD_DIR)

#######################################
# dependencies
#######################################
# 添加所有.d依赖文件
-include $(wildcard $(BUILD_DIR)/*.d)

# *** EOF ***

参考链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值