i.MX6DL学习记录---uboot之Makefile分析
来源:互联网 发布:枭龙战斗机知乎 编辑:程序博客网 时间:2024/06/06 09:47
软件版本:uboot-2013-04
硬件版本:i.MX6DL-Sabreasd
uboot使用的是Makefile来生成uboot镜像的,分析Makefile可以更加清晰的了解uboot的生成过程和源码结构。
uboot在执行make命令之前,执行make mx6dlsabresd_config进行配置,在uboot根目录的Makefile中搜索,可以找到configuration的make目标
unconfig: @rm -f $(obj)include/config.h $(obj)include/config.mk \ $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \ $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep#在执行xxx_config之前得进行unconfig来删除上次编译所生成的文件%_config:: unconfig @$(MKCONFIG) -A $(@:_config=)unconfig之后执行
@$(MKCONFIG) -A $(@:_config=),$(@:_config=)的意义就是把mx6dlsabresd_config中的_config用空替代,跟踪MKCONFIG可以在uboot根目录的Makefile中找到其定义
# Attempt to create a output directory.$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})# Verify if it was successful.BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) #只没有指定编译输出目录时,默认的就是pwd的当前目录即uboot的根目录$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))endif # ifneq ($(BUILD_DIR),)OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))SPLTREE := $(OBJTREE)/splSRCTREE := $(CURDIR)TOPDIR := $(SRCTREE)LNDIR := $(OBJTREE)export TOPDIR SRCTREE OBJTREE SPLTREEMKCONFIG := $(SRCTREE)/mkconfig #<span style="font-family:Arial, Helvetica, sans-serif;">SRCTREE即uboot的根目录</span>export MKCONFIG
所以@$(MKCONFIG) -A $(@:_config=)展开就是./mkconfig -A mx6dlsabresd
既然执行了./mkconfig,这个文件还是挺重要的,所以这里还是得认真分析下
if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then #参数判断 # Automatic mode line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg` || { echo "make: *** No rule to make target \`$2_config'. Stop." >&2 exit 1 } set ${line} # add default board name if needed [ $# = 3 ] && set ${line} ${1}fimkconfig一开始就是在boards.cfg文件中去匹配含有mx6dlsabresd并把这一行字符串赋值给line这个变量,boards.cfg是在uboot根目录下的一个board配置文件,其中包含了board的ARCH、CPU、Board name 、Vendor、SoC、Options等属性
mkconfig其实非常简单,就做了下面三件事,创建文件都是包含在uboot根目录的include中
1》创建arch的链接
if [ "$SRCTREE" != "$OBJTREE" ] ; then ... ...else cd ./include rm -f asm ln -s ../arch/${arch}/include/asm asmfirm -f asm/archif [ -z "${soc}" ] ; then ln -s ${LNPREFIX}arch-${cpu} asm/archelse ln -s ${LNPREFIX}arch-${soc} asm/archfiif [ "${arch}" = "arm" ] ; then rm -f asm/proc ln -s ${LNPREFIX}proc-armv asm/procfi2》创建make编译所需文件include/config.mk
( 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 ) > <span style="color:#cc0000;">config.mk</span>3》创建board属性头文件include/config.h
if [ "$APPEND" = "yes" ] # Append to existing config filethen echo >> config.helse > config.h # Create new config filefiecho "/* Automatically generated - do not edit */" >>config.hfor i in ${TARGETS} ; do i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`" echo "#define CONFIG_${i}" >>config.h ;doneecho "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.hecho "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.hecho "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h[ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h[ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.hcat << EOF >> config.h#define CONFIG_BOARDDIR board/$BOARDDIR#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完成上列三件工作后mkconfig执行结束,make mx6dlsabresd_config配置工作完成!!
===============================================================================================================================
在配置完成后执行make命令就可以生成uboot.imx镜像文件了,单独执行make命令,由于没有像make xxx_config指定目标,所以Makefile得从最开始分析了
VERSION = 2013PATCHLEVEL = 04SUBLEVEL =EXTRAVERSION =ifneq "$(SUBLEVEL)" ""U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)elseU_BOOT_VERSION = $(VERSION).$(PATCHLEVEL)$(EXTRAVERSION)endifMakefile一开始就定义了版本号,这里使用的是U-Boot 2013-04版,U_BOOT_VERSION会在uboot在执行时通过串口打印出来的
ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk)) #判断uboot是否已经进行配置生成了config.mkall:sinclude $(obj)include/autoconf.mk.depsinclude $(obj)include/autoconf.mkifndef CONFIG_SANDBOXSUBDIRS += $(SUBDIR_EXAMPLES)endif# 添加 ARCH, BOARD, and CPU configuration属性include $(obj)include/config.mk export ARCH CPU BOARD VENDOR SOC# set default to nothing for native buildsifeq ($(HOSTARCH),$(ARCH))CROSS_COMPILE ?=endif# load other configurationinclude $(TOPDIR)/config.mk其中添加了$(TOPDIR)/config.mk文件,这个文件指定了uboot的编译工具已经添加了各个目录下的config.mk文件以达到编译整个uboot,这里就不去详细分析了
继续Makefile往下分析,执行到了这里就出现了一个很重要的点,那就是指定链接脚本
ifndef LDSCRIPT #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug ifdef CONFIG_SYS_LDSCRIPT # need to strip off double quotes LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT)) endifendif# If there is no specified link script, we look in a number of places for itifndef LDSCRIPT ... ...<span style="color:#cc0000;"> ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds # We don't expect a Makefile here LDSCRIPT_MAKEFILE_DIR = endif</span> ifeq ($(wildcard $(LDSCRIPT)),)$(error could not find linker script) endifendif这里指定的链接脚本是arch/arm/cpu/u-boot.lds,链接脚本决定了镜像文件的组织结构,例如数据段,程序段,bss段同时该文件也指定了uboot程序的入口,在分析uboot启动时就是从这个文件着手的,有时间再另外做详细分析
到这里所有的准备工作就做完了,指定了编译目录,添加了各个目录的编译文件,指定了编译工具和镜像文件的链接脚本,接下来就要开始make真正的工作了----生成uboot镜像
OBJS = $(CPUDIR)/start.o #<span style="color:#cc0000;">#这里一个非常重要的点!!!一定要将<span style="font-family: Arial, Helvetica, sans-serif;">$(CPUDIR)/start.o这个文件放在目标文件的首位!!!</span></span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="color:#cc0000;">#</span>#</span>OBJS := $(addprefix $(obj),$(OBJS))HAVE_VENDOR_COMMON_LIB = $(if $(wildcard board/$(VENDOR)/common/Makefile),y,n)LIBS-y += lib/libgeneric.oLIBS-y += lib/lzma/liblzma.oLIBS-y += lib/lzo/liblzo.o...... #中间省略了很多库文件的添加,有兴趣可以去逐行查看源码LDPPFLAGS += \ -include $(TOPDIR)/include/u-boot/u-boot.lds.h \ -DCPUDIR=$(CPUDIR) \ $(shell $(LD) --version | \ sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')__OBJS := $(subst $(obj),,$(OBJS))__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
库文件也添加了,接下就是编译需要生成的uboot镜像了,这里反正顺序来,首先贴出终极目标u-boot.imx
$(obj)u-boot.img: $(obj)u-boot.bin $(obj)tools/mkimage -A $(ARCH) -T firmware -C none \ -O u-boot -a $(CONFIG_SYS_TEXT_BASE) \ -e $(CONFIG_SYS_UBOOT_START) \ -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \ sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \ -d $< $@从上面看出u-boot.imx是依赖于u-boot.bin的,然后使用mkimage工具生成的
all: $(ALL-y) $(SUBDIR_EXAMPLES)$(obj)<span style="color:#cc0000;">u-boot.bin:</span> $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ $(BOARD_SIZE_CHECK)u-boot.bin又是依赖于u-boot这个ELF文件
$(obj)u-boot: depend \ $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds $(GEN_UBOOT)ifeq ($(CONFIG_KALLSYMS),y) smap=`$(call SYSTEM_MAP,$(obj)u-boot) | \ awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\\\000"}'` ; \ $(CC) $(CFLAGS) -DSYSTEM_MAP="\"$${smap}\"" \ -c common/system_map.c -o $(obj)common/system_map.o $(GEN_UBOOT) $(obj)common/system_map.oendif$(OBJS): depend $(MAKE) -C $(CPUDIR) $(if $(REMOTE_BUILD),$@,$(notdir $@))$(LIBS): depend $(SUBDIR_TOOLS) $(MAKE) -C $(dir $(subst $(obj),,$@))$(LIBBOARD): depend $(LIBS) $(MAKE) -C $(dir $(subst $(obj),,$@))$(SUBDIRS): depend $(MAKE) -C $@ all$(SUBDIR_EXAMPLES): $(obj)u-boot$(LDSCRIPT): depend $(MAKE) -C $(dir $@) $(notdir $@)$(obj)u-boot.lds: $(LDSCRIPT) $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$< >$@@依赖目标depend :生成各个子目录的.depend文件,.depend列出每个目标文件的依赖文件。生成方法,调用每个子目录的make _depend
depend dep: $(TIMESTAMP_FILE) $(VERSION_FILE) \ $(obj)include/autoconf.mk \ $(obj)include/generated/generic-asm-offsets.h \ $(obj)include/generated/asm-offsets.h for dir in $(SUBDIRS) $(CPUDIR) $(LDSCRIPT_MAKEFILE_DIR) ; do \ $(MAKE) -C $$dir _depend ; doneTAG_SUBDIRS = $(SUBDIRS)TAG_SUBDIRS += $(dir $(__LIBS))TAG_SUBDIRS += include$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds等依赖目标都是前面所产生或添加的
@链接命令GEN_UBOOT:
GEN_UBOOT = \ cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \ $(__OBJS) \ --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ -Map u-boot.map -o u-boot其实就是把start.o和各个子目录makefile生成的库文件按照LDFLAGS连接在一起,生成ELF文件u-boot 和连接时内存分配图文件u-boot.map
整理一下:
ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
all: $(ALL-y) $(SUBDIR_EXAMPLES)all:是Makefile中第一个目标,也就是在make xxx_config后直接执行make,实际上执行的是all这个目标,后面的依赖文件就包括了u-boot.bin,所以会跳到u-boot.bin这个目标继续编译
$(obj)u-boot.bin: $(obj)u-bootu-boot.bin的依赖文件u-boot ELF目标
$(obj)u-boot: depend \ $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds $(GEN_UBOOT)其中OBJS、LIBS等依赖是之前编译生成添加的
最后在all之后会生成各种类型的镜像文件,其中包括u-boot.imx
$(obj)u-boot.img: $(obj)u-boot.bin $(obj)tools/mkimage -A $(ARCH) -T firmware -C none \ -O u-boot -a $(CONFIG_SYS_TEXT_BASE) \ -e $(CONFIG_SYS_UBOOT_START) \ -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \ sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \ -d $< $@
总结:
概括起来,工程的编译流程也就是通过执行执行一个make *_config传入ARCH,CPU,BOARD,SOC参数,mkconfig根据参数将include头文件夹相应的头文件夹连接好,生成config.h。然后执行make分别调用各子目录的makefile 生成所有的obj文件和obj库文件*.a. 最后连接所有目标文件,生成镜像。不同格式的镜像都是调用相应工具由elf镜像直接或者间接生成的。
- i.MX6DL学习记录---uboot之Makefile分析
- i.MX6DL学习记录---uboot移植
- i.MX6DL学习记录---uboot移植
- i.MX6DL学习记录---kernel移植
- i.MX6DL uboot 中 i2c4 总线配置
- uboot 学习 Makefile分析
- Uboot 之Makefile 分析
- uboot之Makefile分析
- Uboot 之Makefile 分析
- uboot之Makefile分析
- uboot之Makefile分析
- Uboot 之Makefile 分析
- Uboot 之Makefile 分析
- uboot分析之Makefile
- uboot之makefile分析
- uboot之makefile学习
- uboot之makefile学习
- uboot之Makefile学习
- JavaScript常用方法函数收集(未测试)
- 未来人类T5-散热改造final版
- 用Understand阅读 VS2010项目源码!
- 基于FTP4J组件的FTP操作客户端(未测试)
- 将System.out输出在控制台的信息保存在文件中(未测试)
- i.MX6DL学习记录---uboot之Makefile分析
- 数据结构实验之数组三:快速转置
- Code Forces 55 D. Beautiful numbers(数位DP)
- HttpClient(Post和Get)
- Hive入门--4.flume-数据收集工具
- java 检测 Java 是否运行在64bit 的JVM上(未测试)
- Net操作Excel(终极方法NPOI)
- java 使用java执行命令简易封装类(未测试)
- sharepoint 2016 学习系列篇(20)-文档库应用篇-(2)在文档库中创建文件夹