目录
- 0. TDA4VM 8.4 RTOS SDK 中 SBL 的编译流程解析
- TI SDK 的可执行文件后缀名是 .xer5f 的原因
- sbl_ospi_img 的 .xer5f 可执行文件的生成过程
-
- .xer5f 文件生成 .tiimage 文件
- 1. makefile 中,如果一个变量存在多个值,如何让变量的值换行输出
- 2.如果想让上一个的命令作用到下一个命令中,那么两个命令需要写在同一行
- 3. make -C 选项可以重新指定当前工作目录
- 4.makefile 中命令包的定义
- 5. makefile 中 call 函数与 eval 函数以及命令包
0. TDA4VM 8.4 RTOS SDK 中 SBL 的编译流程解析
当我们在PDK_INSTALL_DIR/packages/ti/build
目录下执行下述命令,可以编译 ospi sbl:
make -j BOARD=j721e_evm CORE=mcu1_0 BUILD_PROFILE=release sbl_ospi_img
接下来我会以上述编译命令来详细讲述 SBL 编译过程,其他目标同样适用。
根据分析当前目录下的 makefile 文件,发现 sbl_ospi_img 依赖下面的规则编译:
除了生成 .xer5f 文件与生成 .tiimage 文件这步外,其余命令都未执行,上述图片中的命令可简化如下:
$(FINAL_PKG_LIST_ALL) $(FINAL_DUP_EXAMPLE_LIST):
$(MAKE) -C $($@_PATH) $($@_MAKEFILE)
$(MAKE) -C $($@_PATH) $($@_MAKEFILE) sbl_imagegen
其中,$($@_MAKEFILE)
变量在 sbl_component.mk
文件中赋值,展开为-f$(PDK_SBL_COMP_PATH)/build/sbl_img.mk BOOTMODE=ospi SBL_USE_DMA=yes BUILD_HS=no
, 如下图所示:
所以,.xer5f 可执行文件的生成,是通过 sbl_img.mk
文件生成的。
TI SDK 的可执行文件后缀名是 .xer5f 的原因
在 $(MAKERULEDIR)/platform.mk
文件中,定义了生成的目标文件,静态库文件,可执行文件,反汇编文件的通用后缀名,如下:
sbl_ospi_img 的 .xer5f 可执行文件的生成过程
根据上述知识,我们需要执行 sbl_img.mk
来生成 .xer5f 文件。
分析 sbl_img.mk
, 发现 sbl_img.mk
包含了 $(MAKERULEDIR)/common.mk
来包含编译规则,如下:
而在 $(MAKERULEDIR)/common.mk
文件中,第一条规则(默认规则)如下:
(.xerf 文件就是通过默认规则实现的,别急,往下看)
我们发现默认规则 all
的依赖是 $(CORE)
。
那么继续,我们查找目标为 $(CORE)
的规则,同样在 $(MAKERULEDIR)/common.mk
存在如下规则:
(叮咚叮咚~,恭喜你,发现编译生成 .xer5f 文件的最终规则)
对规则的说明如下:
$(CORE) : $(OBJDIR) $(BINDIR) $(DEPDIR) $(CONFIGURO_DIR)
ifneq ($(words $(PKG_LIST)), 0)
$(MAKE) $($(APP_NAME)_MAKEFILE) $(PKG_LIST)
endif
$(MAKE) $($(APP_NAME)_MAKEFILE) $(EXE_NAME)
编译依赖的静态库
编译依赖的静态库命令:
$(MAKE) $($(APP_NAME)_MAKEFILE) $(PKG_LIST)
(虽然 makefile 是这么写了,但是,经过实际测试,就算我改了库的源代码,好像不会重新编译库)
sbl_img.mk
中,会对 APP_NAME
变量赋值,如下:
所以 $($(APP_NAME)_MAKEFILE)
变量展开依旧是 -f$(PDK_SBL_COMP_PATH)/build/sbl_img.mk BOOTMODE=ospi SBL_USE_DMA=yes BUILD_HS=no
。
即再次执行 sbl_img.mk
,不过这一次会指定目标为$(PKG_LIST)
。
在 $(MAKERULEDIR)/common.mk
中, $(PKG_LIST) 编译规则如下:
变量 $@_MAKEFILE
即为具体模块对应的 makefile 文件,比如 board
模块对应的 makefile 文件如下:
即规则可以写作如下(已 board 模块为例):
board :
$(MAKE) -C $(PDK_BOARD_COMP_PATH) -f build/makefile.mk
通过编译上述规则,可以编译 board 模块。
但是经过实际测试,我改了 board 模块源代码,好像并没有重新编译 board 模块???
编译可执行文件命令
编译可执行文件命令:
$(MAKE) $($(APP_NAME)_MAKEFILE) $(EXE_NAME)
sbl_img.mk
中,对 APP_NAME
变量赋值 sbl_ospi_image
, 所以 $($(APP_NAME)_MAKEFILE)
变量展开依旧是 -f$(PDK_SBL_COMP_PATH)/build/sbl_img.mk BOOTMODE=ospi SBL_USE_DMA=yes BUILD_HS=no
。
而对于 $(EXE_NAME)
的值,该变量在 rules_ti_cgt_arm.mk
中赋值:
该文件会以如下方式被 $(MAKERULEDIR)/common.mk
文件包含:
所以,在最后的源文件生成二进制目标文件以及二进制目标文件链接生成可执行文件都是在rules_ti_cgt_arm.mk
文件中执行的。
.xer5f
可执行文件生成的规则如下:
.oer5f
二进制目标文件生成的规则如下:
所以,编译生成可执行文件主要是通过 rules_ti_cgt_arm.mk
的规则实现的,但源文件以及依赖的库文件都需要在上层 mk 文件中赋值。
.xer5f 文件生成 .tiimage 文件
回顾开头,也许你有些忘记了,通过如下命令,我们还需要将 .xer5f
转换为.tiimage
文件,如下:
命令简化如下:
$(MAKE) -C $($@_PATH) $($@_MAKEFILE) sbl_imagegen
参考 sbl_component.mk
文件,将变量展开,这条命令如下:
$(MAKE) -C $(PDK_SBL_COMP_PATH)/board/k3 -f$(PDK_SBL_COMP_PATH)/build/sbl_img.mk BOOTMODE=ospi SBL_USE_DMA=yes BUILD_HS=no sbl_imagegen
即,对 sbl_img.mk
执行 make, 目标为 sbl_imagegen
。
查看 sbl_img.mk
文件,在它包含的 $(MAKERULEDIR)/common.mk
文件中,sbl_imagegen
目标对应的规则如下:
该规则依赖 $(SBL_IMAGE_PATH)
, 该依赖对应的一个新的规则,如下:
同样, $(SBL_IMAGE_PATH)
依赖 $(SBL_BIN_FILE)
,该依赖同样对应一个新的规则,如下:
将 .xer5f
文件转换为 .bin
文件后,回到 $(SBL_IMAGE_PATH)
目标中,执行下列步骤生成 .tiimage
文件:
至此,大功告成(*^_^*)。
恭喜你看到了这里,这就是 sbl_ospi_img 整个的编译流程,TI RTOS SDK 的其余目标基本也基此流程。
我们可以在 /ti/boot/sbl/binary/j721e_evm/ospi/bin
目录下查看生成的文件。
( •̀ ω •́ )y,撒花撒花~
1. makefile 中,如果一个变量存在多个值,如何让变量的值换行输出
makefile 可以使用命令
FINAL_LIB_LIST = csl_init csl_intc csl csl_utils_common csl_uart_console board
print_test :
@$(ECHO) lib = $(foreach LIB,$(FINAL_LIB_LIST),""; echo "$(LIB)")
该命令可以让变量的值换行输出,结果如下:
root@ftcd-010:/mnt/d/ADC30/ti-processor-sdk-rtos-j784s4-evm-08_02_02_02/pdk_j784s4_08_02_02_04/packages/ti/build
lib =
csl_init
csl_intc
csl
csl_utils_common
csl_uart_console
board
2.如果想让上一个的命令作用到下一个命令中,那么两个命令需要写在同一行
makefile 文件如下:
dirtest0:
@cd /proc
@pwd
dirtest1:
@cd /proc; @pwd
只有 dirtest1 会正常输出路径名为:/proc
3. make -C 选项可以重新指定当前工作目录
makefile 文件中 -C 选项使用方式如下:
$(MAKE) -C $($@_PATH) $($@_MAKEFILE)
4.makefile 中命令包的定义
查询资料,makefile 中命令包都以 define 开始,以 endef 结束。
命令包可以用来创建规则。
下面创建了一个 CREATE_DEP_TARGETS 的命令包:
define CREATE_DEP_TARGETS
ifneq ($($(1)_DEPENDS_ON),)
ifeq ($($(1)_DEPENDS_ON),$(filter $($(1)_DEPENDS_ON), $($(2))))
$(1)_has_dep: $($(1)_DEPENDS_ON)_has_dep
+$(MAKE) -f $(PDK_INSTALL_PATH)/ti/build/makefile $(1)
$(2)_DEP_LIST += $($(1)_DEPENDS_ON)
else
$(1)_has_dep:
+$(MAKE) -f $(PDK_INSTALL_PATH)/ti/build/makefile $(1)
endif
else
$(1)_has_dep:
+$(MAKE) -f $(PDK_INSTALL_PATH)/ti/build/makefile $(1)
endif
endef
5. makefile 中 call 函数与 eval 函数以及命令包
下面这篇文章讲得非常好,请仔细阅读:
makefile 中 call 函数与 eval 函数的讲解
函数“eval”是一个比较特殊的函数。使用它可以在Makefile中构造一个可变的规则结构关系(依赖关系链),其中可以使用其它变量和函数
结合第 4 点,示例如下:
$(foreach LIB,$(FINAL_LIB_LIST),$(eval $(call CREATE_DEP_TARGETS,$(LIB),FINAL_LIB_LIST)))
$(foreach APP_LIB,$(FINAL_APP_LIB_LIST),$(eval $(call CREATE_DEP_TARGETS,$(APP_LIB),FINAL_APP_LIB_LIST)))
$(foreach EXAMPLE,$(FINAL_EXAMPLE_LIST),$(eval $(call CREATE_DEP_TARGETS,$(EXAMPLE),FINAL_EXAMPLE_LIST)))
$(foreach DUP_EXAMPLE,$(FINAL_DUP_EXAMPLE_LIST),$(eval $(call CREATE_DEP_TARGETS,$(DUP_EXAMPLE),FINAL_DUP_EXAMPLE_LIST)))
$(foreach FIRM,$(FINAL_FIRM_LIST),$(eval $(call CREATE_DEP_TARGETS,$(FIRM),FINAL_FIRM_LIST)))
$(foreach UTIL,$(FINAL_UTILS_LIST_ALL),$(eval $(call CREATE_DEP_TARGETS,$(UTIL),FINAL_UTILS_LIST_ALL)))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)