uboot-Makefile学习(5)

学习目标:

uboot顶层Makefile分析。

学习内容:

学习使用了正点原子的I.MX6ULL教程及开发平台。
uboot的make过程。

学习时间:

2022-06-29

学习产出:

配置好uboot以后就可以直接make进行编译了,因为没有指明目标,所以会使用默认的目标,主Makefile中的默认目标如下:

# That's our default target when none is given on the command line
PHONY := _all
_all:

目标_all又依赖与all,如下所示:

PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif

因为没有编译模块,所以KBUILD_EXTMOD为空,_all依赖于all。all的目标规则如下:

all:		$(ALL-y)
ifneq ($(CONFIG_SYS_GENERIC_BOARD),y)
	@echo "===================== WARNING ======================"
	@echo "Please convert this board to generic board."
	@echo "Otherwise it will be removed by the end of 2014."
	@echo "See doc/README.generic-board for further information"
	@echo "===================================================="
endif
ifeq ($(CONFIG_DM_I2C_COMPAT),y)
	@echo "===================== WARNING ======================"
	@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
	@echo "(possibly in a subsequent patch in your series)"
	@echo "before sending patches to the mailing list."
	@echo "===================================================="
endif

可以看出all的依赖为$(ALL_y),而在顶层Makefile中ALL-y如下:

# Always append ALL so that arch config.mk's can add custom ones
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check

ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin
ifeq ($(CONFIG_SPL_FSL_PBL),y)
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot-with-spl-pbl.bin
else
ifneq ($(CONFIG_SECURE_BOOT), y)
# For Secure Boot The Image needs to be signed and Header must also
# be included. So The image has to be built explicitly
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl
endif
endif
ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb
ifeq ($(CONFIG_SPL_FRAMEWORK),y)
ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
endif
ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb
ifneq ($(CONFIG_SPL_TARGET),)
ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%)
endif
ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf
ALL-$(CONFIG_EFI_APP) += u-boot-app.efi
ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi

ifneq ($(BUILD_ROM),)
ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom
endif

# enable combined SPL/u-boot/dtb rules for tegra
ifeq ($(CONFIG_TEGRA)$(CONFIG_SPL),yy)
ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb-tegra.bin
endif

# Add optional build target if defined in board/cpu/soc headers
ifneq ($(CONFIG_BUILD_TARGET),)
ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
endif

可以看出ALL-y包含了u-boot.srec、u-boot.bin、u-boot.sym、System.map、u-boot.cfg和binary_size_check这几个文件。根据uboot的配置情况也会包含其他文件,例如:

ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin

CONFIG_ONENAND_U_BOOT是跟ONENAND配置有关的,如果使能了ONENAND,那么在.config配置文件中就会有"CONFIG_ONENAND_U_BOOT=y"这一句话,所以以上代码展开后就为:

ALL-y += u-boot-onenand.bin

ALL-y中还有个u-boot.bin,这个就是我们最终需要的uboot二进制可执行文件,所作的巩固走都是为了它。在顶层Makefile下找到uboot.bin目标对应的规则,如下所示:

ifeq ($(CONFIG_OF_SEPARATE),y)
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
	$(call if_changed,cat)

u-boot.bin: u-boot-dtb.bin FORCE
	$(call if_changed,copy)
else
u-boot.bin: u-boot-nodtb.bin FORCE
	$(call if_changed,copy)
endif

首先判断CONFIG_OF_SEPARATE是否等于y,通过增加打印信息,我们可知此处条件并不成立,所以uboot.bin的规则变为:

u-boot.bin: u-boot-nodtb.bin FORCE
	$(call if_changed,copy)

uboot.bin依赖于u-boot-nodtb.bin,命令为$(call if_changed,copy),这里调用了if_changed,if_changed是一个函数,此函数在scripts/Kbuild.include中有定义,而在顶层Makefile中会包含此文件,if_changed的定义如下:

###
# if_changed      - execute command if any prerequisite is newer than
#                   target, or command line has changed
# if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
#                   including used config symbols
# if_changed_rule - as if_changed but execute rule instead
# See Documentation/kbuild/makefiles.txt for more info

ifneq ($(KBUILD_NOCMDDEP),1)
# Check if both arguments has same arguments. Result is empty string if equal.
# User may override this check using make KBUILD_NOCMDDEP=1
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                    $(filter-out $(cmd_$@),   $(cmd_$(1))) )
else
arg-check = $(if $(strip $(cmd_$@)),,1)
endif

# Replace >$< with >$$< to preserve $ when reloading the .cmd file
# (needed for make)
# Replace >#< with >\#< to avoid starting a comment in the .cmd file
# (needed for make)
# Replace >'< with >'\''< to be able to enclose the whole string in '...'
# (needed for the shell)
make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1)))))

# Find any prerequisites that is newer than target or that does not exist.
# PHONY targets skipped in both cases.
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)

# Execute command if command has changed or prerequisite(s) are updated.
#
if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
	@set -e;                                                             \
	$(echo-cmd) $(cmd_$(1));                                             \
	printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

