一,u-boot编译过程总结
编译时的Makefile log:
//链接得到ELF格式的u-boot
arm-buildroot-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x87800000 -o u-boot -T u-boot.lds arch/arm/cpu/armv7/start.o
--start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/imx-common/built-in.o arch/arm/lib/built-in.o board/freescale/common/built-in.o board/freescale/mx6ullevk/built-in.o cmd/built-in.o
common/built-in.o disk/built-in.o drivers/built-in.o drivers/dma/built-in.o drivers/gpio/built-in.o drivers/i2c/built-in.o drivers/mmc/built-in.o drivers/mtd/built-in.o drivers/mtd/onenand/built-in.o drivers/mtd/spi/built-in.o
drivers/net/built-in.o drivers/net/phy/built-in.o drivers/pci/built-in.o drivers/power/built-in.o drivers/power/battery/built-in.o drivers/power/domain/built-in.o drivers/power/fuel_gauge/built-in.o drivers/power/mfd/built-in.o
drivers/power/pmic/built-in.o drivers/power/regulator/built-in.o drivers/serial/built-in.o drivers/spi/built-in.o drivers/usb/cdns3/built-in.o drivers/usb/common/built-in.o drivers/usb/dwc3/built-in.o drivers/usb/emul/built-in.o
drivers/usb/eth/built-in.o drivers/usb/gadget/built-in.o drivers/usb/gadget/udc/built-in.o drivers/usb/host/built-in.o drivers/usb/musb-new/built-in.o drivers/usb/musb/built-in.o drivers/usb/phy/built-in.o drivers/usb/ulpi/built-in.o
fs/built-in.o lib/built-in.o net/built-in.o test/built-in.o test/dm/built-in.o --end-group arch/arm/lib/eabi_compat.o arch/arm/lib/lib.a -Map u-boot.map
//无设备树的u-boot-nodtb.bin
arm-buildroot-linux-gnueabihf-objcopy --gap-fill=0xff -j .text -j .secure_text -j .secure_data -j .rodata -j .hash -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn -j .efi_runtime -j .efi_runtime_rel -O binary u-boot u-boot-nodtb.bin
//编译设备树
make -f ./scripts/Makefile.build obj=dts dtbs
make -f ./scripts/Makefile.build obj=arch/arm/dts dtbs
test -e arch/arm/dts/imx6ull-14x14-evk.dtb || ( \
echo >&2; \
echo >&2 "Device Tree Source is not correctly specified."; \
echo >&2 "Please define 'CONFIG_DEFAULT_DEVICE_TREE'"; \
echo >&2 "or build with 'DEVICE_TREE=<device_tree>' argument"; \
echo >&2; \
/bin/false)
//最终的设备树
cat arch/arm/dts/imx6ull-14x14-evk.dtb > dts/dt.dtb
//含有设备树的 bin
cat u-boot-nodtb.bin dts/dt.dtb > u-boot-dtb.bin
make -f ./scripts/Makefile.build obj=arch/arm/imx-common u-boot-dtb.imx
mkdir -p board/freescale/mx6ullevk/
arm-buildroot-linux-gnueabihf-gcc -E -Wp,-MD,board/freescale/mx6ullevk/.imximage.cfg.cfgtmp.d -nostdinc -isystem /home/zhuwg1/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -I. -D__KERNEL__ -D__UBOOT__ -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -mword-relocations -fno-pic -mno-unaligned-access -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv7-a -D__LINUX_ARM_ARCH__=7 -x c -o board/freescale/mx6ullevk/imximage.cfg.cfgtmp board/freescale/mx6ullevk/imximage.cfg
//制作映像文件 u-boot-dtb.imx
./tools/mkimage -n board/freescale/mx6ullevk/imximage.cfg.cfgtmp -T imximage -e 0x87800000 -d u-boot-dtb.bin u-boot-dtb.imx
Image Type: Freescale IMX Boot Image
Image Ver: 2 (i.MX53/6/7 compatible)
Mode: DCD
Data Size: 524288 Bytes = 512.00 KiB = 0.50 MiB
Load Address: 877ff420
Entry Point: 87800000
二,具体的编译过程
1,结论
细节如下:
-
执行make命令时,要编译得到哪些文件由ALL-y 决定
*规则如下
include config.mk # 里面会包含arch/arm/config.mk(含有ALL-y +=
u-boot-dtb.imx)
_all : all
# 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 binary_size_check
ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb
all: $(ALL-y)
*ALL-y 的值为:
checkarmreloc u-boot-dtb.imx u-boot.srec u-boot.bin u-boot.sym
System.map binary_size_check u-boot.dtb
-
u-boot-dtb.imx依赖于u-boot-dtb.bin,u-boot-dtb.bin又依赖于u-boot-nodtb.bin和dts/dt.dtb
-
各类u-boot文件都依赖于u-boot,先编译得到u-boot,它由u-boot-init 、u-boot-main 两部分链接而成
* u-boot-init为:arch/arm/cpu/armv7/start.o
*u-boot-main为:lib/built-in.o fs/built-in.o net/built-in.o 等等
*如何编译各个built-in.o,以lib/built-in.o为例
执行: `make -f ./scripts/Makefile.build obj=lib
会包含lib/Makefile,里面定义了obj-y
使用Makefile.build的规则把各个obj-y编译、链接为built-in.o
*使用如下的命令链接得到u-boot:
quiet_cmd_u-boot__ ?= LD $@
cmd_u-boot__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_u-boot) -o $@ \
-T u-boot.lds $(u-boot-init) \
--start-group $(u-boot-main) --end-group \
$(PLATFORM_LIBS) -Map u-boot.map
-
再编译得到设备树文件: make -f ./scripts/Makefile.build obj=dts dtbs
*顶层Makefile如下:
dts/dt.dtb: checkdtc u-boot
$(Q)$(MAKE) $(build)=dts dtbs
*scripts/Makefile.build中,会包含 dts/Makefile
DTB := arch/$(ARCH)/dts/$(DEVICE_TREE).dtb
$(DTB): arch-dtbs
$(obj)/dt.dtb: $(DTB) FORCE
$(call if_changed,shipped)
targets += dt.dtb
$(DTB): arch-dtbs
$(Q)test -e $@ || ( \
echo >&2; \
echo >&2 "Device Tree Source is not correctly specified."; \
echo >&2 "Please define 'CONFIG_DEFAULT_DEVICE_TREE'"; \
echo >&2 "or build with 'DEVICE_TREE=<device_tree>' argument"; \
echo >&2; \
/bin/false)
arch-dtbs:
$(Q)$(MAKE) $(build)=arch/$(ARCH)/dts dtbs
.SECONDARY: $(obj)/dt.dtb.S
obj-$(CONFIG_OF_EMBED) := dt.dtb.o
dtbs: $(obj)/dt.dtb
@:
- 最后把u-boot、设备树打包: make -f ./scripts/Makefile.build obj=arch/arm/imx-common u-boot-dtb.imx
include config.mk # 里面会包含arch/arm/config.mk(含有ALL-y += uboot-
dtb.imx)
%.imx: %.bin
$(Q)$(MAKE) $(build)=arch/arm/imx-common $@
2,顶层Makefile
顶层Makefile里:
-
包含架构相关的Makefile,里面指定了第1个文件(head-y)
-
指定了要编译哪些子目录(libs-y)。
从顶层Makefile开始分析:
include config.mk # 里面会包含arch/arm/config.mk(含有ALL-y += u-bootdtb.imx)
include arch/$(ARCH)/Makefile # arch/arm/Makefile, 里面含有head-y libs-y
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 += $(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))
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map binary_size_check
对于arch/arm/Makefile :
head-y := arch/arm/cpu/$(CPU)/start.o
libs-y += arch/arm/cpu/$(CPU)/
libs-y += arch/arm/cpu/
libs-y += arch/arm/lib/
所以,顶层Makefile包含了arch/arm/Makefile ,确定了head-y为arch/arm/cpu/armv7/start.o 。
还定义了libs-y变量,它里面含有多个目录。
3,编译子目录
顶层Makefile里定义了libs-y,会进入里面每一目录,使用它的Makefile进行编译:
boot-main := $(libs-y)
$(sort $(u-boot-init) $(u-boot-main)): $(u-boot-dirs) ;
u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples
$(u-boot-dirs): prepare scripts
# make -f $(srctree)/scripts/Makefile.build obj=arch/arm/cpu/arm7
$(Q)$(MAKE) $(build)=$@
比如:u-boot-main里面含有一个目录"arch/arm/cpu/armv7/",在u-boot-dirs中它末尾的"/"被取消,
就变成:arch/arm/cpu/armv7。
然后使用scripts/Makefile.build进行处理:$(Q)$(MAKE) $(build)=$@ ,展开就是:
make -f scripts/Makefile.build obj=arch/arm/cpu/armv7/
scripts/Makefile.build是编译u-boot源码的关键:
src := $(patsubst $(prefix)/%,%,$(obj)) # obj=arch/arm/cpu/arm7/,
src=arch/arm/cpu/armv7
# 第1个目标
__build:
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuilddir)/
Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file) # 包含 arch/arm/cpu/arm7/Makefile
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a # 如果包含的arch/arm/cpu/armv7/Makefile里定义了lib-y
endif
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o # 如果包含的arch/arm/cpu/armv7/Makefile里定义了
obj-y
endif
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
ifdef builtin-target
quiet_cmd_link_o_target = LD $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cmd_secanalysis),\
rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
targets += $(builtin-target)
endif # builtin-target
核心脚本Makefile.build脚本分析:
4,链接得到u-boot
顶层Makefile里:
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
# Rule to link u-boot
# May be overridden by arch/$(ARCH)/config.mk
/*
*执行cmd_u-boot__指令
*
arm-buildroot-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x87800000 -o u-boot -T u-boot.lds arch/arm/cpu/armv7/start.o
--start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/imx-common/built-in.o arch/arm/lib/built-in.o board/freescale/common/built-in.o board/freescale/mx6ullevk/built-in.o cmd/built-in.o
common/built-in.o disk/built-in.o drivers/built-in.o drivers/dma/built-in.o drivers/gpio/built-in.o drivers/i2c/built-in.o drivers/mmc/built-in.o drivers/mtd/built-in.o drivers/mtd/onenand/built-in.o drivers/mtd/spi/built-in.o
drivers/net/built-in.o drivers/net/phy/built-in.o drivers/pci/built-in.o drivers/power/built-in.o drivers/power/battery/built-in.o drivers/power/domain/built-in.o drivers/power/fuel_gauge/built-in.o drivers/power/mfd/built-in.o
drivers/power/pmic/built-in.o drivers/power/regulator/built-in.o drivers/serial/built-in.o drivers/spi/built-in.o drivers/usb/cdns3/built-in.o drivers/usb/common/built-in.o drivers/usb/dwc3/built-in.o drivers/usb/emul/built-in.o
drivers/usb/eth/built-in.o drivers/usb/gadget/built-in.o drivers/usb/gadget/udc/built-in.o drivers/usb/host/built-in.o drivers/usb/musb-new/built-in.o drivers/usb/musb/built-in.o drivers/usb/phy/built-in.o drivers/usb/ulpi/built-in.o
fs/built-in.o lib/built-in.o net/built-in.o test/built-in.o test/dm/built-in.o --end-group arch/arm/lib/eabi_compat.o arch/arm/lib/lib.a -Map u-boot.map
*/
quiet_cmd_u-boot__ ?= LD $@
cmd_u-boot__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_u-boot) -o $@ \
-T u-boot.lds $(u-boot-init) \
--start-group $(u-boot-main) --end-group \
$(PLATFORM_LIBS) -Map u-boot.map
quiet_cmd_smap = GEN common/system_map.o
cmd_smap = \
smap=`$(call SYSTEM_MAP,u-boot) | \
awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\\\000"}'` ; \
$(CC) $(c_flags) -DSYSTEM_MAP="\"$${smap}\"" \
-c $(srctree)/common/system_map.c -o common/system_map.o
//cmd_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:
5,映像文件的依赖
对于IMX6ULL,要使用的是u-boot-dtb.imx,它含有u-boot和设备树。
在顶层Makefile里:
include config.mk # 里面会包含arch/arm/config.mk(含有ALL-y += u-bootdtb.imx)
%.imx: %.bin
$(Q)$(MAKE) $(build)=arch/arm/imx-common $@
u-boot-dtb.imx依赖于u-boot-dtb.bin,u-boot-dtb.bin又依赖于u-boot-nodtb.bin和dts/dt.dtb。
在顶层Makefile里:
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
所以,编译出u-boot后,会先制作u-boot-nodtb.bin;然后编译dts/dt.dtb;最后生成u-boot-dtb.bin、imx文件:
6,编译设备树
顶层Makefile里:
dts/dt.dtb: checkdtc u-boot
# make -f $(srctree)/scripts/Makefile.build obj=dts dtbs
$(Q)$(MAKE) $(build)=dts dtbs
需要用到scripts/Makefile.build中,它会包含 dts/Makefile, dts/Makefile中含有dtbs目标:
DEVICE_TREE ?= $(CONFIG_DEFAULT_DEVICE_TREE:"%"=%)
DTB := arch/$(ARCH)/dts/$(DEVICE_TREE).dtb # 就是 arch/arm/dts/imx6ull-14x14-evk.dtb
$(obj)/dt.dtb: $(DTB) FORCE
$(call if_changed,shipped)
targets += dt.dtb
$(DTB): arch-dtbs
$(Q)test -e $@ || ( \
echo >&2; \
echo >&2 "Device Tree Source is not correctly specified."; \
echo >&2 "Please define 'CONFIG_DEFAULT_DEVICE_TREE'"; \
echo >&2 "or build with 'DEVICE_TREE=<device_tree>' argument"; \
echo >&2; \
/bin/false)
arch-dtbs:
$(Q)$(MAKE) $(build)=arch/$(ARCH)/dts dtbs
.SECONDARY: $(obj)/dt.dtb.S
obj-$(CONFIG_OF_EMBED) := dt.dtb.o
dtbs: $(obj)/dt.dtb
@:
最后会使用$(Q)$(MAKE) $(build)=arch/$(ARCH)/dts dtbs 来处理,使用arch/arm/dts/Makefile,里面定了dtb-y:
dtb-$(CONFIG_MX6) += imx6ul-14x14-ddr3-arm2.dtb \
imx6ul-14x14-ddr3-arm2-emmc.dtb \
imx6ul-14x14-ddr3-arm2-gpmi-weim.dtb \
imx6ul-14x14-lpddr2-arm2.dtb \
imx6ul-14x14-evk.dtb \
imx6ul-14x14-evk-emmc.dtb \
PHONY += dtbs
dtbs: $(addprefix $(obj)/, $(dtb-y))
@:
要编译出各类dtb文件,用到scripts/Makefile.lib,规则如下:
quiet_cmd_dtc = DTC $@
# Modified for U-Boot
# Bring in any U-Boot-specific include after the '/dts-v1/;' header
cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
cat $< $(if $(u_boot_dtsi),\
| sed '/^\/ {$$/{x;s%$$%\#include \"$(u_boot_dtsi)\"%;G;}') | \
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ;
\
$(DTC) -O dtb -o $@ -b 0 \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
$(obj)/%.dtb: $(src)/%.dts FORCE
$(call if_changed_dep,dtc)
7,制作映像文件
当制作出设备树文件后,在顶层Makefile里有如下规则,进而制作出u-boot-dtb.bin:
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)
回到顶层Makefile,看看如何制作imx映像文件:
include config.mk # 里面会包含arch/arm/config.mk(含有ALL-y += u-bootdtb.imx)
%.imx: %.bin
$(Q)$(MAKE) $(build)=arch/arm/imx-common $@
现在u-boot-dtb.imx的依赖文件u-boot-dtb.bin已经生成了,将会使用arch/arm/imxcommon/Makefile来生产imx文件:
u-boot.imx: u-boot.bin $(IMX_CONFIG) $(PLUGIN).bin FORCE
$(call if_changed,mkimage)
最后会使用如下命令生产imx映像文件:
./tools/mkimage -n board/freescale/mx6ullevk/imximage.cfg.cfgtmp -T imximage -e
0x87800000 -d u-boot-dtb.bin u-boot-dtb.imx
u-boot-dtb.imx生成过程总结: