一、 UBoot配置编译初步分析

1. UBoot源码结构

(1)UBoot工程项目中的文件可以分为3类

① 第1类目录:与处理器体系结构或开发板硬件直接相关

② 第2类目录:一些通用的函数或驱动程序

③ 第3类目录:UBoot的应用程序、工具或文档

2. UBoot的配置编译

  1. make <board_name>_config
  2. make

3. UBoot的配置编译初步分析

(1)顶层目下的Makefile:每一种开发板在顶层Makefile中都有自己的配置规则

  1. mini2440_config : unconfig
  2. @$(MKCONFIG) $(@:_config=) arm arm920t mini2440 samsung s3c24x0

(2)执行make mini2440_config命令,将通过UBoot顶层目录下的mkconfig脚本生成配置文件include/config.mk

  1. ARCH = arm
  2. CPU = arm920t
  3. BOARD = mini2440
  4. VENDOR = samsung
  5. SOC = s3c24x0

(3)而顶层目录的Makefile则包含了include/config.mk文件

  1. # load ARCH, BOARD, and CPU configuration
  2. include $(obj)include/config.mk
  3. export ARCH CPU BOARD VENDOR SOC

(4)Makefile的编译选项和规则

① 各种体系结构通用的规则直接在顶层目录的config.mk文件中,通过ARCH、CPU、BOARD、SOC等变量为不同平台定义不同选项。

② 不同体系结构的规则分别包含在各自的lib_xxx目录下的config.mk文件中

(5)开发板配置头文件:移植时为开发板定义配置选项及参数,文件名为include/configs/<board_name>.h

  1. #define CONFIG_ARM920T /* This is an ARM920T Core */
  2. #define CONFIG_S3C24X0 /* in a SAMSUNG S3C24X0 SoC */

(6)编译结果

① 根据对Makefile的分析,编译分为两步:第1步配置,如make mini2440_config;第2步编译,执行make命令

② 编译完成后可得到UBoot的各种格式的映像文件和符号表

System.map:

u-boot:

u-boot.bin:

u-boot.srec:

(7)UBoot常用工具:编译完成后在tools目录下会生成一些常用工具

① bmp_logo

② img2srec

③ envcrc

④ mkimage

⑤ gen_eth_addr

⑥ updater

二、UBoot配置编译详细分析

1. 主机构建环境配置过程:顶层Makefile

(1)定义主机系统架构:HOSTARCH:=i386

  1. HOSTARCH := $(shell uname -m | \
  2. sed -e s/i./i386/ \
  3. -e s/sun4u/sparc64/ \
  4. -e s/arm.*/arm/ \
  5. -e s/sa110/arm/ \
  6. -e s/powerpc/ppc/ \
  7. -e s/ppc64/ppc/ \
  8. -e s/macppc/ppc/)

① “sed -e s/abc/def/”:表示从标准输入中查找内容为“abc”的字符串,然后替换为def。其中“abc”中可以用“.”作为通配符

② uname -m:输出主机CPU架构类型

(2)定义主机操作系统类型:HOSTOS:=linux

  1. HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
  2. sed -e 's/\(cygwin\).*/cygwin/')

(3)定义脚本解释器:SHELL:=/bin/bash

  1. SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
  2. else if [ -x /bin/bash ]; then echo /bin/bash; \
  3. else echo sh; fi; fi)

(4)设定编译输出目录:BUILD_DIR:=./

① 执行“make O=/tmp/build”命令可以将输出目录设置为特定目录

  1. ifdef O
  2. ifeq ("$(origin O)", "command line")
  3. BUILD_DIR := $(O)
  4. endif
  5. endif

② 与UBoot源码目录和输出目录相关的变量

  1. OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
  2. SRCTREE := $(CURDIR)
  3. TOPDIR := $(SRCTREE)
  4. LNDIR := $(OBJTREE)

 

2. 目标机相关配置过程

(1)顶层Makefie中与具体开发板相关的配置规则

  1. mini2440_config : unconfig
  2. @$(MKCONFIG) $(@:_config=) arm arm920t mini2440 samsung s3c24x0

其中依赖“unconfig”的定义如下

  1. unconfig:
  2. @rm -f $(obj)include/config.h $(obj)include/config.mk \
  3. $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
  4. $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep

