uboot:主Makefile分析

发布于:2024-09-19 ⋅ 阅读:(194) ⋅ 点赞:(0)
#
# (C) Copyright 2000-2008
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# See file CREDITS for list of people who contributed to this
# project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundatio; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#

(C) 版权所有 2000-2008
Wolfgang Denk,DENX 软件工程,wd@denx.de。
请查看 CREDITS 文件,了解为本项目做出贡献的人员列表。
本程序是自由软件;您可以根据自由软件基金会发布的 GNU 通用公共许可证(GPL)条款,
重新分发和/或修改它;可以是许可证的第2版,也可以是(根据您的选择)任何后续版本。
本程序分发时希望在它有用,但不提供任何担保;
甚至不暗示有关商品适用性或特定用途适合性的担保。请参阅
GNU 通用公共许可证了解更多详情。
您应该已经收到了随本程序附带的 GNU 通用公共许可证副本;
如果没有,请写信给:
自由软件基金会,
59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA

uboot version

VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h
- VERSION = 1:定义了U-Boot的主版本号。在这个例子中,主版本号是1- PATCHLEVEL = 3:定义了U-Boot的补丁级别(或次版本号)。在这个例子中,补丁级别是3- SUBLEVEL = 4:定义了U-Boot的子级别(或修订号)。在这个例子中,子级别是4- EXTRAVERSION =:定义了一个额外的版本号,但在这个例子中它被留空了,意味着没有额外的版本号。

版本字符串组合

- U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION):这行代码通过组合上述定义的版本号来创建一个完整的U-Boot版本字符串。在这个例子中,版本字符串将是1.3.4(因为EXTRAVERSION为空)。

版本文件生成

  • VERSION_FILE = ( o b j ) i n c l u d e / v e r s i o n a u t o g e n e r a t e d . h :这行代码定义了一个变量 V E R S I O N F I L E ,它指定了版本信息将被写入哪个文件。这里,它指向 (obj)include/version_autogenerated.h:这行代码定义了一个变量VERSION_FILE,它指定了版本信息将被写入哪个文件。这里,它指向 (obj)include/versionautogenerated.h:这行代码定义了一个变量VERSIONFILE,它指定了版本信息将被写入哪个文件。这里,它指向(obj)include/version_autogenerated.h,其中$(obj)是一个通常在Makefile中定义的变量,表示U-Boot源代码树的某个构建输出目录(如objtree或srctree的某个子目录)。这意味着版本信息将被写入到构建输出目录的include子目录下名为version_autogenerated.h的文件中。编译过后的目录当中才会有这个文件,内容是编译过后的版本号

HOSTARCH和HOSTOS

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

HOSTARCH

变量用于存储主机架构的标识符。它通过执行一系列命令来设置:
1.uname -m
:这个命令用于打印出主机的硬件名称,比如 x86_64、i686、arm64 等。
2.sed -e
:sed 是一个流编辑器,用于对文本进行过滤和转换。这里使用 -e 选项来指定一系列的编辑命令,每个命令都用于将 uname -m 的输出转换为更通用的架构名称。

  • s/i.86/i386/:将任何以 i 开头,后跟任意字符和 86 结尾的字符串替换为 i386。这主要是为了将 i686、ix86 等类似的架构名称统一为 i386。
  • s/sun4u/sparc64/:将 sun4u 替换为 sparc64。sun4u 是 Sun Microsystems 的 UltraSPARC 架构的旧名称。
  • s/arm.*/arm/:将任何以 arm 开头的字符串替换为 arm。这忽略了具体的 ARM 架构变种(如 armv7l、armv8l 等),只保留 arm。
  • s/sa110/arm/:将 sa110 替换为 arm。sa110 是 ARM 架构的一个旧处理器系列。
  • s/powerpc/ppc/ 和 s/ppc64/ppc/:将 powerpc 和 ppc64 替换为 ppc。这主要是为了简化架构名称,因为 PowerPC 架构在大多数上下文中都可以简单地称为 ppc。
  • s/macppc/ppc/:将 macppc 替换为 ppc。macppc 是指基于 PowerPC 架构的 Mac 计算机。
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/x86_64/64/ \
        -e s/macppc/ppc/)
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
        sed -e 's/\(cygwin\).*/cygwin/')
