u-boot 编译过程分析

前言

写文章的目的是想通过记录自己的学习过程,以便以后使用到相关的知识点可以回顾和参考。

u-boot的编译流程

1、make distclean --------- //先清理一下工程
2、make xxx_config ------ //配置uboot(xxx为开发板的名字)
3、make all ------------------ //最终编译生成我们所需要的uboot.bin
通过以上三条命令,uboot的编译就完成了,接下来分析一下这三个命令是怎样个工作流程来实现我们最终的目的

一、u-boot清理工程过程分析

make distclean命令的作用是清理工程,把以前编译生成的文件清理掉。打开顶层Makefile,搜索distclean定位到以下代码段

# distclean
#
PHONY += distclean

distclean: mrproper
	@find $(srctree) $(RCS_FIND_IGNORE) \
		\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
		-o -name '.*.rej' -o -name '*%' -o -name 'core' \
		-o -name '*.pyc' \) \
		-type f -print | xargs rm -f

“|”表示管道,即左边的输出作为右边的输入,实现删除编辑器备份文件,修补遗留文件等。同时发现依赖mrproper,接着搜索mrproper

# mrproper - Delete all generated files, including .config
#
# Directories & files removed with 'make mrproper'
MRPROPER_DIRS  += include/config include/generated          \
		  .tmp_objdiff
MRPROPER_FILES += .config .config.old \
		  tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
		  include/config.h include/config.mk
		  
mrproper: rm-dirs  := $(wildcard $(MRPROPER_DIRS))
mrproper: rm-files := $(wildcard $(MRPROPER_FILES))
mrproper-dirs      := $(addprefix _mrproper_,scripts)

PHONY += $(mrproper-dirs) mrproper archmrproper
$(mrproper-dirs):
	$(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@)

mrproper: clobber $(mrproper-dirs)
	$(call cmd,rmdirs)
	$(call cmd,rmfiles)
	@rm -f arch/*/include/asm/arch

这里删除所有生成的文件,包括配置文件,同时依赖clobber,搜索clobber

clobber: clean tidy
	$(call cmd,rmdirs)
	$(call cmd,rmfiles)

看到依赖clean和tidy,接着搜索clean和tidy

clean: $(clean-dirs)
	$(call cmd,rmdirs)
	$(call cmd,rmfiles)
	@find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
		-o -name '*.ko.*' -o -name '*.su' -o -name '*.cfgtmp' \
		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
		-o -name '*.symtypes' -o -name 'modules.order' \
		-o -name modules.builtin -o -name '.tmp_*.o.*' \
		-o -name '*.gcno' \) -type f -print | xargs rm -f

tidy:	
	@find $(OBJTREE) -type f \( -name '*.depend*' \) -print | xargs rm -f

clean和dity也是清除生成的文件,不过是一大部分,不是全部。

所以总结得:
make clean:主要删除.o以及可执行文件
make mrproper:在clean的基础上删除配置生成文件
make distclean:删除所有生成的文件

二、u-boot配置过程分析

make xxx_config命令的作用是配置uboot,每个开发板厂家都会提供这个配置文件,通常以板子的名字来命名,我使用的是6818开发板,则使用命令make x6818_config。打开顶层Makefile
,搜索%_config

%_config:: outputmakefile
	@$(MKCONFIG) -A $(@:_config=)

$(@:_config=)意思是把目标x6818_config的_config替换为空,得到x6818。结合上下文展开得:

@./mkconfig -A x6818

再次搜索依赖outputmakefile

outputmakefile:
ifneq ($(KBUILD_SRC),)
	$(Q)ln -fsn $(srctree) source
	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
	    $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

因为KBUILD_SRC为空,所以条件不成立,不会进入执行下面的命令,那么只需要去分析@./mkconfig -A x6818这一条命令就可以,可以看出使用到了mkconfig,则打开mkconfig进行分析

if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then
	# Automatic mode
	line=`awk '($0 !~ /^#/ && $7 ~ /^'"$2"'$/) { print $1, $2, $3, $4, $5, $6, $7, $8 }' $srctree/boards.cfg`
	if [ -z "$line" ] ; then
		echo "make: *** No rule to make target \`$2_config'.  Stop." >&2
		exit 1
	fi

	set ${line}
	# add default board name if needed
	[ $# = 3 ] && set ${line} ${1}
fi

@./mkconfig -A x6818命令的参数有两个且第一个参数为-A,条件成立,则进入判断执行下面代码,
line=awk '($0 !~ /^#/ && $7 ~ /^'"$2"'$/) { print $1, $2, $3, $4, $5, $6, $7, $8 }' $srctree/boards.cfg,使用到awk命令,把boards.cfg里面匹配到的信息提取到line中,打开配置文件boards.cfg

在这里插入图片描述
展开得

line= Active arm slsiap s5p6818 s5p6818 x6818 x6818 -

set ${line}作用是为了后面方便使用line中的数据,比如

$1:Active,
$2:arm,
$3:slsiap,
$4:s5p6818,
$5:s5p6818,
$6:x6818,
$7:x6818,
$8:-

继续分析mkconfig

CONFIG_NAME="${7%_config}"

[ "${BOARD_NAME}" ] || BOARD_NAME="${7%_config}"

arch="$2"
cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $1}'`
spl_cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $2}'`

展开得:

CONFIG_NAME=x6818_config
arch=arm
cpu=slsiap

继续分析

if [ -n "$KBUILD_SRC" ] ; then
	mkdir -p ${objtree}/include
	LNPREFIX=${srctree}/arch/${arch}/include/asm/
	cd ${objtree}/include
	mkdir -p asm
else
	cd arch/${arch}/include
fi

rm -f asm/arch

if [ "${soc}" ] ; then
	ln -s ${LNPREFIX}arch-${soc} asm/arch
elif [ "${cpu}" ] ; then
	ln -s ${LNPREFIX}arch-${cpu} asm/arch
fi

在Makifile中知道KBUILD_SRC为空,返回1,条件成立,执行下面语句,又soc=s5p6818,不为空,则创建头文件链接,展开得

mkdir -p ./include
LNPREFIX=./arch/arm/include/asm/
cd ./include
mkdir -p asm
ln -s ./arch/arm/include/asm/arch-s5p6818 asm/arch

继续分析

# Create include file for Make
#
( echo "ARCH   = ${arch}"
    if [ ! -z "$spl_cpu" ] ; then
	echo 'ifeq ($(CONFIG_SPL_BUILD),y)'
	echo "CPU    = ${spl_cpu}"
	echo "else"
	echo "CPU    = ${cpu}"
	echo "endif"
    else
	echo "CPU    = ${cpu}"
    fi
    echo "BOARD  = ${board}"

    [ "${vendor}" ] && echo "VENDOR = ${vendor}"
    [ "${soc}"    ] && echo "SOC    = ${soc}"
    exit 0 ) > config.mk

这里创建了include/config.mk

ARCH = arm
CPU = slsiap
BOARD = x6818
VENDOR = s5p6818
SOC = s5p6818

继续分析

# Create board specific header file
#
if [ "$APPEND" = "yes" ]	# Append to existing config file
then
	echo >> config.h
else
	> config.h		# Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h

for i in ${TARGETS} ; do
	i="`echo ${i} | sed '/=/ {s/=/	/;q; } ; { s/$/	1/; }'`"
	echo "#define CONFIG_${i}" >>config.h ;
done

echo "#define CONFIG_SYS_ARCH  \"${arch}\""  >> config.h
echo "#define CONFIG_SYS_CPU   \"${cpu}\""   >> config.h
echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h

[ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h

[ "${soc}"    ] && echo "#define CONFIG_SYS_SOC    \"${soc}\""    >> config.h

[ "${board}"  ] && echo "#define CONFIG_BOARDDIR board/$BOARDDIR" >> config.h
cat << EOF >> config.h
#include <config_cmd_defaults.h>
#include <config_defaults.h>
#include <configs/${CONFIG_NAME}.h>
#include <asm/config.h>
#include <config_fallbacks.h>
#include <config_uncmd_spl.h>
EOF

这里创建了开发板相关头文件include/config.h

/* Automatically generated - do not edit */
#define CONFIG_SYS_ARCH “arm”
#define CONFIG_SYS_CPU “slsiap”
#define CONFIG_SYS_BOARD “x6818”
#define CONFIG_SYS_VENDOR “s5p6818”
#define CONFIG_SYS_SOC “s5p6818”
#define CONFIG_BOARDDIR board/s5p6818/x6818
#include <config_cmd_defaults.h>
#include <config_defaults.h>
#include <configs/x6818.h>
#include <asm/config.h>
#include <config_fallbacks.h>
#include <config_uncmd_spl.h>

