uboot 的主Makefile分析

    科技2025-11-03  8

    1. uboot版本号设置

    VERSION = 1 PATCHLEVEL = 3 SUBLEVEL = 4 EXTRAVERSION = U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) VERSION_FILE = $(obj)include/version_autogenerated.h

    设置uboot的版本号,version_autogenerated.h在编译后自动生成,里面的内容为 #define U_BOOT_VERSION "U-Boot 1.3.4",以宏定义的方式定义uboot的版本号。

    2. 导出编译主机的CPU架构和操作系统

    HOSTARCH := $(shell uname -m | \ sed -e s/i.86/i386/ \ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ \ -e s/sa110/arm/ \ -e s/powerpc/ppc/ \ -e s/ppc64/ppc/ \ -e s/macppc/ppc/) HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ sed -e 's/\(cygwin\).*/cygwin/') export HOSTARCH HOSTOS

    (1) 在shell中符号|叫做管道,把管道前的运算式的输出作为后面一个运算式的输入,sed可以实现字符替换;

    (2)tr '[:upper:]' '[:lower:]'是将大写字符替换为小写字符;

    (3)export    HOSTARCH HOSTOS是导出环境变量,分别是主机系统架构和主机操作系统,后面会用到。

    3.静默编译

    # Allow for silent builds ifeq (,$(findstring s,$(MAKEFLAGS))) XECHO = echo else XECHO = : endif

    编译时使用 make -s, 使用 ifeq (,$(findstring s,$(MAKEFLAGS))) 来判断是否有属性s,如果有,则XECHO为空,不打印编译信息。

    4. 实现两种编译方式,原地编译和设置输出目录编译

    ifdef O ifeq ("$(origin O)", "command line") BUILD_DIR := $(O) endif endif ifneq ($(BUILD_DIR),) saved-output := $(BUILD_DIR) # 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) $(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist)) endif # ifneq ($(BUILD_DIR),) OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) SRCTREE := $(CURDIR) TOPDIR := $(SRCTREE) LNDIR := $(OBJTREE) export TOPDIR SRCTREE OBJTREE

     配置输出目录,可以防止污染源代码。

    OBJTREE   :编译输出的.o文件存放的目录的根目录

    SRCTREE   :源码目录,也就是当前目录

    TOPDIR       :顶层目录,也就是源码目录

    5.配置脚本

    导入配置脚本

    MKCONFIG := $(SRCTREE)/mkconfig export MKCONFIG

    在12部分对配置过程进行介绍

    6.导入 ARCH, BOARD, and CPU 的配置

    include $(obj)include/config.mk export ARCH CPU BOARD VENDOR SOC

     这个文件是在配置之后生成的,主要是对使用板子的架构、CPU型号、板子型号、厂家、SOC进行配置,是通过 make xx_config实现的,是在5中的配置脚本中进行配置的,生成文件的格式如下:

    ARCH = arm CPU = s5pc11x BOARD = x210 VENDOR = samsung SOC = s5pc110

    最后将这5个变量作为环境变量并进行导出。

    7.确定交叉编译工具链的前缀

    ifeq ($(ARCH),arm) CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- endif

    是根据6中的ARCH进行配置的,不同的ARCH对应的编译工具链是不同的,之所以对交叉编译工具链的前缀进行设置,是因为不同CPU架构的交叉编译链的后缀是相同的,只需要对前缀进行配置即可,要根据自己交叉编译工具链的配置路径或者是否设置符号链接来设置自己的CROSS_COMPILE。

    8.在config.mk文件中导入了其他的配置

    include $(TOPDIR)/config.mk

    (1)config.mk中定义了编译工具,这些才是编译中最终使用的交叉编译工具

    # # Include the make variables (CC, etc...) # AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm LDR = $(CROSS_COMPILE)ldr STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump RANLIB = $(CROSS_COMPILE)RANLIB

     (2)导入了开发板的配置项目

    sinclude $(OBJTREE)/include/autoconf.mk

    autoconf.mk是在配置过程中生成的,这个文件中包含很多CONFIG_开头的宏,用来指导uboot的编译过程(条件编译),主要用来实现可移植性的。这个文件是通过源码目录的include/configs/xx.h产生的,这个也是移植uboot的关键所在。

    (3)导入CPU ARCH BOARD SOC等的专有配置

    # Load generated board configuration sinclude $(OBJTREE)/include/autoconf.mk ifdef ARCH sinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rules endif ifdef CPU sinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include CPU specific rules endif ifdef SOC sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk # include SoC specific rules endif ifdef VENDOR BOARDDIR = $(VENDOR)/$(BOARD) else BOARDDIR = $(BOARD) endif ifdef BOARD sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules endif

     (4)设置链接脚本

    ifndef LDSCRIPT #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug ifeq ($(CONFIG_NAND_U_BOOT),y) LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds else LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds endif endif

    在board文件夹下有各种版本的链接脚本,在uboo编译链接时需要考虑这个链接脚本。

    (5)TEXT_BASE:链接地址

    ifneq ($(TEXT_BASE),) CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) endif

     TEXT_BASE的值是在Makefile中进行设置的

    @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

     TEXT_BASE是将来uboot链接时指定的链接地址,因为uboot启用了虚拟地址映射,0xc3e00000的地址就是0x23e00000

    ifneq ($(TEXT_BASE),) LDFLAGS += -Ttext $(TEXT_BASE) endif

    在此处设置了链接地址-Ttext。

    %.s: %.S $(CPP) $(AFLAGS) -o $@ $< %.o: %.S $(CC) $(AFLAGS) -c -o $@ $< %.o: %.c $(CC) $(CFLAGS) -c -o $@ $<

    Makefile的自动推导规则

    9. 加载.o和.a的目标文件

    10. uboot最终编译链接生成了.elf格式的可执行文件,通过工具可以加工成烧录的.bin文件和反汇编文件。

    11.unconfig:

    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 \ $(obj)board/$(VENDOR)/$(BOARD)/config.mk x210_sd_config : unconfig @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110 @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

     unconfig的作用主要是 配置过之后还可以在进行配置,x210_sd_config依赖于unconfig。

    12.配置过程详解

    x210_sd_config : unconfig @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110 @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

    调用了MKCONFIG脚本并传递了6个参数

    $(@是目标,代表 x210_sd_config

    :代表进行加工,将=前放入_config用空替换,得到x210_sd,所以第一个参数就是x210_sd,后面的参数显而易见。

    即$1=x210_sd $2=arm $3=s5pc11x $4 = x210 $5=samsung $6=s5pc110 $#=6

    13.mkconfig文件分析

    while [ $# -gt 0 ] ; do case "$1" in --) shift ; break ;; -a) shift ; APPEND=yes ;; -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;; *) break ;; esac done

     因为$#为6,$1为x210_sd 跟while中的case值没有匹配,相当于没有进行操作。

     

    [ "${BOARD_NAME}" ] || BOARD_NAME="$1"

     看BOARD_NAME是否为空,如果为空则赋值为$1。

     

    [ $# -lt 4 ] && exit 1 [ $# -gt 6 ] && exit 1

    $# 小于4 或者大于6的时候就返货,所以传参个数必须是4/5/6三种情况。

     

    后面创建了一些列的符号链接,这些符号链接文件主要是给头文件包含提供一些指向性的连接,让uboot具有可移植性。实现原理就是通过配置参数选择不同架构、cpu、开发板,通过符号链接的方式提供一个具体的名字工文件编译时使用。

    cd ./include rm -f asm ln -s asm-$2 asm

    第一个:在include目录下创建asm文件指向asm-arm。

    ln -s ${LNPREFIX}arch-$6 asm-$2/arch

    第二个:在include/asm-arm下创建一个arch文件指向include/asm-arm/arch-s5pc110文件。

    # create link for s5pc11x SoC if [ "$3" = "s5pc11x" ] ; then rm -f regs.h ln -s $6.h regs.h rm -f asm-$2/arch ln -s arch-$3 asm-$2/arch fi

     第三个:include目录下创建一个reg.h文件指向include/s5pc110.h,删除第二个符号链接,在include/asm-arm下创建一个arch文件指向include/asm-arm/arch-s5pc11x文件,其他的类似。

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

    将配置值写入config.mk文件,该文件在6中提到的地方引入主Makefile。

     

    # # 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 echo "#include <configs/$1.h>" >>config.h

    包含配置头文件

    x210_sd.h文件被用来生成一个autoconfig.mk文件,这个文件会被主Makefile文件引入,来指导uboot的编译过程,这些宏定义会影响对大部分C文件的编译选择,从而实现uboot的可移植性。

    14.链接脚本

    ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { cpu/s5pc11x/start.o (.text) cpu/s5pc11x/s5pc110/cpu_init.o (.text) board/samsung/x210/lowlevel_init.o (.text) cpu/s5pc11x/onenand_cp.o (.text) cpu/s5pc11x/nand_cp.o (.text) cpu/s5pc11x/movi.o (.text) common/secure_boot.o (.text) common/ace_sha1.o (.text) cpu/s5pc11x/pmic.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .got : { *(.got) } __u_boot_cmd_start = .; .u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .; . = ALIGN(4); .mmudata : { *(.mmudata) } . = ALIGN(4); __bss_start = .; .bss : { *(.bss) } _end = .; }

    ENTRY(_start):程序的入口地址,整个程序的第一句指令

    在链接脚本的SECTIONS开头用. = 0x00000000;来指定链接的起始地址,但是Makefile中的-Ttext也可以指定链接地址,并且可以覆盖链接脚本中的地址。

    在代码段中必须注意文件的排列顺序,这是因为uboot有两部分,BL1中的初始化DDR iNand 重定位等的读取BL2部分等的文件要先被编译。

     

     

    Processed: 0.016, SQL: 8