unconfig的作用是清除上次执行make *_config命令产生的配置文件

(2)将具体开发板相关的配置规则替换变量后

  1. ./mkconfig mini2440 arm arm920t mini2440 samsung s3c24x0

也就是以“mini2440 arm arm920t mini2440 samsung s3c24x0”为参数执行mkconfig脚本

(3)mkconfig的用法

  1. # Parameters: Target Architecture CPU Board [VENDOR] [SOC]

① 确定开发板名称:BOARD_NAME:=mini2440

  1. while [ $# -gt ] ; do
  2. case "$1" in
  3. --) shift ; break ;;
  4. -a) shift ; APPEND=yes ;;
  5. -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
  6. -t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
  7. *) break ;;
  8. esac
  9. done
  10.  
  11. [ "${BOARD_NAME}" ] || BOARD_NAME="$1"

② 检查参数合法性

  1. [ $# -lt ] && exit
  2. [ $# -gt ] && exit
  3.  
  4. if [ "${ARCH}" -a "${ARCH}" != "$2" ]; then
  5. echo "Failed: \$ARCH=${ARCH}, should be '$2' for ${BOARD_NAME}" >&
  6. exit
  7. fi

③ 创建到目标板相关目录的链接

  1. if [ "$SRCTREE" != "$OBJTREE" ] ; then
  2. mkdir -p ${OBJTREE}/include
  3. mkdir -p ${OBJTREE}/include2
  4. cd ${OBJTREE}/include2
  5. rm -f asm
  6. ln -s ${SRCTREE}/include/asm-$ asm
  7. LNPREFIX="../../include2/asm/"
  8. cd ../include
  9. rm -rf asm-$
  10. rm -f asm
  11. mkdir asm-$
  12. ln -s asm-$ asm
  13. else
  14. cd ./include
  15. rm -f asm
  16. ln -s asm-$ asm
  17. fi
  18.  
  19. rm -f asm-$2/arch
  20.  
  21. if [ -z "$6" -o "$6" = "NULL" ] ; then
        ln -s ${LNPREFIX}arch-$3 asm-$2/arch
    else
        ln -s ${LNPREFIX}arch-$6 asm-$2/arch
    fi
  22.  
  23. if [ "$2" = "arm" ] ; then
        rm -f asm-$2/proc
        ln -s ${LNPREFIX}proc-armv asm-$2/proc
    fi

④ 构建include/config.mk文件

  1. echo "ARCH = $2" > config.mk
  2. echo "CPU = $3" >> config.mk
  3. echo "BOARD = $4" >> config.mk
  4.  
  5. [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
  6.  
  7. [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk

⑤ 构建include/config.h文件

  1. if [ "$APPEND" = "yes" ] # Append to existing config file
  2. then
  3. echo >> config.h
  4. else
  5. > config.h # Create new config file
  6. fi
  7. echo "/* Automatically generated - do not edit */" >>config.h
  8.  
  9. for i in ${TARGETS} ; do
  10. echo "#define CONFIG_MK_${i} 1" >>config.h ;
  11. done
  12.  
  13. cat << EOF >> config.h
  14. #define CONFIG_BOARDDIR board/$BOARDDIR
  15. #include <config_defaults.h>
  16. #include <configs/$.h>
  17. #include <asm/config.h>
  18. EOF
  19.  
  20. exit

(4)总结"make mini2440_config"的执行结果

① 创建到目标板相关文件的链接

  1. ln -s asm-arm asm
  2. ln -s arch-s3c24x0 asm-arm/arch
  3. ln -s proc-armv asm-arm/proc

② 创建include/config.mk文件

  1. ARCH = arm
  2. CPU = arm920t
  3. BOARD = mini2440
  4. VENDOR = samsung
  5. SOC = s3c24x0

③ 创建与目标板相关的头文件include/config.h

  1. #define CONFIG_BOARDDIR board/samsung/mini2440
  2. #include <config_defaults.h>
  3. #include <configs/mini2440.h>
  4. #include <asm/config.h>

3. make命令执行过程

(1)include/autoconf.mk生成过程

主Makefile开始部分,会包含如下头文件

  1. sinclude $(obj)include/autoconf.mk.dep
  2. sinclude $(obj)include/autoconf.mk

① include/autoconf.mk文件是与开发板相关的一些宏定义,在Makefile执行过程中,需要根据某些宏来确定执行哪些操作

② include/autoconf.mk的生成规则

  1. $(obj)include/autoconf.mk: $(obj)include/config.h
        @$(XECHO) Generating $@ ; \
        set -e ; \
        : Extract the config macros ; \
        $(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \
            sed -n -f tools/scripts/define2mk.sed > $@.tmp && \
        mv $@.tmp $@

  * 根据上面的规则,编译器提取额include/common.h中定义的宏,然后输出给tools/scripts/define2mk.sed脚本处理,处理的结果是生成include/autoconf.mk文件

  * include/common.h中包含include/config,h文件,而include/config.h文件包含configs/mini2440、asm/config.h等文件

(2)config.mk执行过程:

主Makefile中接着将由make mini2440_config生成的config.mk文件包含进来

  1. # load ARCH, BOARD, and CPU configuration
  2. include $(obj)include/config.mk
  3. export ARCH CPU BOARD VENDOR SOC

① 设置obj与src

  1. ifneq ($(OBJTREE),$(SRCTREE))
  2. ifeq ($(CURDIR),$(SRCTREE))
  3. dir :=
  4. else
  5. dir := $(subst $(SRCTREE)/,,$(CURDIR))
  6. endif
  7.  
  8. obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)
  9. src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/)
  10.  
  11. $(shell mkdir -p $(obj))
  12. else
  13. obj :=
  14. src :=
  15. endif

② 设置编译选项:下面3个变量表示交叉编译选项

  1. PLATFORM_RELFLAGS =
  2. PLATFORM_CPPFLAGS =
  3. PLATFORM_LDFLAGS =

  * 变量CC和CFLAGS将会在后面的代码中定义。

  * 函数cc-option用于检查编译器CC是否支持某选项,定义如下

  1. cc-option = $(shell if $(CC) $(CFLAGS) $() -S -o /dev/null -xc /dev/null \
  2. > /dev/null >&; then echo "$(1)"; else echo "$(2)"; fi ;)

  * 函数cc-option使用示例

  1. FLAGS += $(call cc-option, option1, option2)

③ 指定交叉编译工具

  1. AS = $(CROSS_COMPILE)as
  2. LD = $(CROSS_COMPILE)ld
  3. CC = $(CROSS_COMPILE)gcc
  4. CPP = $(CC) -E
  5. AR = $(CROSS_COMPILE)ar
  6. NM = $(CROSS_COMPILE)nm
  7. LDR = $(CROSS_COMPILE)ldr
  8. STRIP = $(CROSS_COMPILE)strip
  9. OBJCOPY = $(CROSS_COMPILE)objcopy
  10. OBJDUMP = $(CROSS_COMPILE)objdump
  11. RANLIB = $(CROSS_COMPILE)RANLIB

  * 对于arm开发板,CROSS_COMPILE定义于lib_arm/config.mk文件中

  1. CROSS_COMPILE ?= arm-linux-

④ 包含与开发板相关的配置文件

  * 包含文件lib_arm/config.mk:该文件中指定了交叉编译前缀,添加了一些与CPU架构相关的编译选项,最后还指定了UBoot的连接器脚本cpu/arm920t/u-boot.lds

  1. ifdef ARCH
  2. sinclude $(TOPDIR)/lib_$(ARCH)/config.mk # include architecture dependend rules
  3. endif

  * 包含文件cpu/arm920t/config.mk

  * 包含文件cpu/arm920t/s3c24x0/config.mk

  * 包含文件board/samsung/mini2440/config.mk:TEXT_BASE定义于此文件中

⑤ 指定隐含的编译规则:

  1. # Allow boards to use custom optimize flags on a per dir/file basis
  2. BCURDIR := $(notdir $(CURDIR))
  3. $(obj)%.s: %.S
  4. $(CPP) $(AFLAGS) $(AFLAGS_$(@F)) $(AFLAGS_$(BCURDIR)) -o $@ $<
  5. $(obj)%.o: %.S
  6. $(CC) $(AFLAGS) $(AFLAGS_$(@F)) $(AFLAGS_$(BCURDIR)) -o $@ $< -c
  7. $(obj)%.o: %.c
  8. $(CC) $(CFLAGS) $(CFLAGS_$(@F)) $(CFLAGS_$(BCURDIR)) -o $@ $< -c
  9. $(obj)%.i: %.c
  10. $(CPP) $(CFLAGS) $(CFLAGS_$(@F)) $(CFLAGS_$(BCURDIR)) -o $@ $< -c
  11. $(obj)%.s: %.c
  12. $(CC) $(CFLAGS) $(CFLAGS_$(@F)) $(CFLAGS_$(BCURDIR)) -o $@ $< -c -S

4. UBoot镜像生成过程

(1)顶层Makefile定义了LIBS变量,用以指明UBoot需要的库文件

  1. LIBS = lib_generic/libgeneric.a
  2. LIBS += lib_generic/lzma/liblzma.a
  3. LIBS += lib_generic/lzo/liblzo.a

(2)下面的代码定义了Makefile第一个目标all的依赖

  1. # Always append ALL so that arch config.mk's can add custom ones
  2. ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)
  3.  
  4. all: $(ALL)
  5.  
  6. $(obj)u-boot.hex: $(obj)u-boot
  7. $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
  8.  
  9. $(obj)u-boot.srec: $(obj)u-boot
  10. $(OBJCOPY) -O srec $< $@
  11.  
  12. $(obj)u-boot.bin: $(obj)u-boot
  13. $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@

(3)uboot文件的生成规则

  1. $(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
  2. $(GEN_UBOOT)
  3. ifeq ($(CONFIG_KALLSYMS),y)
  4. smap=`$(call SYSTEM_MAP,u-boot) | \
  5. awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\\\000"}'` ; \
  6. $(CC) $(CFLAGS) -DSYSTEM_MAP="\"$${smap}\"" \
  7. -c common/system_map.c -o $(obj)common/system_map.o
  8. $(GEN_UBOOT) $(obj)common/system_map.o
  9. endif

① depend 依赖:

② (SUBDIRS)依赖:

③ (OBJS)依赖

④ (LIBBOARD)依赖

⑤ (LIBS)依赖

⑥ (LDSCRIPT)依赖

⑦ (obj)u-boot.lds依赖

(4)编译生成u-boot镜像的命令GEN_UBOOT

  1. GEN_UBOOT = \
  2. UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
  3. sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
  4. cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
  5. --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  6. -Map u-boot.map -o u-boot

① 第一部分:

  1. UNDEF_SYM=`arm-linux-objdump -x board/samsung/mini2440/libmini2449.a... | \
  2. sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

替换相应变量后

  1. UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
  2. sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

将编译u-boot所生成的库中包含__u_boot_cmd_的所有标号,替换为-u__u_boot_cmd_形式的标号,排序(sort),并保证唯一(uniq),然后将所有这样的标号组成的字符串赋值给UNDEF_SYM

②第二部分:

  1. cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
  2. --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  3. -Map u-boot.map -o u-boot

替换相应变量后

  1. cd $(OBJTREE) && arm-linux-ld -Bstatic -T u-boot.lds -Ttext 0x33F80000 $UNDEF_SYM
  2.   cpu/arm920t/start.o --start-group lib_generic/libgeneric.a ... board/samsung/
  3.   mini2440/libmini2440.a --end-group ... -Map u-boot.map -o u-boot

(5)从ELF文件u-boot中提取二进制文件u-boot.bin

  1. $(obj)u-boot.bin: $(obj)u-boot
  2. $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@

替换变量后

  1. $(obj)u-boot.bin: $(obj)u-boot
  2. arm-linux-objcopy --gap-fill=0xff -O binary u-boot uboot.bin

后记:以上分析基于uboot2010.03版本,后续版本中的Makefile组织可能会略有不同

UBoot配置编译及Makefile分析的更多相关文章

  1. (九)uboot配置编译、源码分析

    一.X210官方uboot配置编译实践1.找到官方移植好的uboot(BSP概念)(1)源头的源代码是uboot官网下载的.这个下载的源代码可能没有你当前使用的开发板的移植,甚至找不到当前开发板使用的 ...

  2. uboot主Makefile分析(t配置和编译过程详解)

    1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_c ...

  3. Linux内核配置、编译及Makefile简述

    Hi,大家好!我是CrazyCatJack.最近在学习Linux内核的配置.编译及Makefile文件.今天总结一下学习成果,分享给大家^_^ 1.解压缩打补丁 首先是解压缩你获取到的Linux内核. ...

  4. 嵌入式Linux驱动学习之路(三)u-boot配置分析

    u-boot配置流程分析 执行make tiny4412_config后,将会对u-boot进行一些列的配置,以便于后面的编译. 打开顶层目录下的Makefile,查找对于的规则tiny4412_co ...

  5. U-Boot Makefile分析(5)主控Makefile分析

    这次分析源码根目录下的Makefile,它负责读入配置过的信息,通过OBJS.LIBS等变量设置能够参与镜像链接的目标文件,设定编译的目标等等. HOSTARCH := $(shell uname - ...

  6. uboot主Makefile分析

    VERSION = 1 PATCHLEVEL = 3 SUBLEVEL = 4 EXTRAVERSION = U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(S ...

  7. u-boot剖析(一)----Makefile分析

    由于u-boot比较庞大,所以我们分开来分析,对于一个大型的项目我们想快速的了解其代码架构和内容,最方便的方法就是分析Makefile,所以我们今天以三星的s3c2440来分析Makefile.我们今 ...

  8. TQ210 —— S5PV210 uboot顶层Makefile分析

    转自:http://blog.csdn.net/wqx521/article/details/52469759 # (C) Copyright 2000-2008 # Wolfgang Denk, D ...

  9. uboot配置和编译过程详解【转】

    本文转载自:http://blog.csdn.net/czg13548930186/article/details/53434566 uboot主Makefile分析1 1.uboot version ...

随机推荐

  1. React:Composition

    在日常的UI构建中,经常会遇到一种情况:组件本身更多是作为一个容器,它所包含的内容可能是动态的.未预先定义的.这时候它的内容取决另一个组件或外部的输入.比如弹层. props.children: Re ...

  2. React知识点整理

    面试题:三大框架中数据绑定实现上有何绑定? 一.概述:是Facebook维护的一个构建用户界面的JS库,核心很精简,但是生态圈扩展很大. React:MVVM框架 React-Router:路由 Re ...

  3. 2.5 Hello golang

    编写第一个hello golang 创建空文件hello.go,尝试执行 touch hello.go go run hello.go 产生如下报错 can't load package: packa ...

  4. DPDK Hash Library原理(学习笔记)

    0 前言 本文主要翻译至DPDK的官方编程指南,在谷歌翻译的基础上根据自己的理解做了一些修改.网上搜索的很多中文翻译大多是翻译后直接黏贴上来,有时候连语句都读不通.希望本文能够对你有所帮助. 1 介绍 ...

  5. Java Web之路一:过滤器(Filter)

    一.过滤器(Filter)简介 过滤器是对web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,主要可以拦截request和response 过滤器是以一种组件的形式与web程序绑定 ...

  6. 同一父进程下的子进程之间的通信(pipe通信)

    首先对于fork命令  通过fork命令创建进程 父进程返回子进程id 子进程返回0 失败返回-1 对于pipe通讯机制   pipe通讯是半双工的 也就是说只能一方读一方写 题目中想要P1的输出作为 ...

  7. 【JAVA习题三】求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加

    import java.util.Scanner; public class a加aa加aaa { public static void main(String[] args) { // TODO A ...

  8. 基于 abp vNext 和 .NET Core 开发博客项目 - 用AutoMapper搞定对象映射

    上一篇文章(https://www.cnblogs.com/meowv/p/12961014.html)集成了定时任务处理框架Hangfire,完成了一个简单的定时任务处理解决方案. 本篇紧接着来玩一 ...

  9. CF1353D Constructing the Array(优先队列)

    Question 给你一个长度为n的全为0的序列,让你从1-n填数,填的位置为找出最长的0序列,如序列长度为奇数,则为(l+r)/2,为偶数,则为(l+r-1)/2 Solution 运用优先队列,将 ...

  10. 前端星计划笔记-day1

    前端 功能,美观,安全,无障碍,性能,兼容,体验 前端编程思想 WA doctype: 文档版本 浏览器决定渲染模式 语义化: 所有的标签都有自己的含义,属性 可读性 前端规范 whatwg css显 ...