从config.h中,我们可以得出:如果要在board目录下新建一个开发板的目录,则在include/configs目录下也要建立一个文件<board_name.h>,里面存放的就是<board_name>的配置信息。

记得以前在学校中老师也教过使用make menuconfig来配置,它是一种类似Linux一样的可视化配置界面,要手动修改配置文件include/configs/<board_name>.h 来裁减、设置uboot。

三、u-boot编译过程分析

make all命令就是编译uboot了,生成我们最终需要的u-boot.bin,接下来分析下编译的过程,在顶层Makefile中搜索all

all:		$(ALL-y)

可以看到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 System.map 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
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl
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 u-boot-dtb.bin
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

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

可以看出ALL-y包含了u-boot.srec,u-boot.bin,System.map,binary_size_check这几个文件,当然也会包含其他文件,比如下面的u-boot-onenand.bin等,这取决去在上面配置uboot时生成的./include/config.h里面包含了.h头文件里面有没有定义CONFIG_ONENAND_U_BOOT这些变量值是否为“y”,例如CONFIG_ONENAND_U_BOOT=y,那么u-boot-onenand.bin就会生成

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

u-boot.bin: u-boot FORCE
	$(call if_changed,objcopy)
	$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
	$(BOARD_SIZE_CHECK)
	#./tools/mk6818 x6818u-boot.bin nsih.txt 2ndboot u-boot.bin

看出目标u-boot.bin依赖于u-boot,搜索u-boot相关规则:

u-boot:	$(u-boot-init) $(u-boot-main) u-boot.lds
	$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
	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
	$(call cmd,u-boot__) common/system_map.o
endif

u-boot又依赖于u-boot-init,u-boot-main ,u-boot.lds。u-boot.lds 是链接文件,而 u-boot-init 和 u-boot-main 是两个变量,在顶层Makefile中的定义如下:

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

$(head-y)在顶层Makefile中定义:

head-y := $(CPUDIR)/start.o

因为 (head-y) 跟 CPU 架构有关,我们使用的是 ARM 芯片,在./config.mk中 CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)

,所以$(CPUDIR)的路径是./arch/arm/cpu/slsiap,因此展开得:

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

接着在顶层Makefile中搜索$(libs-y)

libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-y += $(CPUDIR)/
ifdef SOC
libs-y += $(CPUDIR)/$(SOC)/
endif
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += arch/$(ARCH)/lib/
libs-y += fs/
libs-y += net/
libs-y += disk/
libs-y += drivers/
libs-$(CONFIG_DM) += drivers/core/
libs-y += drivers/dma/
libs-y += drivers/gpio/
libs-y += drivers/i2c/
libs-y += drivers/input/
libs-y += drivers/mmc/
ifdef CONFIG_NAND_MTD
libs-y += drivers/mtd/
libs-y += drivers/mtd/nand/
libs-y += drivers/mtd/onenand/
libs-y += drivers/mtd/spi/
libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/
endif
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/
libs-y += drivers/spi/
libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
libs-y += drivers/serial/
libs-y += drivers/usb/eth/
libs-y += drivers/usb/gadget/
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 += common/
libs-y += lib/libfdt/
libs-$(CONFIG_API) += api/
libs-$(CONFIG_HAS_POST) += post/
libs-y += test/
libs-y += test/dm/
libs-$(CONFIG_DM_DEMO) += drivers/demo/

ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx31 mx35 mxs vf610))
libs-y += arch/$(ARCH)/imx-common/
endif

libs-$(CONFIG_ARM) += arch/arm/cpu/
libs-$(CONFIG_PPC) += arch/powerpc/cpu/

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))

可以看出$(head-y)是 uboot 各子目录的集合,然后通过 libs-y := $(patsubst %/, %/built-in.o, $(libs-y)) 把 “/" 替换为 “/built-in.o” ,相当于将 libs-y 改为所有子目录中 built-in.o 文件的集合。那么

u-boot-main 就等于所有子目录中 built-in.o 的集合。

这个规则就相当于将以 u-boot.lds 为链接脚本,将 ./arch/arm/cpu/slsiap/start.o 和各个子目录
下的 built-in.o 链接在一起生成 u-boot。