all:
    @echo $(HOSTARCH)
    echo $(HOSTOS)

HOSTOS

HOSTOS 变量用于存储主机操作系统的标识符。
1.uname -s
:这个命令用于打印出主机的操作系统名称,比如 Linux、Darwin(macOS 的内核名称)、Cygwin 等。
2.tr ‘[:upper:]’ ‘[:lower:]’
:tr 是一个用于删除或转换字符的命令。这里,它用于将 uname -s 的输出中的所有大写字母转换为小写字母。这是为了确保操作系统名称的一致性,因为不同的系统可能会以不同的方式返回其名称(大写、小写或混合大小写)。
3.sed -e ‘s/(cygwin).*/cygwin/’
:这个 sed 命令实际上可能有些多余,因为前面的 tr 命令已经将所有字符转换为小写,并且如果 uname -s 返回 Cygwin,它已经是小写的了。不过,这个命令的意图可能是确保如果 uname -s 返回的是以 cygwin 开头的任何字符串(尽管这在实践中不太可能),它都会被简化为 cygwin。然而,由于前面的 tr 命令,这个 sed 命令实际上不会改变任何内容,除非 uname -s 的输出在某种情况下包含了额外的字符(这在实际中很少见)。

在这里插入图片描述

竖线 | 表示的是管道

shell中的|叫做管道,管道的作用就是把管道前面一个运算式的输出作为后面一个的输入再去做处理,最终的输出才是我们整个式子的输出。
想查看当前目录下所有文件的列表,并且只对这些列表中的.txt文件进行计数。可以使用ls命令列出文件,然后使用grep命令筛选出.txt文件,最后使用wc -l命令计算行数(即.txt文件的数量)。

ls | grep '\.txt$' | wc -l
  • ls 命令列出当前目录下的所有文件和文件夹。
  • grep '.txtKaTeX parse error: Undefined control sequence: \进 at position 66: …表达式中有特殊含义,所以需要用\̲进̲行转义),表示行的末尾,确保匹配的是文件名而不是文件名中的一部分。
  • wc -l 命令计算传递给它的行数,即.txt文件的数量。

静默编译

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

