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}fi
mkconfig一开始就是在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/procfi
2》创建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)endif
Makefile一开始就定义了版本号,这里使用的是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-boot
u-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 $< $@


总体流程:OBJS、LIBS等依赖文件====》u-boot ELF文件=====》u-boot.bin=====》u-boot.imx

总结:

概括起来,工程的编译流程也就是通过执行执行一个make *_config传入ARCH,CPU,BOARD,SOC参数,mkconfig根据参数将include头文件夹相应的头文件夹连接好,生成config.h。然后执行make分别调用各子目录的makefile 生成所有的obj文件和obj库文件*.a.  最后连接所有目标文件,生成镜像。不同格式的镜像都是调用相应工具由elf镜像直接或者间接生成的。












0 0