此处if_changed的作用就是从u-boot-notdb.bin生成u-boot.bin。
生成u-boot-notdb.bin在顶测光Makefile下有如下代码:

u-boot-nodtb.bin: u-boot FORCE
	$(call if_changed,objcopy)
	$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
	$(BOARD_SIZE_CHECK)

目标u-boot-nodtb.bin又依赖于u-boot,顶层Makefile中u-boot有如下代码:

u-boot:	$(u-boot-init) $(u-boot-main) u-boot.lds FORCE
	$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
	$(call cmd,smap)
	$(call cmd,u-boot__) common/system_map.o
endif

u-boot又依赖于目标u-boot-init、u-boot-main和u-boot.lds,u-boot-init和u-boot-main是两个变量,在顶层Makefile下有定义,值如下:


u-boot-init := $(head-y)
u-boot-main := $(libs-y)

head-y在arch/arm/Makefile中被指定为:

head-y := arch/arm/cpu/$(CPU)/start.o

之前分析过,$(CPU)为armv7,因此head-y站靠后就为:

head-y := arch/arm/cpu/armv7/start.o

因此,

u-boot-init := arch/arm/cpu/armv7/start.o

$(libs-y)在顶层Makefile中被定义为uboot所有子目录下build-in.o的集合,代码如下:

libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += fs/
libs-y += net/
libs-y += disk/
libs-y += drivers/
libs-y += drivers/dma/
libs-y += drivers/gpio/
libs-y += drivers/i2c/
libs-y += drivers/mmc/
libs-y += drivers/mtd/
libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/
libs-y += drivers/mtd/onenand/
libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/
libs-y += drivers/mtd/spi/
libs-y += drivers/net/
libs-y += drivers/net/phy/
libs-y += drivers/pci/
libs-y += drivers/power/ \
	drivers/power/fuel_gauge/ \
	drivers/power/mfd/ \
	drivers/power/pmic/ \
	drivers/power/battery/ \
	drivers/power/regulator/
libs-y += drivers/spi/
libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
libs-$(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
libs-y += drivers/serial/
libs-y += drivers/usb/dwc3/
libs-y += drivers/usb/emul/
libs-y += drivers/usb/eth/
libs-y += drivers/usb/gadget/
libs-y += drivers/usb/gadget/udc/
libs-y += drivers/usb/host/
libs-y += drivers/usb/musb/
libs-y += drivers/usb/musb-new/
libs-y += drivers/usb/phy/
libs-y += drivers/usb/ulpi/
libs-y += cmd/
libs-y += common/
libs-$(CONFIG_API) += api/
libs-$(CONFIG_HAS_POST) += post/
libs-y += test/
libs-y += test/dm/
libs-$(CONFIG_UT_ENV) += test/env/

libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)

libs-y := $(sort $(libs-y))

u-boot-dirs	:= $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples

u-boot-alldirs	:= $(sort $(u-boot-dirs) $(patsubst %/,%,$(filter %/, $(libs-))))

libs-y		:= $(patsubst %/, %/built-in.o, $(libs-y))

从上面代码可以看出,libs-y都是uboot各子目录的集合,最后

libs-y		:= $(patsubst %/, %/built-in.o, $(libs-y))

调用了patsubst,将libs-y中的“/”替换为“/built-in.o”,相当于将libs-y改为所有子目录中build-in.o文件的集合。那么,u-boot-main就是所有子目录中build-in.o的集合。
生成u-boot的这个规则就相当于将以u-boot.lds为链接脚本,将arch/arm/cpu/armv7/start.o和各个目录下的build-in.o链接在一起生辰u-boot。
u-boot.lds的规则如下:

u-boot.lds: $(LDSCRIPT) prepare FORCE
$(call if_changed_dep,cpp_lds)

接下来的重点就是各子目录下的 built-in.o 是怎么生成的,以 drivers/gpio/built-in.o 为例,在drivers/gpio/目录下会有个名为.built-in.o.cmd 的文件,此文件内容如下:

cmd_drivers/gpio/built-in.o := arm-linux-gnueabihf-ld.bfd -r -o
drivers/gpio/built-in.o drivers/gpio/mxc_gpio.o

从命令“cmd_drivers/gpio/built-in.o”可以看出, drivers/gpio/built-in.o 这个文件是使用 ld 命令由文件 drivers/gpio/mxc_gpio.o 生成而来的, mxc_gpio.o 是 mxc_gpio.c 编译生成的.o 文件,这个是 NXP 的 I.MX 系列的 GPIO 驱动文件。
这里用到了 ld 的“-r”参数,参数含义如下:
-r –relocateable: 产生可重定向的输出,比如,产生一个输出文件它可再次作为‘ld’ 的输入,这经常被叫做“部分链接”,当我们需要将几个小的.o 文件链接成为一个.o 文件的时候,需要使用此选项。
最终将各个子目录中的 built-in.o 文件链接在一起就形成了 u-boot。
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值