自己写的bootloader可以引导kernel了,我以为曾经神秘的u-boot代码将变得毫无挑战,然事实表明u-boot作为优秀的开源代码,阅读起来还是很有挑战的,值得一读!
阅读碰到的头等问题:Makefile和shell脚本看不懂...
说起来做linux也很久了,Makefile和shell脚本都接触过,但真的都是略懂而已.因为公司的Makefile和shell简单的一眼望的对穿,很初级的写法,简单的应用.再随便在网上下个老外的开源代码,那个Makefile和shell复杂啊.一不留神想起来了qt的qmake根据工程文件生成的Makefile也是很简单,但qmake是人家老外写的.不说其他语言了,只看Makefile和shell,中外的差距就在那了.
这次准备移植u-boot到tq2440上,选用的u-boot版本是u-boot-2012.07.
下面是我对u-boot配置和编译的makefile mkconfig config.mk等文件的解读,有些解读我是在源档上添加文字注释的,有些是另外写的,解读难免有误,若有读者发现了,希望能够指出,在下感激不尽!
在编译u-boot的过程,就是make xxx_config和make两步
以make smdk2410_config为例:
当以smdk2410_config为目标时,makefile中前面一些变量的定义和其他文件的引用也是有的,这个在原档中添加了有关注释:
在makefile中有:
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 %_config:: unconfig echo $@ $(MKCONFIG) -A $(@:_config=)
%是个通配符,make xxx_config都是这个目标.目标的依赖是unconfig,unconfig的命令是删除一些文件,而这些文件正是从make xxx_config过程中产生的.unconfig就是清理配置的.
我们来看@$(MKCONFIG) -A $(@:_config=)
其实执行的是mkconfig -A smdk2410
我们可以在该行上面添加一行:echo $@
则会输出smdk2410_config,因为$@就是指目标
$(@:_config=)是变量的替换引用
格式为“$(VAR:A=B)”(或者“${VAR:A=B}”),意思是:替换变量“VAR”中所有“A”字符结尾的字为“B”结尾的字。
所以smdk2410_config末尾的_config去除了.
下面就是执行mkconfig脚本了,mkconfig -A smdk2410
给出添加注释的mkconfig文件:
#!/bin/sh -e # Script to create header files and links to configure # U-Boot for a specific board. # # Parameters: Target Architecture CPU Board [VENDOR] [SOC] # # (C) 2002-2010 DENX Software Engineering, Wolfgang Denk <[email protected]> # APPEND=no # Default: Create new config file BOARD_NAME="" # Name to print in make output TARGETS="" arch="" cpu="" board="" vendor="" soc="" options="" echo $# if [ \( $# -eq 2 \) -a \( "$1" = "-A" \) ] ; then # Automatic mode line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg` || { echo "make: *** No rule to make target \`$2_config'. Stop." >&2 exit 1 } set ${line} echo ${line} echo $# # add default board name if needed [ $# = 3 ] && set ${line} ${1} ##################################### #我们执行脚本的命令是mkconfig -A smdk2410,$#表示的是参数的个数,$1表示的是第一个参数 #line 就是在boards.cfg文件中smdk2410的那行,而-i表示忽略大小写 #在boards.cfg文件中,有 #Target ARCH CPU Board name Vendor SoC Options #smdk2410 arm arm920t - samsung s3c24x0 # set ${line} # set也可用于在脚本内部给出其运行参数,所以这个时候参数就变为"smdk2410 arm arm920t - samsung s3c24x0" #这个时候参数个数就变成6个了 ###################################### elif [ "${MAKEFLAGS+set}${MAKELEVEL+set}" = "setset" ] ; then # only warn when using a config target in the Makefile cat <<-EOF warning: Please migrate to boards.cfg. Failure to do so will mean removal of your board in the next release. EOF sleep 5 fi echo $1 while [ $# -gt 0 ] ; do case "$1" in --) shift ; break ;; -a) shift ; APPEND=yes ;; -n) shift ; BOARD_NAME="${1%_config}" ; shift ;; -t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;; *) break ;; esac done ################################################ #因为$1的值为smdk2410,所以case找不到对应的 ################################################# [ $# -lt 4 ] && exit 1 [ $# -gt 7 ] && exit 1 ################################################## #对参数个数做检查,小于4个或大于7个就退出 ################################################## # Strip all options and/or _config suffixes CONFIG_NAME="${1%_config}" #################### #CONFIG_NAME的值为smdk2410 ######################### echo config_ echo ${CONFIG_NAME} [ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}" echo board echo ${BOARD_NAME} ########################################### #如果BOARD_NAME在之前已经被设定了,就不做任何动作;如果为空,就设定为smdk2410.这里设定为smdk2410 ############################################ arch="$2" cpu="$3" if [ "$4" = "-" ] ; then board=${BOARD_NAME} else board="$4" fi ###################################################### #设定arch变量的值为arm #cpu变量的值为arm920t #因为第四个变量为"-",所以board变量的值为smdk2410 ####################################################### [ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5" [ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6" ############################################################# #设定verdor变量的值为samsung #设定soc变量的值为s3c24x0 ############################################################# [ $# -gt 6 ] && [ "$7" != "-" ] && { # check if we have a board config name in the options field # the options field mave have a board config name and a list # of options, both separated by a colon (':'); the options are # separated by commas (','). # # Check for board name tmp="${7%:*}" if [ "$tmp" ] ; then CONFIG_NAME="$tmp" fi # Check if we only have a colon... if [ "${tmp}" != "$7" ] ; then options=${7#*:} TARGETS="`echo ${options} | sed 's:,: :g'` ${TARGETS}" fi } ################################################# #因为我们的变量个数就是6个,这一段不执行 ################################################# echo ${ARCH} echo ${arch} if [ "${ARCH}" -a "${ARCH}" != "${arch}" ]; then echo "Failed: \$ARCH=${ARCH}, should be '${arch}' for ${BOARD_NAME}" 1>&2 exit 1 fi #################################################### #ARCH是在顶层makefile中定义的,在此刻还是为空的。 #如果ARCH已经有值了,那么就检测ARCH和arch是否匹配了. #################################################### if [ "$options" ] ; then echo "Configuring for ${BOARD_NAME} - Board: ${CONFIG_NAME}, Options: ${options}" else echo "Configuring for ${BOARD_NAME} board..." fi ########################################################################### #我们没有定义options变量,所以输出Configuring for smdk2410 board... ########################################################################### # # Create link to architecture specific headers # echo ${SRCTREE} echo ${OBJTREE} if [ "$SRCTREE" != "$OBJTREE" ] ; then mkdir -p ${OBJTREE}/include mkdir -p ${OBJTREE}/include2 cd ${OBJTREE}/include2 rm -f asm ln -s ${SRCTREE}/arch/${arch}/include/asm asm LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/ cd ../include mkdir -p asm else cd ./include rm -f asm ln -s ../arch/${arch}/include/asm asm fi ############################################################################# #在makefile中我们已经知道SRCTREE和OBJTREE都是当前目录,所以这里执行else #进入./include目录,删除asm链接,并重新建立链接asm,指向arch/arm/include/asm ############################################################################# rm -f asm/arch ######################################################################### #删除include目录下的asm下的arch链接文件 ######################################################################## ss= echo ${ss} if [ -z "${ss}" ] ; then echo "null" else echo "not null" fi echo ${LNPREFIX} if [ -z "${soc}" ] ; then ln -s ${LNPREFIX}arch-${cpu} asm/arch else ln -s ${LNPREFIX}arch-${soc} asm/arch fi ########################################################## #-z用来检测字符串是否为空,为空返回真 #这里我们的soc不为空,执行else #将asm/arch链向arch-s3c24x0,看一下arch-s3c24x0目录,里面都是s3c24x0相关的头文件 ########################################################## if [ "${arch}" = "arm" ] ; then rm -f asm/proc ln -s ${LNPREFIX}proc-armv asm/proc fi ########################################################### #删除asm/proc链接文件 #将asm/proc链向proc-armv目录,该目录下是四个头文件:domain.h\processor.h\ptrace.h\system.h ############################################################# # # Create include file for Make # echo "ARCH = ${arch}" > config.mk echo "CPU = ${cpu}" >> config.mk echo "BOARD = ${board}" >> config.mk [ "${vendor}" ] && echo "VENDOR = ${vendor}" >> config.mk [ "${soc}" ] && echo "SOC = ${soc}" >> config.mk ###################################################################### #上面几句的作用在注释中描述的很清楚 #include/config.mk的文件如下: #ARCH = arm #CPU = arm920t #BOARD = smdk2410 #VENDOR = samsung #SOC = s3c24x0 ###################################################################### # Assign board directory to BOARDIR variable if [ -z "${vendor}" ] ; then BOARDDIR=${board} else BOARDDIR=${vendor}/${board} fi echo ${BOARDDIR} ####################################################################### #因为vendor变量不为空,所以执行else #BOARDDIR的值为samsung/s3c24x0 ######################################################################## # # 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 ######################################################################## #在文件的最开头可以看到APPEND为no,所以这里我们在include文件夹下建立config.h文件 ####################################################################### echo "/* Automatically generated - do not edit */" >>config.h echo ${TARGETS} for i in ${TARGETS} ; do i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`" echo "#define CONFIG_${i}" >>config.h ; done ################################################### #这里我们TARGETS为空,上面不执行了 ################################################## echo "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.h echo "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.h echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h [ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h [ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.h cat << EOF >> config.h #define CONFIG_BOARDDIR board/$BOARDDIR #include <config_cmd_defaults.h> #include <config_defaults.h> #include <configs/${CONFIG_NAME}.h> #include <asm/config.h> #include <config_fallbacks.h> EOF ###################################################### #生成config.h文件如下: # /* Automatically generated - do not edit */ # #define CONFIG_SYS_ARCH "arm" # #define CONFIG_SYS_CPU "arm920t" # #define CONFIG_SYS_BOARD "smdk2410" # #define CONFIG_SYS_VENDOR "samsung" # #define CONFIG_SYS_SOC "s3c24x0" # #define CONFIG_BOARDDIR board/samsung/smdk2410 # #include <config_cmd_defaults.h> # #include <config_defaults.h> # #include <configs/smdk2410.h> # #include <asm/config.h> # #include <config_fallbacks.h> ##################################################### exit 0
make xxx_config后,主要的变化是多了几个文件:
1.include/asm --> arch/arm/include/arm
2.include/asm/arch --> arch-s3c24x0
3.include/asm/proc --> proc-armv
4.在include目录下新建了config.mk文件,文件内容是ARCH CPU BOARD VENDOR SOC的定义
5.在include目录下新建了config.h文件
接着看make:
给出部分makefile中的注释,主要是一些变量的定义:
VERSION = 2012 PATCHLEVEL = 07 SUBLEVEL = EXTRAVERSION = ifneq "$(SUBLEVEL)" "" U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) else U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL)$(EXTRAVERSION) endif ################################ #定义U_BOOT_VERSION为2012.07 ##################################### TIMESTAMP_FILE = $(obj)include/generated/timestamp_autogenerated.h VERSION_FILE = $(obj)include/generated/version_autogenerated.h ############################### #因为obj为空,所以定义TIMESTAMP_FILE为include/generated/timestamp_autogenerated.h #定义VERSION_FILE为include/generated/version_autogenerated.h #**************** HOSTARCH := $(shell uname -m | \ sed -e s/i.86/x86/ \ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ \ -e s/sa110/arm/ \ -e s/ppc64/powerpc/ \ -e s/ppc/powerpc/ \ -e s/macppc/powerpc/\ -e s/sh.*/sh/) HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ sed -e 's/\(cygwin\).*/cygwin/') # Set shell to bash if possible, otherwise fall back to sh SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi; fi) export HOSTARCH HOSTOS SHELL ######################### #HOSTARCH为i686,HOSTOS为linux,SHELL为/bin/sh ############################# # Deal with colliding definitions from tcsh etc. VENDOR= ######################################################################### # Allow for silent builds ifeq (,$(findstring s,$(MAKEFLAGS))) XECHO = echo else XECHO = : endif ########################### #因为MAKEFLAGS变量的字符串为空,找不到s,所以ifeq为真,XECHO = echo ########################### ######################################################################### # # 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' # # 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' # './MAKEALL' # # Command line 'O=' setting overrides BUILD_DIR environent variable. # # When none of the above methods is used the local build is performed and # the object files are placed in the source directory. # ifdef O ifeq ("$(origin O)", "command line") BUILD_DIR := $(O) endif endif ################################# #如果没有在make命令行中定义O=/tmp之类的,那么BUILD_DIR就为/tmp,否则为空。 #当使用make O=/tmp时,表明#ifdef O有定义,而$(origin O)返回的就是"command line" ################################# 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),) ################################# #如果BUILD_DIR不为空,那么这几句就执行: #首先,saved-output变量也是BUILD_DIR的值 #如果BUILD_DIR不存在,那么就创建BUILD_DIR目录 #检测BUILD_DIR目录是否成功建好了,如果有问题就输出错误信息 ################################# OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) SPLTREE := $(OBJTREE)/spl SRCTREE := $(CURDIR) TOPDIR := $(SRCTREE) LNDIR := $(OBJTREE) export TOPDIR SRCTREE OBJTREE SPLTREE ########################################### #如果BUILD_DIR有值,那么OBJTREE就是BUILD_DIR的值,如果BUILD_DIR为空,那么OBJTREE就是CURDIR的值,$(CURDIR)时GNU Make内嵌的变量,是当前目录。 #我们在make时候不加O=/tmp之类的参数,所以OBJTREE就是当前工作目录,SPLTREE是当前工作目录下的spl目录,SRCTREE时当前工作目录,TOPDIR也是当前目录,LNDIR也是当前目录。 ########################################## MKCONFIG := $(SRCTREE)/mkconfig export MKCONFIG ############################################# #MKCONFIG定义为当前工作目录下的mkconfig脚本,并export ############################################# ifneq ($(OBJTREE),$(SRCTREE)) REMOTE_BUILD := 1 export REMOTE_BUILD endif #################################################################### #在我们的执行中,OBJTREE和SRCTREE是相等的,所以不管了 ################################################################### # $(obj) and (src) are defined in config.mk but here in main Makefile # we also need them before config.mk is included which is the case for # some targets like unconfig, clean, clobber, distclean, etc. ifneq ($(OBJTREE),$(SRCTREE)) obj := $(OBJTREE)/ src := $(SRCTREE)/ else obj := src := endif export obj src ####################################### #可以先看下上面的注释 因为两个路径相同,所以执行else ######################################### # Make sure CDPATH settings don't interfere unexport CDPATH ######################################################################### # The "tools" are needed early, so put this first # Don't include stuff already done in $(LIBS) # The "examples" conditionally depend on U-Boot (say, when USE_PRIVATE_LIBGCC # is "yes"), so compile examples after U-Boot is compiled. SUBDIR_TOOLS = tools SUBDIR_EXAMPLES = examples/standalone examples/api SUBDIRS = $(SUBDIR_TOOLS) ############################################### #定义SUBDIR_TOOLS SUBDIR_EXAMPLES 和 SUBDIRS ############################################### .PHONY : $(SUBDIRS) $(VERSION_FILE) $(TIMESTAMP_FILE) ######################## #定义几个伪目标 ######################## ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk)) # Include autoconf.mk before config.mk so that the config options are available # to all top level build files. We need the dummy all: target to prevent the # dependency target in autoconf.mk.dep from being the default. all: sinclude $(obj)include/autoconf.mk.dep sinclude $(obj)include/autoconf.mk ################################################################################### #包含auoconf.mk和autoconf.mk.dep文件 ################################################################################### ifndef CONFIG_SANDBOX SUBDIRS += $(SUBDIR_EXAMPLES) endif ################################### #追加SUBDIRS 为"tools examples/standalone examples/api" ################################### # load ARCH, BOARD, and CPU configuration include $(obj)include/config.mk export ARCH CPU BOARD VENDOR SOC ####################################### #包含include/config.mk文件,这个文件是在make xxx_config过程中产生的 ####################################### # set default to nothing for native builds ifeq ($(HOSTARCH),$(ARCH)) CROSS_COMPILE ?= endif ####################################### #看看注释就知道了,但是很显示我们的HOSTARCH是x86的,目标时arm的 ######################################## # load other configuration include $(TOPDIR)/config.mk ####################################### #包含uboot顶层目录的config.mk文件 ####################################### # If board code explicitly specified LDSCRIPT or CONFIG_SYS_LDSCRIPT, use # that (or fail if absent). Otherwise, search for a linker script in a # standard location. LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT)) ############################################################################## #用等号赋值的变量是递归方式扩展的变量。变量定义时,变量值中对其他变量的引用不会被替换展开; #而是变量在引用它的地方替换展开的同时,它所引用的其它变量才会被一同替换展开。 #其优点是: #这种类型变量在定义时,可以引用其它的之前没有定义的变量(可能在后续部分定义,或者是通过make的命令行选项传递的变量)。 #LDSCRIPT变量就是后面才定义的 ############################################################################## ifndef LDSCRIPT #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug ifdef CONFIG_SYS_LDSCRIPT # need to strip off double quotes LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT)) endif endif ####################################################################################### #如果定义了CONFIG_SYS_LDSCRIPT,将CONFIG_SYS_LDSCRIPT代表的字符串去掉双引号后赋值给LDSCRIPT变量 #这里我们并没有定义CONFIG_SYS_LDSCRIPT ####################################################################################### # If there is no specified link script, we look in a number of places for it ifndef LDSCRIPT ifeq ($(CONFIG_NAND_U_BOOT),y) LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds endif endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds endif ifeq ($(wildcard $(LDSCRIPT)),) LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds # We don't expect a Makefile here LDSCRIPT_MAKEFILE_DIR = endif ifeq ($(wildcard $(LDSCRIPT)),) $(error could not find linker script) endif endif ########################################################################################## #注释写的很明确,如果没有用CONFIG_SYS_LDSCRIPT指定LDSCRIPT,那么就在几个地方搜 #第一个地方:如果CONFIG_NAND_U_BOOT是y,就用u-boot-nand.lds 但是这里没有这个定义 #第一个地方没找到,就找第二个地方:u-boot-2012.07/board/samsung/smdk2410 这个目录没有u-boot.lds文件 #第二个地方没找到,就找第三个地方:其中CPUDIR是在顶层的config.mk中定义的,在arch/arm/cpu/arm920t中找 这个目录也没有 #第三个地方没找到,就找第四个地方:arch/arm/cpu/u-boot.lds,这里就找到了!!!! ########################################################################################## ######################################################################### # U-Boot objects....order is important (i.e. start must be first) OBJS = $(CPUDIR)/start.o ifeq ($(CPU),x86) OBJS += $(CPUDIR)/start16.o OBJS += $(CPUDIR)/resetvec.o endif ifeq ($(CPU),ppc4xx) OBJS += $(CPUDIR)/resetvec.o endif ifeq ($(CPU),mpc85xx) OBJS += $(CPUDIR)/resetvec.o endif OBJS := $(addprefix $(obj),$(OBJS)) ##################################### #为OBJS增加前缀,其中obj在顶层目录的config.mk中定义,这里根据实际情况 OBJS就是 arch/arm/cpu/arm920t/start.o ##################################### LIBS = lib/libgeneric.o LIBS += lib/lzma/liblzma.o LIBS += lib/lzo/liblzo.o LIBS += lib/zlib/libz.o ifeq ($(CONFIG_TIZEN),y) LIBS += lib/tizen/libtizen.o endif LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \ "board/$(VENDOR)/common/lib$(VENDOR).o"; fi) LIBS += $(CPUDIR)/lib$(CPU).o ifdef SOC LIBS += $(CPUDIR)/$(SOC)/lib$(SOC).o endif ifeq ($(CPU),ixp) LIBS += arch/arm/cpu/ixp/npe/libnpe.o endif ifeq ($(CONFIG_OF_EMBED),y) LIBS += dts/libdts.o endif LIBS += arch/$(ARCH)/lib/lib$(ARCH).o LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \ fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \ fs/ubifs/libubifs.o LIBS += net/libnet.o LIBS += disk/libdisk.o LIBS += drivers/bios_emulator/libatibiosemu.o LIBS += drivers/block/libblock.o LIBS += drivers/dma/libdma.o LIBS += drivers/fpga/libfpga.o LIBS += drivers/gpio/libgpio.o LIBS += drivers/hwmon/libhwmon.o LIBS += drivers/i2c/libi2c.o LIBS += drivers/input/libinput.o LIBS += drivers/misc/libmisc.o LIBS += drivers/mmc/libmmc.o LIBS += drivers/mtd/libmtd.o LIBS += drivers/mtd/nand/libnand.o LIBS += drivers/mtd/onenand/libonenand.o LIBS += drivers/mtd/ubi/libubi.o LIBS += drivers/mtd/spi/libspi_flash.o LIBS += drivers/net/libnet.o LIBS += drivers/net/phy/libphy.o LIBS += drivers/pci/libpci.o LIBS += drivers/pcmcia/libpcmcia.o LIBS += drivers/power/libpower.o LIBS += drivers/spi/libspi.o ifeq ($(CPU),mpc83xx) LIBS += drivers/qe/libqe.o LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o endif ifeq ($(CPU),mpc85xx) LIBS += drivers/qe/libqe.o LIBS += drivers/net/fm/libfm.o LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o endif ifeq ($(CPU),mpc86xx) LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o endif LIBS += drivers/rtc/librtc.o LIBS += drivers/serial/libserial.o ifeq ($(CONFIG_GENERIC_LPC_TPM),y) LIBS += drivers/tpm/libtpm.o endif LIBS += drivers/twserial/libtws.o LIBS += drivers/usb/eth/libusb_eth.o LIBS += drivers/usb/gadget/libusb_gadget.o LIBS += drivers/usb/host/libusb_host.o LIBS += drivers/usb/musb/libusb_musb.o LIBS += drivers/usb/phy/libusb_phy.o LIBS += drivers/usb/ulpi/libusb_ulpi.o LIBS += drivers/video/libvideo.o LIBS += drivers/watchdog/libwatchdog.o LIBS += common/libcommon.o LIBS += lib/libfdt/libfdt.o LIBS += api/libapi.o LIBS += post/libpost.o ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) LIBS += $(CPUDIR)/omap-common/libomap-common.o endif ifeq ($(SOC),mx5) LIBS += $(CPUDIR)/imx-common/libimx-common.o endif ifeq ($(SOC),mx6) LIBS += $(CPUDIR)/imx-common/libimx-common.o endif ifeq ($(SOC),s5pc1xx) LIBS += $(CPUDIR)/s5p-common/libs5p-common.o endif ifeq ($(SOC),exynos) LIBS += $(CPUDIR)/s5p-common/libs5p-common.o endif LIBS := $(addprefix $(obj),$(sort $(LIBS))) ######################################## #将LIBS排序后为LIBS增加前缀 ######################################### .PHONY : $(LIBS) LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).o LIBBOARD := $(addprefix $(obj),$(LIBBOARD)) ########################################### #为LIBBOARD增加前缀,LIBBOARD就是board/samsung/smdk2410/libsmdk2410.o ########################################### # Add GCC lib ifdef USE_PRIVATE_LIBGCC ifeq ("$(USE_PRIVATE_LIBGCC)", "yes") PLATFORM_LIBGCC = $(OBJTREE)/arch/$(ARCH)/lib/libgcc.o else PLATFORM_LIBGCC = -L $(USE_PRIVATE_LIBGCC) -lgcc endif else PLATFORM_LIBGCC := -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc endif PLATFORM_LIBS += $(PLATFORM_LIBGCC) export PLATFORM_LIBS # Special flags for CPP when processing the linker script. # Pass the version down so we can handle backwards compatibility # on the fly. LDPPFLAGS += \ -include $(TOPDIR)/include/u-boot/u-boot.lds.h \ -DCPUDIR=$(CPUDIR) \ $(shell $(LD) --version | \ sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p') __OBJS := $(subst $(obj),,$(OBJS)) __LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD)) ######################################################################### ######################################################################### ifneq ($(CONFIG_BOARD_SIZE_LIMIT),) BOARD_SIZE_CHECK = \ @actual=`wc -c $@ | awk '{print $$1}'`; \ limit=$(CONFIG_BOARD_SIZE_LIMIT); \ if test $$actual -gt $$limit; then \ echo "$@ exceeds file size limit:"; \ echo " limit: $$limit bytes"; \ echo " actual: $$actual bytes"; \ echo " excess: $$((actual - limit)) bytes"; \ exit 1; \ fi else BOARD_SIZE_CHECK = endif
这里也给出顶层目录下的config.mk文件的注释:
# # (C) Copyright 2000-2006 # Wolfgang Denk, DENX Software Engineering, [email protected]. # # 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 Foundation; 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 # ######################################################################### ifeq ($(CURDIR),$(SRCTREE)) dir := else dir := $(subst $(SRCTREE)/,,$(CURDIR)) endif ########################################################################### #在顶层makefile中已经分析了CURDIR和SRCTREE都是当前目录,所以这里dir暂时为空 ########################################################################### ifneq ($(OBJTREE),$(SRCTREE)) # Create object files for SPL in a separate directory ifeq ($(CONFIG_SPL_BUILD),y) obj := $(if $(dir),$(SPLTREE)/$(dir)/,$(SPLTREE)/) else obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/) endif src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/) $(shell mkdir -p $(obj)) else # Create object files for SPL in a separate directory ifeq ($(CONFIG_SPL_BUILD),y) obj := $(if $(dir),$(SPLTREE)/$(dir)/,$(SPLTREE)/) $(shell mkdir -p $(obj)) else obj := endif src := endif ######################################################################################## #首先OBJTREE和SRCTREE都是当前目录,所以执行else #查找CONFIG_SPL_BUILD是否定义为y,在autoconf.mk中,并没有这个定义,所以obj和src暂时也为空 ######################################################################################## # clean the slate ... PLATFORM_RELFLAGS = PLATFORM_CPPFLAGS = PLATFORM_LDFLAGS = ######################################################################### HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer \ $(HOSTCPPFLAGS) HOSTSTRIP = strip # # Mac OS X / Darwin's C preprocessor is Apple specific. It # generates numerous errors and warnings. We want to bypass it # and use GNU C's cpp. To do this we pass the -traditional-cpp # option to the compiler. Note that the -traditional-cpp flag # DOES NOT have the same semantics as GNU C's flag, all it does # is invoke the GNU preprocessor in stock ANSI/ISO C fashion. # # Apple's linker is similar, thanks to the new 2 stage linking # multiple symbol definitions are treated as errors, hence the # -multiply_defined suppress option to turn off this error. # ifeq ($(HOSTOS),darwin) # get major and minor product version (e.g. '10' and '6' for Snow Leopard) DARWIN_MAJOR_VERSION = $(shell sw_vers -productVersion | cut -f 1 -d '.') DARWIN_MINOR_VERSION = $(shell sw_vers -productVersion | cut -f 2 -d '.') os_x_before = $(shell if [ $(DARWIN_MAJOR_VERSION) -le $(1) -a \ $(DARWIN_MINOR_VERSION) -le $(2) ] ; then echo "$(3)"; else echo "$(4)"; fi ;) # Snow Leopards build environment has no longer restrictions as described above HOSTCC = $(call os_x_before, 10, 5, "cc", "gcc") HOSTCFLAGS += $(call os_x_before, 10, 4, "-traditional-cpp") HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress") else HOSTCC = gcc endif ifeq ($(HOSTOS),cygwin) HOSTCFLAGS += -ansi endif # We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of # exceptions for files that aren't complaint. HOSTCFLAGS_NOPED = $(filter-out -pedantic,$(HOSTCFLAGS)) HOSTCFLAGS += -pedantic ############################################################ #HOSTCFLAGS_NOPED是利用filter-out函数从HOSTCFLAGS中过滤掉-pedantic选项 #而HOSTCFLAGS追加上-pedantic选项 ############################################################ ######################################################################### # # Option checker, gcc version (courtesy linux kernel) to ensure # only supported compiler options are used # CC_OPTIONS_CACHE_FILE := $(OBJTREE)/include/generated/cc_options.mk CC_TEST_OFILE := $(OBJTREE)/include/generated/cc_test_file.o -include $(CC_OPTIONS_CACHE_FILE) ############################################################################# #定义编译选项 #在cc_options.mk中有如下选项: # CC_OPTIONS += -marm # CC_OPTIONS += -mno-thumb-interwork # CC_OPTIONS += -mapcs-32 # CC_OPTIONS += -malignment-traps # CC_OPTIONS += -Wno-format-nonliteral # CC_OPTIONS += -Wno-format-security # CC_OPTIONS += -mabi=apcs-gnu # CC_OPTIONS += -mabi=aapcs-linux ############################################################################# cc-option-sys = $(shell mkdir -p $(dir $(CC_TEST_OFILE)); \ if $(CC) $(CFLAGS) $(1) -S -xc /dev/null -o $(CC_TEST_OFILE) \ > /dev/null 2>&1; then \ echo 'CC_OPTIONS += $(strip $1)' >> $(CC_OPTIONS_CACHE_FILE); \ echo "$(1)"; fi) ifeq ($(CONFIG_CC_OPT_CACHE_DISABLE),y) cc-option = $(strip $(if $(call cc-option-sys,$1),$1,$2)) else cc-option = $(strip $(if $(findstring $1,$(CC_OPTIONS)),$1,\ $(if $(call cc-option-sys,$1),$1,$2))) endif ########################################################################################### #定义两个函数,cc-option-sys被cc-option调用 #cc-option被后面的函数调用 ############################################################################################ # cc-version # Usage gcc-ver := $(call cc-version) cc-version = $(shell $(SHELL) $(SRCTREE)/tools/gcc-version.sh $(CC)) ########################################################################################## #使用tools/gcc-version.sh脚本来获取编译器的版本 #在顶层makefile中,有调用cc-version函数 ########################################################################################## # # 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 DTC = dtc ######################################################################### #定义汇编器,连接器,编译器,打包工具,反汇编工具,值的注意的RANLIB的作用是在静态库有添加新的.o后,负责更新索引. ######################################################################### # Load generated board configuration sinclude $(OBJTREE)/include/autoconf.mk sinclude $(OBJTREE)/include/config.mk ################################################################################################ #包上配置编译时产生的autoconf.mk和config.mk文件 ################################################################################################ # Some architecture config.mk files need to know what CPUDIR is set to, # so calculate CPUDIR before including ARCH/SOC/CPU config.mk files. # Check if arch/$ARCH/cpu/$CPU exists, otherwise assume arch/$ARCH/cpu contains # CPU-specific code. CPUDIR=arch/$(ARCH)/cpu/$(CPU) ifneq ($(SRCTREE)/$(CPUDIR),$(wildcard $(SRCTREE)/$(CPUDIR))) CPUDIR=arch/$(ARCH)/cpu endif ################################################################################################# #定义CPUDIR为arch/arm/cpu/arm920t ################################################################################################# sinclude $(TOPDIR)/arch/$(ARCH)/config.mk # include architecture dependend rules sinclude $(TOPDIR)/$(CPUDIR)/config.mk # include CPU specific rules ################################################################################################## #包上arch/arm/config.mk和/arch/arm/cpu/arm920t/config.mk文件 ################################################################################################## ifdef SOC sinclude $(TOPDIR)/$(CPUDIR)/$(SOC)/config.mk # include SoC specific rules endif ###################################################################### #包上arch/arm/cpu/arm920t/s3c24x0/config.mk文件 ##################################################################### ifdef VENDOR BOARDDIR = $(VENDOR)/$(BOARD) else BOARDDIR = $(BOARD) endif ifdef BOARD sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules endif ###################################################################################### #包上board/samsung/smdk2410/config.mk文件 ###################################################################################### ######################################################################### # We don't actually use $(ARFLAGS) anywhere anymore, so catch people # who are porting old code to latest mainline but not updating $(AR). ARFLAGS = $(error update your Makefile to use cmd_link_o_target and not AR) RELFLAGS= $(PLATFORM_RELFLAGS) DBGFLAGS= -g # -DDEBUG OPTFLAGS= -Os #-fomit-frame-pointer OBJCFLAGS += --gap-fill=0xff gccincdir := $(shell $(CC) -print-file-name=include) CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \ -D__KERNEL__ # Enable garbage collection of un-used sections for SPL ifeq ($(CONFIG_SPL_BUILD),y) CPPFLAGS += -ffunction-sections -fdata-sections LDFLAGS_FINAL += --gc-sections endif ifneq ($(CONFIG_SYS_TEXT_BASE),) CPPFLAGS += -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE) endif ifneq ($(CONFIG_SPL_TEXT_BASE),) CPPFLAGS += -DCONFIG_SPL_TEXT_BASE=$(CONFIG_SPL_TEXT_BASE) endif ifneq ($(CONFIG_SPL_PAD_TO),) CPPFLAGS += -DCONFIG_SPL_PAD_TO=$(CONFIG_SPL_PAD_TO) endif ifeq ($(CONFIG_SPL_BUILD),y) CPPFLAGS += -DCONFIG_SPL_BUILD endif ifneq ($(RESET_VECTOR_ADDRESS),) CPPFLAGS += -DRESET_VECTOR_ADDRESS=$(RESET_VECTOR_ADDRESS) endif ifneq ($(OBJTREE),$(SRCTREE)) CPPFLAGS += -I$(OBJTREE)/include2 -I$(OBJTREE)/include endif CPPFLAGS += -I$(TOPDIR)/include CPPFLAGS += -fno-builtin -ffreestanding -nostdinc \ -isystem $(gccincdir) -pipe $(PLATFORM_CPPFLAGS) ifdef BUILD_TAG CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \ -DBUILD_TAG='"$(BUILD_TAG)"' else CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes endif CFLAGS_SSP := $(call cc-option,-fno-stack-protector) CFLAGS += $(CFLAGS_SSP) # Some toolchains enable security related warning flags by default, # but they don't make much sense in the u-boot world, so disable them. CFLAGS_WARN := $(call cc-option,-Wno-format-nonliteral) \ $(call cc-option,-Wno-format-security) CFLAGS += $(CFLAGS_WARN) # Report stack usage if supported CFLAGS_STACK := $(call cc-option,-fstack-usage) CFLAGS += $(CFLAGS_STACK) # $(CPPFLAGS) sets -g, which causes gcc to pass a suitable -g<format> # option to the assembler. AFLAGS_DEBUG := # turn jbsr into jsr for m68k ifeq ($(ARCH),m68k) ifeq ($(findstring 3.4,$(shell $(CC) --version)),3.4) AFLAGS_DEBUG := -Wa,-gstabs,-S endif endif AFLAGS := $(AFLAGS_DEBUG) -D__ASSEMBLY__ $(CPPFLAGS) LDFLAGS += $(PLATFORM_LDFLAGS) LDFLAGS_FINAL += -Bstatic LDFLAGS_u-boot += -T $(obj)u-boot.lds $(LDFLAGS_FINAL) ifneq ($(CONFIG_SYS_TEXT_BASE),) LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE) endif LDFLAGS_u-boot-spl += -T $(obj)u-boot-spl.lds $(LDFLAGS_FINAL) ifneq ($(CONFIG_SPL_TEXT_BASE),) LDFLAGS_u-boot-spl += -Ttext $(CONFIG_SPL_TEXT_BASE) endif # Location of a usable BFD library, where we define "usable" as # "built for ${HOST}, supports ${TARGET}". Sensible values are # - When cross-compiling: the root of the cross-environment # - Linux/ppc (native): /usr # - NetBSD/ppc (native): you lose ... (must extract these from the # binutils build directory, plus the native and U-Boot include # files don't like each other) # # So far, this is used only by tools/gdb/Makefile. ifeq ($(HOSTOS),darwin) BFD_ROOT_DIR = /usr/local/tools else ifeq ($(HOSTARCH),$(ARCH)) # native BFD_ROOT_DIR = /usr else #BFD_ROOT_DIR = /LinuxPPC/CDK # Linux/i386 #BFD_ROOT_DIR = /usr/pkg/cross # NetBSD/i386 BFD_ROOT_DIR = /opt/powerpc endif endif ######################################################################### export HOSTCC HOSTCFLAGS HOSTLDFLAGS PEDCFLAGS HOSTSTRIP CROSS_COMPILE \ AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP MAKE export CONFIG_SYS_TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS ######################################################################### # Allow boards to use custom optimize flags on a per dir/file basis BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%)) ALL_AFLAGS = $(AFLAGS) $(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR)) ALL_CFLAGS = $(CFLAGS) $(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR)) EXTRA_CPPFLAGS = $(CPPFLAGS_$(BCURDIR)/$(@F)) $(CPPFLAGS_$(BCURDIR)) ALL_CFLAGS += $(EXTRA_CPPFLAGS) # The _DEP version uses the $< file target (for dependency generation) # See rules.mk EXTRA_CPPFLAGS_DEP = $(CPPFLAGS_$(BCURDIR)/$(addsuffix .o,$(basename $<))) \ $(CPPFLAGS_$(BCURDIR)) $(obj)%.s: %.S $(CPP) $(ALL_AFLAGS) -o $@ $< $(obj)%.o: %.S $(CC) $(ALL_AFLAGS) -o $@ $< -c $(obj)%.o: %.c $(CC) $(ALL_CFLAGS) -o $@ $< -c $(obj)%.i: %.c $(CPP) $(ALL_CFLAGS) -o $@ $< -c $(obj)%.s: %.c $(CC) $(ALL_CFLAGS) -o $@ $< -c -S ######################################################################### # If the list of objects to link is empty, just create an empty built-in.o cmd_link_o_target = $(if $(strip $1),\ $(LD) $(LDFLAGS) -r -o $@ $1,\ rm -f $@; $(AR) rcs $@ ) #########################################################################
最后分析下make:
$(obj)include/autoconf.mk.dep: $(obj)include/config.h include/common.h @$(XECHO) Generating $@ ; \ set -e ; \ : Generate the dependancies ; \ $(CC) -x c -DDO_DEPS_ONLY -M $(CFLAGS) $(CPPFLAGS) \ -MQ $(obj)include/autoconf.mk include/common.h > $@ $(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 > [email protected] && \ mv [email protected] $@第一个是生成include/autoconf.mk的依赖文件
第二个是根据include/config.h的文件内容,利用tools/scripts/define2mk.sed脚本将所有的CONFIG提取到autoconf.mk文件中
终极目标是:ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
u-boot.srec也是根据u-boot用objcopy工具搞出来的,不知的什么作用
u-boot.bin也是根据u-boot用objcopy工具搞出来的,最终烧写的二进制bin档
System.map是符号列表
$(obj)u-boot.bin: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ $(BOARD_SIZE_CHECK) ################################################################################### #要得到最后的u-boot.bin,必须得到u-boot.u-boot.bin是最后要烧写到板子上的二进制bin档 #利用objcopy来得到这个二进制文件($@是规则的目标文件名,$<是规则的第一个依赖文件名) #调用BOARD_SIZE_CHECK ###################################################################################