一直对于嵌入式Linux很感兴趣,但是苦于上班以及考研的压力,最近几天稍有空余时间,想把自己对于u-boot认识写出来,以便和大家交流,u-boot这个东西我想熟悉嵌入式的人应该很熟悉,u代表的是universal的意思,顾名思义它能够支持很多平台,这也是导致u-boot代码变得异常庞大的原因,我个人比较爱研究早期的代码,因为早期的代码首先比较小,并且比较适合初学者阅读,但是千万不要认为早期的代码有多么简单,因为如果能把比较早的代码读懂,你沿着版本读下去,会感觉比你以前直接读高版本的效率高,记得想当年读Linux源代码,一开始就去触碰Linux2.6版本,结果导致迷失在代码中,所以我现在研究u-boot依然坚持这个路线,读早期版本。
废话不想多说,但是我想研究源代码最好还是从Makefile开始,就像fudan_abc说的那样,Makefile就是源代码的地图,指引着我们前进,所以今天首先来研究u-boot的各层Makefile的配置,顺便说句我的版本是u-boot0.2.0,主线是以S3C2410(其实和2440研究的方法是一样的)。
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/macppc/ppc/)
HOSTOS := $(shell uname -s | tr A-Z a-z |
sed -e 's/(cygwin).*/cygwin/')
export HOSTARCH
# Deal with colliding definitions from tcsh etc.
VENDOR=
#########################################################################
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
export TOPDIR
ifeq (include/config.mk,$(wildcard include/config.mk))
# load ARCH, BOARD, and CPU configuration
include include/config.mk
export ARCH CPU BOARD VENDOR
# load other configuration
include $(TOPDIR)/config.mk
ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),ppc)
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = ppc_8xx-
endif
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm_920TDI-
endif
ifeq ($(ARCH),i386)
#CROSS_COMPILE = i386-elf-
endif
endif
endif
export CROSS_COMPILE
# The "tools" are needed early, so put this first
SUBDIRS = tools
lib_generic
lib_$(ARCH)
cpu/$(CPU)
board/$(BOARDDIR)
common
disk
fs
net
rtc
dtt
drivers
post
post/cpu
examples
#########################################################################
我们先慢慢来,先上部分代码,首先看到的是一个变量HOSTARCH,这个变脸顾名思义,是主机平台的意思哈,也就是要在这里选择我编译u-boot当前的PC机的操作系统,:=是对变量进行复制的符号,Makefile支持两中赋值方式:递归式、直接式。我们接着看,接着:=是一串很长的东西,其实这个是Makefile中的一个函数名叫shell,Makefile对这个函数的描述是,可以和外部进行通信,什么意思呢?其实就是说,shell这个函数是专门用来引用Linux操作系统中的命令的,换句话说,就是shell这函数必须要有各参数,这个参数必须是一个命令(shell的命令哦!!!),就拿我们这个上面代码来说,它的参数就是“uname”和“sed”,而这函数的返回值就是和这个命令在shell中执行的结果,那好,我们上面那段代码的意义就很明确啦,就是要通过shell函数的参数“uname”和“sed”把它的值返回给HOSTARCH,那“uname”和“sed”是什么意思呢?“uname
-m”是将使用的CPU型号名称显示在标准输出中,比如输出“i686”, “sed”这个命令比较复杂,内容很丰富,他是正则表达式的一种,不过,我们在这里就不展开了,就说说它上面表达是什么意思,“sed -e s/arm.*/arm/” 目的就是讲arm.*都替换成arm,所以废了半天话,其实这句话,就是把“uname -m”的结果传给命令“sed”进行过滤,最终将输出结果赋给HOSTARCH,我的电脑的结HOSTARCHi386,。
下面一句话,和上面一句的功能类似,都是要知道主机的信息,这次换成了操作系统,并且多了一个命令 “tr”,“tr”作用其实就是替换/删除字符串,所以这句话的意思是将大写全部替换成小写,然后在输出给“sed”,进行过滤,最后将结果输出给HOSTOS。
随后一句话,是将HOSTARCH输出,其作用将其传递给各个目录下的子Makefile。
“VENDOR=”没有赋值,为什么呢?我也不知道,可能在下面会用到,等到用到的时候再来看吧!!!
接下来就比较重要,因为不管是编译u-boot还是编译Linux内核,都需要进入不同的子目录进行编译,然而这些子目录,我们怎么找到呢???如果死板的设置目录的当前位置,那么一旦将目录更改,那么就将无法编译,因为顶层目录被更改了,所以,我在编译之前,需要获取顶层目录的路径,这样便可找到子目录的路径,就可以进行编译了,所以TOPDIR这个变量就是将贯穿始终顶层目录的路径,并且下面一定还会将这个变量传递给子Makefile。注意:在Makefile中编写shell脚本和单纯编写shell脚本有一些不同的,比如这里,为什么要用两个“$$”呢?因为在Makefile中变量调用都是用“$”开头的,所以这里shell中引用变量为了和Makefile中的变量区别,要用两个“$$”,还有一些其他规则,等用到时再细讲。
得到了TOPDIR的值,然后立刻将他输出,也就是变成全局变量,方便子Makefile调用。
接下来就要进行配置的选择,在我们u-boot顶层目录下有个文件config.mk是关于u-boot配置Makefile,我们稍后会进行讲解,这句话中用到了另个一Makefile的函数wildcard,wildard其实就是他有一个参数,就是讲所有匹配这个参数的所有文件展开,如:wildcard(*.c)就是将所有以.c结尾的文件展开,所以上面那句话的意思就是寻找include目录下的config.mk是否存在,如果存在则包含此文件夹,并将其中的参数输出,如果include下没有config.mk文件,则将包含顶层目录下的config.mk。
接下来就是选择交下编译工具参数,这里我们使用的是arm,所以经过判断,最后CROSS_COMPILE被编译为arm_920TDI-。
最后是将子目录的名字都赋给变量SUBDIRS,上面注释提醒,因为toos/文件下下面的要先用到,所以要把它放在第一个。
今天废话了很多,似乎没说多少代码,不过,今天讲了很多Makefile的语法规则,这在以后既不在讲解了,所以今天的废话也是值得,希望大家能喜欢,也希望能有高手给我指点,今天就先到这里,未完待续。。。