1.ifeq (, ( f i n d s t r i n g s , (findstring s, (findstrings,(MAKEFLAGS))):

  • 这是一个条件判断语句,用于检查MAKEFLAGS变量中是否包含字符串s。
  • MAKEFLAGS是一个环境变量,它包含了传递给make程序的命令行选项。当make被递归调用时,这些选项也会被传递下去。
  • ( f i n d s t r i n g s , (findstring s, (findstrings,(MAKEFLAGS))是一个函数调用,用于在MAKEFLAGS变量中查找字符串s。如果找到了,它返回找到的字符串(在这个场景下是s);如果没有找到,它返回空字符串。
  • ifeq是条件判断的开始,它比较两个参数是否相等。在这里,它比较的是findstring函数的返回值(可能是s或空字符串)和空字符串()。如果相等(即MAKEFLAGS中不包含s),则执行接下来的XECHO = echo语句;如果不相等(即MAKEFLAGS中包含s),则跳过该语句,继续检查下一个条件(虽然在这个例子中并没有显示下一个条件,但通常这种结构会包含else分支来处理包含s的情况)。
    2.XECHO = echo:
  • 如果MAKEFLAGS中不包含s,这行代码会被执行,将变量XECHO的值设置为echo命令。这意味着在Makefile的后续部分中,每当使用${XECHO}时,实际上都会执行echo命令,从而打印出相应的信息。
    3.else:
  • 这是一个条件分支的开始,用于处理MAKEFLAGS中包含s的情况。在这个例子中,else分支紧跟在ifeq条件判断之后,没有显示的条件判断结束(endif),但我们可以推断出它的存在。
    4.XECHO = ::
  • 如果MAKEFLAGS中包含s,这行代码会被执行,将变量XECHO的值设置为冒号(:)。在shell中,单独的冒号是一个空命令,它什么也不做,也不会产生任何输出。因此,在Makefile的后续部分中,每当使用${XECHO}时,实际上什么也不会发生,从而实现了静默模式。
    执行make -s Makefile中的命令不会被打印出来

2种编译方法(原地编译和单独输出文件夹编译)

原地编译 :当前文件夹中的.c文件,编译出来的.o文件会放在同一文件夹下
单独输出文件夹编译:在编译时另外指定一个输出目录,将来所有的编译生成的.o文件或生成的其他文件全部丢到那个输出目录下去。源代码目录不做任何污染,这样输出目录就承载了本次配置编译的所有结果。

#
# U-boot build supports producing a object files to the separate external
# directory. Two use cases are supported:
#
# 1) Add O= to the make command line
# 'make O=/tmp/build all' 告诉make程序在/tmp/build目录下进行构建,而不是在源代码目录中。注意,all是make的默认目标,所以即使省略它,make也会尝试构建所有目标。
#
# 2) Set environement variable BUILD_DIR to point to the desired location
# 'export BUILD_DIR=/tmp/build'
# 'make'
#
# The second approach can also be used with a MAKEALL script
# 'export BUILD_DIR=/tmp/build' 另一种方法是设置环境变量BUILD_DIR来指定构建目录。你可以在你的shell环境中设置这个变量,然后直接运行make命令。
# './MAKEALL'
#
# Command line 'O=' setting overrides BUILD_DIR environent variable.
#同时使用了O=命令行参数和BUILD_DIR环境变量,O=参数的优先级更高。这意味着,如果你同时设置了它们,make会优先使用O=参数指定的目录作为构建目录。
# When none of the above methods is used the local build is performed and
# the object files are placed in the source directory.
#

第一种:make O=输出目录
第二种:export BUILD_DIR=输出目录 然后再make
如果两个都指定了(既有BUILD_DIR环境变量存在,又有O=xx),则O=xx具有更高优先级,听他的。
两种编译的实现代码在Makefile的78-123行

OBJTREE     := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE     := $(CURDIR)
TOPDIR      := $(SRCTREE)
LNDIR       := $(OBJTREE)
export  TOPDIR SRCTREE OBJTREE

OBJTREE、SRCTREE、TOPDIR
(1)OBJTREE:编译出的.o文件存放的目录的根目录。在默认编译下,OBJTREE等于当前目录;在O=xx编译下,OBJTREE就等于我们设置的那个输出目录。
(2)SRCTREE: 源码目录,其实就是源代码的根目录,也就是当前目录。
总结:在默认编译下,OBJTREE和SRCTREE相等;在O=xx这种编译下OBJTREE和SRCTREE不相等。Makefile中定义这两个变量,其实就是为了记录编译后的.o文件往哪里放,就是为了实现O=xx的这种编译方式的。

MKCONFIG(Makefile的101行)

MKCONFIG    := $(SRCTREE)/mkconfig
export MKCONFIG

(1)Makefile中定义的一个变量(在这里定义,在后面使用),它的值就是我们源码根目录下面的mkconfig。这个mkconfig是一个脚本,这个脚本就是uboot配置阶段的配置脚本。后面要用至少3节课详细讲这个配置脚本的工作。

include $(obj)include/config.mk(133行)

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

(1)include/config.mk不是源码自带的(你在没有编译过的源码目录下是找不到这个文件的),要在配置过程(make x210_sd_config)中才会生成这个文件。因此这个文件的值和我们配置过程有关,是由配置过程根据我们的配置自动生成的。在(mkconfig文件123-129行)创建的
(2)我们X210在iNand情况下配置生成的config.mk内容为:

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

(3)我们在下一行(134行)export导出了这5个变量作为环境变量。所以着两行加起来其实就是为当前makefile定义了5个环境变量而已。之所以不直接给出这5个环境变量的值,是因为我们希望这5个值是可以被人很容易的、集中的配置的。

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

(4)这里的配置值来自于2589行那里的配置项。如果我们要更改这里的某个配置值要到2589行那里调用MKCONFIG脚本传参时的参数。

ARCH CROSS_COMPILE

(1)接下来有2个很重要的环境变量。一个是ARCH,上面导出的,值来自于我们的配置过程,它的值会影响后面的CROSS_COMPILE环境变量的值。ARCH的意义是定义当前编译的目标CPU的架构。
(2)CROSS_COMPILE是定义交叉编译工具链的前缀的。定义这些前缀是为了在后面用(用前缀加上后缀来定义编译过程中用到的各种工具链中的工具)。我们把前缀和后缀分开还有一个原因就是:在不同CPU架构上的交叉编译工具链,只是前缀不一样,后缀都是一样的。因此定义时把前缀和后缀分开,只需要在定义前缀时区分各种架构即可实现可移植性。
(3)CROSS_COMPILE在136-182行来确定。CROSS_COMPILE是被ARCH所确定的,只要配置了ARCH=arm,那么我们就只能在ARM的那个分支去设置CROSS_COMPILE的值。这个设置值只要能保证找到那个交叉编译工具链即可,不一定非得是全路径的,相对路径也可以。(如果已经将工具链导出到环境变量,并且设置了符号链接,这样CROSS_COMPILE = arm-linux-就可以)
(4)实际运用时,我们可以在Makefile中去更改设置CROSS_COMPILE的值,也可以在编译时用make CROSS_COMPILE=xxxx来设置,而且编译时传参的方法可以覆盖Makefile里面的设置。

$(TOPDIR)/config.mk(主Makefile的185行)

# load other configuration
include $(TOPDIR)/config.mk

编译工具定义(config.mk 94-107行)



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

包含开发板配置项目(config.mk, 112行)

# Load generated board configuration
sinclude $(OBJTREE)/include/autoconf.mk

(1)autoconfig.mk文件不是源码提供的,是配置过程自动生成的。
(2)这个文件的作用就是用来指导整个uboot的编译过程。这个文件的内容其实就是很多CONFIG_开头的宏(可以理解为变量),这些宏/变量会影响我们uboot编译过程的走向(原理就是条件编译)。在uboot代码中有很多地方使用条件编译进行编写,这个条件编译是用来实现可移植性的。(可以说uboot的源代码在很大程度来说是拼凑起来的,同一个代码包含了各种不同开发板的适用代码,用条件编译进行区别。)
(3)这个文件不是凭空产生的,配置过程也是需要原材料来产生这个文件的。原材料在源码目录的inlcude/configs/xxx.h头文件。(X210开发板中为include/configs/x210_sd.h)。这个h头文件里面全都是宏定义,这些宏定义就是我们对当前开发板的移植。每一个开发板的移植都对应这个目录下的一个头文件,这个头文件里每一个宏定义都很重要,这些配置的宏定义就是我们移植uboot的关键所在。

链接脚本(config.mk 142-149行)

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

(1)如果定义了CONFIG_NAND_U_BOOT宏,则链接脚本叫u-boot-nand.lds,如果未定义这个宏则链接脚本叫u-boot.lds。
(2)从字面意思分析,即可知:CONFIG_NAND_U_BOOT是在Nand版本情况下才使用的,我们使用的X210都是iNand版本的,因此这个宏没有的。
(3)实际在board\samsung\x210目录下有u-boot.lds,这个就是链接脚本。我们在分析uboot的编译链接过程时就要考虑这个链接脚本。

TEXT_BASE(config.mk 156-158行)

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

(1)Makefile中在配置X210开发板时,在board/samsung/x210目录下生成了一个文件config.mk,其中的内容就是:TEXT_BASE = 0xc3e00000相当于定义了一个变量。
(2)TEXT_BASE是将来我们整个uboot链接时指定的链接地址。因为uboot中启用了虚拟地址映射,因此这个C3E00000地址就等于0x23E00000(也可能是33E00000具体地址要取决于uboot中做的虚拟地址映射关系)。
(3)回顾裸机中讲的链接地址的问题,再想想dnw方式先下载x210_usb.bin然后再下载uboot.bin时为什么第二个地址是23E00000.

自动推导规则(config.mk 239-256行)

all:        $(ALL)

(1)291行出现了整个主Makefile中第一个目标all(也就是默认目标,我们直接在uboot根目录下make其实就等于make all,就等于make这个目标)
(2)目标中有一些比较重要的。譬如:u-boot是最终编译链接生成的elf格式的可执行文件,
(3)unconfig字面意思来理解就是未配置。这个符号用来做为我们各个开发板配置目标的依赖。目标是当我们已经配置过一个开发板后再次去配置时还可以配置。
(4)我们配置开发板时使用:make x210_sd_config,因此分析x210_sd_config肯定是主Makefile中的一个目标。

MKCONFIG(主Makefile的2589行)

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

1)mkconfig脚本的6个参数
$(@:_config=) arm s5pc11x x210 samsung s5pc110
x210_sd_config里的_config部分用空替换,得到:x210_sd,这就是第一个参数,所以:
$1: x210_sd
$2: arm
$3: s5pc11x
$4: x210
$5: samsumg
6 : s 5 p c 110 所以, 6: s5pc110 所以, 6:s5pc110所以,# = 6
(2)第23行:其实就是看BOARD_NAME变量是否有值,如果有值就维持不变;如果无值就给他赋值为$1,实际分析结果:BOARD_NAME=x210_sd

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

[ “${BOARD_NAME}” ] || BOARD_NAME=“$1”

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

(4)第26行:如果$#大于6,则也返回1.
所以:mkconfig脚本传参只能是4、5、6,如果大于6或者小于4都不行。

(5)从第33行到第118行,都是在创建符号链接。为什么要创建符号链接?这些符号链接文件的存在就是整个配置过程的核心,这些符号链接文件(文件夹)的主要作用是给头文件包含等过程提供指向性连接。根本目的是让uboot具有可移植性。
uboot可移植性的实现原理:在uboot中有很多彼此平行的代码,各自属于各自不同的架构/CPU/开发板,我们在具体到一个开发板的编译时用符号连接的方式提供一个具体的名字的文件夹供编译时使用。这样就可以在配置的过程中通过不同的配置使用不同的文件,就可以正确的包含正确的文件。
(6)创建的符号链接:

    cd ./include
    rm -f asm
    ln -s asm-$2 asm
  • ln 是 “link” 的缩写,用于创建链接。在Unix/Linux中,有两种类型的链接:硬链接(hard links)和符号链接(symbolic links,简称symlinks)。
  • -s 选项指定创建一个符号链接,而不是硬链接。符号链接类似于Windows中的快捷方式。
  • asm-$2 是目标文件或目录的名称,其中 $2 是一个位置参数(positional parameter),在shell脚本中,$1、$2、$3… 分别代表传递给脚本的第一个、第二个、第三个…参数。因此,asm-$2 实际上是将 asm- 和传递给脚本的第二个参数拼接起来形成的字符串,作为符号链接指向的目标。
  • asm 是新创建的符号链接的名称。
    第一个:在include目录下创建asm文件,指向asm-arm。(46-48行)
    第二个:在inlcude/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目录下创建regs.h文件,指向include/s5pc110.h
删除第二个。
第四个:在inlcude/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc11x

if [ "$2" = "arm" ] ; then
    rm -f asm-$2/proc
    ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi

第五个:在include/asm-arm下创建一个proc文件,指向include/asm-arm/proc-armv
总结:一共创建了4个符号链接。这4个符号链接将来在写代码过程中,头文件包含时非常有用。譬如一个头文件包含可能是:#include <asm/xx.h>

(1)创建include/config.mk文件(mkconfig文件123-129行)
(2)创建include/config.mk文件是为了让主Makefile在第133行去包含的。

#
# Create include file for Make
#
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

(3)思考:uboot的配置和编译过程的配合。编译的时候需要ARCH=arm、CPU=xx等这些变量来指导编译,配置的时候就是为编译阶段提供这些变量。那为什么不在Makefile中直接定义这些变量去使用,而要在mkconfig脚本中创建config.mk文件然后又在Makefile中include这些文件呢?
(4)理解这些脚本时,时刻要注意自己当前所处的路径。
(5)创建(默认情况)/追加(make -a时追加)include/config.h文件(mkconfig文件的134-141行)。

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

exit 0

(6)这个文件里面的内容就一行#include <configs/x210_sd.h>,这个头文件是我们移植x210开发板时,对开发板的宏定义配置文件。这个文件是我们移植x210时最主要的文件。
(7)x210_sd.h文件会被用来生成一个autoconfig.mk文件,这个文件会被主Makefile引入,指导整个编译过程。这里面的这些宏定义会影响我们对uboot中大部分.c文件中一些条件编译的选择。从而实现最终的可移植性。

注意:uboot的整个配置过程,很多文件之间是有关联的(有时候这个文件是在那个文件中创建出来的;有时候这个文件被那个文件包含进去;有时候这个文件是由那个文件的内容生成的决定的)
注意:uboot中配置和编译过程,所有的文件或者全局变量都是字符串形式的(不是指的C语言字符串的概念,指的是都是字符组成的序列)。这意味着我们整个uboot的配置过程都是字符串匹配的,所以一定要细节,注意大小写,要注意不要输错字符,因为一旦错一个最后会出现一些莫名其妙的错误,很难排查,这个是uboot移植过程中新手来说最难的地方。

在这里插入图片描述

uboot的链接脚本u-boot.lds

链接脚本目录uboot\board\samsung\x210,文件u-boot.lds

ENTRY(_start)

ENTRY(_start)用来指定整个程序的入口地址。所谓入口地址就是整个程序的开头地址,可以认为就是整个程序的第一句指令。有点像C语言中的main。

指定程序的链接地址有2种方法:一种是在Makefile中ld的flags用-Ttext 0x20000000来指定;第二种是在链接脚本的SECTIONS开头用.=0x20000000来指定。两种都可以实现相同效果。其实,这两种技巧是可以共同配合使用的,也就是说既在链接脚本中指定也在ld flags中用-Ttext来指定。两个都指定以后以-Ttext指定的为准。TEXT_BASE(config.mk 156-158行)
uboot的最终链接起始地址就是在Makefile中用-Ttext 来指定的,具体参见2.4.5.2节,注意TEXT_BASE变量。最终来源是Makefile中配置对应的命令中,在make xxx_config时得到的。
在代码段中注意文件排列的顺序。指定必须放在前面部分的那些文件就是那些必须安排在前16KB内的文件,这些文件中的函数在前16KB会被调用。在后面第二部分(16KB之后)中调用的程序,前后顺序就无所谓了。
链接脚本中除了.text .data .rodata .bss段等编译工具自带的段之外,编译工具还允许我们自定义段。譬如uboot总的.u_boot_cmd段就是自定义段。自定义段很重要。

学习记录,侵权联系删除。
来源:朱老师物联网大课堂


网站公告

今日签到

点亮在社区的每一天
去签到