总结一下make all编译过程,如下图:
在这里插入图片描述

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 编译mt7621配置的U-Boot需要进行以下步骤: 首先,确认已经准备好编译环境,包括安装好交叉编译工具链和相关依赖库。 然后,从U-Boot官方仓库中获取最新的源代码。可以使用git命令进行克隆,例如: git clone https://github.com/u-boot/u-boot.git 接下来,切换到代码目录并进入配置界面,执行以下命令: cd u-boot make menuconfig 在配置界面中,选择"MTK",然后选择"MTK_MT7621"作为目标平台。根据需要,可以进行其他选项的配置,如串口、网络等。 配置完成后,保存退出配置界面。然后,执行以下命令进行编译: make CROSS_COMPILE=<交叉编译工具链前缀> 编译过程可能需要一段时间,取决于计算机性能和代码规模。 编译完成后,可以得到u-boot.bin文件作为编译结果。该文件可以烧录到MT7621芯片的Flash中,用于启动设备。 以上是编译mt7621配置的U-Boot的大致步骤。根据具体需求,可能还需要进行其他配置和调整。在进行编译前,建议查阅U-Boot的官方文档和相关资料,以便更详细地了解配置和编译过程。 ### 回答2: 编译 U-Boot for MT7621 配置需要先准备编译环境和相关工具链。以下是编译 MT7621 配置的步骤: 1. 首先,确保你的系统上已经安装了交叉编译工具链。可以通过执行以下命令来检查是否已安装交叉编译工具链: ``` arm-openwrt-linux-gcc -v ``` 如果显示出工具链的版本信息,则表示已经安装成功。 2. 下载 U-Boot 的源码。你可以通过 Git 或者下载压缩包的方式获取源码。例如,使用 Git 命令来克隆 U-Boot 的仓库: ``` git clone https://github.com/u-boot/u-boot.git ``` 3. 进入源码目录,并创建编译配置文件。执行以下命令: ``` cd u-boot make mt7621_xxx_config ``` 其中,`mt7621_xxx_config` 是针对你的具体设备的配置文件,例如 `mt7621_rfb_config` 或 `mt7621_xxx_config` 等。你可以查阅相关文档来确定正确的配置文件。 4. 根据配置文件生成编译规则。执行以下命令: ``` make oldconfig ``` 根据你的需求来回答一些提示问题。默认选项通常是可以满足大多数需求的。 5. 开始编译。执行以下命令: ``` make ``` 编译时间会根据你的机器性能和代码大小而不同。最终编译产生的 U-Boot 可执行文件将位于生成文件夹中。 完成上述步骤后,你将获得一个适用于 MT7621 的 U-Boot 可执行文件。你可以将它用于你的项目中,并在启动过程中加载它。当然,在编译之前,你可能需要修改一些配置文件,以确保 U-Boot 适配你的具体硬件环境。 ### 回答3: 要编译 mt7621 的 u-boot 需要进行一些配置。 首先,你需要下载 u-boot 的源代码。可以从官方网站或者 GitHub 上找到 mt7621 相关的 u-boot 仓库,并下载代码至你的开发环境中。 接下来,你需要进入 u-boot 的源代码目录。使用终端命令行工具进入该目录。 在源代码目录中,你可以找到一个名为 `configs` 的文件夹,其中包含了不同平台的配置文件。你需要找到一个名为 `mt7621_bpir2_defconfig` 的文件,这是针对 mt7621 平台的默认配置文件。 如果你想进行自定义配置,可复制该文件,并在复制的文件上进行修改。你可以使用一个文本编辑器打开配置文件,找到需要修改的选项,并进行相应的修改。例如,你可以修改串口配置、内存配置、网络协议等选项,以适配你的具体需求。 完成修改后,你可以保存文件,并返回到源代码的根目录。 最后,你需要运行编译命令来生成可执行的 u-boot 映像文件。通常情况下,你可以通过运行 `make` 命令来进行编译编译过程可能会耗费一些时间,请耐心等待。 当编译完成后,你可以在源代码目录下找到生成的 u-boot 映像文件。该文件一般以 `u-boot.bin` 或者 `u-boot.img` 的形式存在。 编译完成后,你可以将生成的 u-boot 映像文件烧录到 mt7621 平台的 Flash 存储器中,以替换原有的 u-boot 程序。 总而言之,编译 mt7621 的 u-boot 需要下载源代码、进行配置修改,并通过编译命令生成 u-boot 映像文件。最后,将生成的映像文件烧录到目标平台中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值