uboot编译三步走:
这一步是产生板子的配置文件。
我们假设是配置ast2500evb板子,那么这里的配置命令就是 make ast2500evb_config
uboot/Makefile
这里%_config中%表示通配任意字符,即匹配ast2500evb_config。
首先执行依赖target ‘unconfig’的命令:删除之前配置时产生的文件。
然后执行命令@$(MKCONFIG) -A $(@:_config=)
$(MKCONFIG)为uboot/mkconfig, .
${CURDIR}为makefile变量,表示当前目录
$(@:_config=)表示将target(即%_config)中的_config替换为=后面的(null), 实际这里就相当于执行mkconfig -A ast2500evb
我们接着看mkconfig文件。
uboot/mkconfig
这是一个shell脚本。
$#: 表示参数个数
$n:表示第n个参数
首先判断参数的个数是否为2(makefile调用时的格式为mkconfig -A ast2500evb,参数个数为2)。
然后使用egrep提取boards.cfg中的数据,egrep使用的正则表达式: "^[[:space:]]*${2}[[:space:]]"
注意,这个正则表达式中有shell变量${2},要先替换。替换后正则表达式为
"^[[:space:]]*ast2500evb[[:space:]]"。
egrep正则表达式匹配任何以一个或多个空白符开头后跟ast2500evb字符串再后跟一个空白符的行,或者以ast2500evb字符串开头后跟一个空白符的行。
boards.cfg为输入文件。
boards.cfg描述了板子的arch, cpu, soc, board等信息。
对于我们的例子而言,egrep输出ast2500evb arm arm1176 ast2500evb – ast2500.
之后,通过set将这些信息赋值给$1, $2, $3…
这样之后,
$1 代表target ast2500evb;
$2代表arch arm;
$3代表cpu arm1176;
$4代表board ast2500evb
$5代表vendor –
$6代表soc ast2500
然后将这些信息设置为相应的变量:
注意,55行的${1%_config},%_config表示去掉_config以及其右边的字符串,即表示将$1中的_config以及_config右边的所有字符串去掉。
接下去,创建特定的文件和目录。
$SRCTREE: 表示当前工程的顶层目录uboot/
$OBJTREE: 表示build目录,该目录由make -O=xxx来指定,如果没有指定,则默认为$SRCTREE.
$SRCTREE和$OBJTREE都定义在uboot/Makefile中。
假定$SRCTREE == $OBJTREE, 即我们make时没有指定-O=xxx参数。
那么mkconfig会在uboot/include下面创建一个asm软链接,链接到../arch/arm/include/asm
然后删除之前创建的链接文件uboot/include/asm/arch(uboot/arch/arm/include/asm/arch), 并创建本次配置的arch链接文件.
接着创建asm/proc链接文件:
之后,创建uboot/include/config.mk文件,文件内容为
ARCH =
CPU =
BOARD =
SOC =
并配置板子目录变量为ast2500evb
然后创建uboot/include/config.h文件,并写入定义行注释代码。
接着向config.h写入内容:
174-177行写入一些预定义的宏,这些宏由boards.cfg中的最后一列(Options)而来。
比如:
那么174-177行就向config.h写入如下宏:
#define CONFIG_AT91SAM9260
#define CONFIG_SYS_USE_DATAFLASH_CS0
由于ast2500evb没有Options,故174-177行不执行。
对于ast2500evb是写入如下定义:
config_cmd_defaults.h locates at uboot/include/config_cmd_defaults.h
config_defaults.h locates at uboot/include/config_defaults.h
configs/ast2500evb.h locates at uboot/configs/ast2500evb.h
asm/config.h locates at uboot/arch/arm/include/asm/config.h
config_fallbacks.h locates at uboot/include/config_fallbacks.h
config_uncmd_spl.h locates at uboot/include/config_uncmd_spl.h
到这里,make menuconfig就执行结束了。
总结一下,make ast2500evb_config会创建
uboot/include/asm -> uboot/arch/arm/include/asm
uboot/include/asm/arch -> uboot/arch/arm/include/asm/arch-ast2500
uboot/include/asm/proc -> uboot/arch/arm/include/asm/proc-armv
uboot/include/config.mk
uboot/include/config.h
执行make时,默认的target是all, uboot/Makefile中有两处定义了all:
这里,第二个all会覆盖第一个all。故执行make或make all时,对应uboot/Makefile:448处的all.
从448行,我们知道,执行make的时候,它的依赖为$(ALL-y)和$(SUBDIR_EXAMPLES)。我们主要来看一下$(ALL-y)都是些啥:
$(ALL-y)包含了u-boot.srec, u-boot.bin, System.map. 我们的例子中ast2500evb没有配置CONFIG_NAND_U_BOOT, CONFIG_ONENAND_U_BOOT, CONFIG_SPL, CONFIG_OF_SEPARATE, CONFIG_SPL等。
u-boot.srec, u-boot.bin都是基于u-boot的格式转换。u-boot.bin为“裸”的二进制格式,可以直接被cpu执行(只有*.txt, *.bss之类的段,没有其他的header之类的,比如elf header等)。其他的*.srec, *.hex是有文件格式的,就像有文件头描述之类的一样,该类文件需要解析成bin文件才能被cpu执行。
u-boot这个又依赖于伪目标depend,$(SUBDIR_TOOLS) ,$(OBJS) ,$(LIBBOARD) ,$(LIBS) ,$(LDSCRIPT) ,$(obj)u-boot.lds
u-boot是通过链接程序ld,将*.o, *.a, *.so等,以及链接脚本u-boot.lds生成的elf可执行文件(linux os可识别的可执行文件格式,含有elf header)。
这个u-boot直接给cpu是无法执行的,因为cpu可不认elf header。
所以,u-boot.bin就是将u-boot中的text, bss之类的段提取出来的纯可执行的二进制文件。
下面是u-boot的elf header和文件内容:
我们来看看u-boot.bin中的内容:
从下面的对比来看,u-boot.bin中的内容就是u-boot中offset 0x10000开始处的内容。
我们接着来介绍下u-boot的依赖depend,$(SUBDIR_TOOLS) ,$(OBJS) ,$(LIBBOARD) ,$(LIBS) ,$(LDSCRIPT) ,$(obj)u-boot.lds.
depend是用来生成依赖关系的。比如源文件*.c引用了头文件*.h,depend的作用就是用于生成*.c依赖*.h这样的依赖关系,有了这个依赖关系后,当*.h有变化时,make就会重新编译对应的*.c文件。
$(SUBDIR_TOOLS)就是tools.
$(OBJS)就是*.o, 它包含哪些呢?
uboot/Makefile
这里的CPUDIR是在uboot/config.mk中定义的,uboot/config.mk在uboot/Makefile中包含。
uboot/Makefile
uboot/config.mk
CPUDIR就是uboot/arch/arm/cpu/arm1176, 这里$(ARCH), $(CPU)就是在由make ast2500evb_config生成的uboot/include/config.mk中定义。
因此, $(OBJS)为uboot/arch/arm/cpu/arm1176/start.o.
补充一下,uboot/include/config.mk 164和165行的文件是在depend的依赖中生成的。
uboot/Makefile
$(LIBBOARD): 就是 uboot/board/ast2500evb/libast2500evb.o
uboot/Makefile
$(LIBS): 就是下列各种*.o
uboot/Makefile
$(LDSCRIPT): 就是指定连接器脚本,即uboot/board/ast2500evb/u-boot.lds
uboot/Makefile
u-boot.lds文件中定义了程序的入口、代码段、数据段地址等信息:
至此,我们大概了解了这几个依赖:depend,$(SUBDIR_TOOLS) ,$(OBJS) ,$(LIBBOARD) ,$(LIBS) ,$(LDSCRIPT) ,$(obj)u-boot.lds。
我们接着看依赖$(OBJS)。
$(OBJS)是通过进入到$(CPUDIR)目录(CPUDIR=uboot/arch/arm/cpu/arm1176)中执行make而得到的。
uboot/arch/arm/cpu/arm1176/Makefile
uboot/config.mk中定义了*.o生成的规则。
uboot/config.mk
我们看下一个$(LIBBOARD)
$(LIBBOARD) = uboot/board/ast2500evb/libast2500evb.o
uboot/Makefile
$(LIBBOARD)这个target是通过进入其所在目录(uboot/board/ast2500evb),执行make而得到的。
uboot/board/ast2500evb/Makefile
类似地,$(LIBS)也是分别进入目标所在的目录,执行make操作而得到。
最后,我们来看一下$(ALL-y)的一个依赖System.map是如何生成的。
System.map是通过u-boot这个elf可执行文件而来的。
uboot/Makefile
System.map是一个map文件,记录了符号和地址信息。
(略)