uboot为用户提供两种编译方式,一种是在uboot当前目录下进行编译,第二种方式就是将编译生成的文件输出到指定的目录下。


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.


在这个注释中可以看出uboot的开发者是通过O来指定一个输出目录的,第二种方法又包含两种操作方法

(1)在命令行中添加O=/tmp/build all指定文件输出的位置

这里要注意的是在配置和编译时都要加上O=/tmp/build all来指定目录

路径

(2)先设置环境变量 export BUILD_DIR=/tmp/build(路径可根据自己需要确定),然后make或者在设置完环境变量之后执行MAKEALL脚本./MAKEALL



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})


27~37行代码主要就是针对上述的两种编译方法设计的,当O被我们定义为一个目录时命令$(origin O)会返回"command line",这时BUILD_DIR就

指向我们由O定义的那个目录,如果我们指定的O不是通过" "指定,那么

就由saved-output来指向$(BUILD_DIR)

37行当${BUILD_DIR}目录不存在时,就会建立一个目录,之后进入刚刚创建的目录下,并且显示当前路径,如果返回值为真,则不显示任何信息,否则打印出*** output directory "" does not exist. Stop.这样的信息。


OBJTREE:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))

SRCTREE:= $(CURDIR)

TOPDIR:= $(SRCTREE)

LNDIR:= $(OBJTREE)

exportTOPDIR SRCTREE OBJTREE


定义OBJTREE、SRCTREE、TOPDIR、LNDIR四个变量

如果$(BUILD_DIR)返回值为真,则OBJTREE为$(BUILD_DIR)(我们在开始时指定的那个目录),否则为$(CURDIR)(我们的当前目录,即使uboot根目录),TOPDIR、LNDIR就顺理成章了


MKCONFIG:= $(SRCTREE)/mkconfig

定义变量MKCONFIG,它所指向的就是uboot目录下的mkconfig脚本


ifneq ($(OBJTREE),$(SRCTREE))

obj := $(OBJTREE)/

src := $(SRCTREE)/

else

obj :=

src :=

endif

export obj src


$(obj) and $(src)是在config.mk下定义的两个变量,但是在主Makefile下的一些目标也需要它们,所以就在这里定义它们两个

在进行配置时我们没有指定输出目录,所以这里$(OBJTREE)和$(SRCTREE)相同,故$(obj)和$(src)都为空


ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk))

include $(obj)include/config.mk

exportARCH CPU BOARD VENDOR SOC

当$(obj)include/config.mk按字节展开和$(obj)include/config.mk相同时,包含uboot/include/config.mk


ifndef CROSS_COMPILE

ifeq ($(HOSTARCH),$(ARCH))

CROSS_COMPILE =

else

ifeq ($(ARCH),arm)

#CROSS_COMPILE = arm-linux-

#CROSS_COMPILE = /usr/local/arm/4.4.1-eabi-cortex-a8/usr/bin/arm-linux-

#CROSS_COMPILE = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-

CROSS_COMPILE = /usr/local/ARM/arm-2009q3/bin/arm-none-linux-gnueabi-

endif


开始定义交叉编译工具链,因为我们是编译的ARM架构的代码,所以使用ARM的交叉编译工具。



# load other configuration

include $(TOPDIR)/config.mk

如注释所写,我们需要引入一些其他的配置,所以通过include来包含这些文件,这个文件就是uboot根目录下的config.mk文件

所以下面我们就要转向分析这个config.mk文件,之后再回来分析主Makefile。


#Load generated board configuration

sinclude $(OBJTREE)/include/autoconf.mk


ifdefARCH

sinclude $(TOPDIR)/$(ARCH)_config.mk# include architecture dependend rules

endif

ifdefCPU

sinclude $(TOPDIR)/cpu/$(CPU)/config.mk# include CPUspecific rules

endif

ifdefSOC

sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk# include SoCspecific rules

endif

ifdefVENDOR

BOARDDIR = $(VENDOR)/$(BOARD)

else

BOARDDIR = $(BOARD)

endif

ifdefBOARD

sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk# include board specific rules

endif


89~108引入已经生成的与开发板相关的配置文件

在进行相关配置make x210_sd_config操作时,ARCH、CPU、SOC、VENDOR、BOARD的相关信息

通过@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110这条语句使用uboot下的mkconfig脚本到处到uboot/include/config.mk中,所以这些变量都是已经定义了的将上面代码提及的相关目录下的config.mk文件用sinclude(相当于include)包含起来。


LDFLAGS += -Ttext $(TEXT_BASE) 进行重定位,链接到链接地址


ifndef REMOTE_BUILD


%.s:%.S

$(CPP) $(AFLAGS) -o $@ $<

%.o:%.S

$(CC) $(AFLAGS) -c -o $@ $<

%.o:%.c

$(CC) $(CFLAGS) -c -o $@ $<


else


$(obj)%.s:%.S

$(CPP) $(AFLAGS) -o $@ $<

$(obj)%.o:%.S

$(CC) $(AFLAGS) -c -o $@ $<

$(obj)%.o:%.c

$(CC) $(CFLAGS) -c -o $@ $<

endif


进行Makefile隐式规则推导


现在回到主Makkefile下继续分析:


LIBS += cpu/ixp/npe/libnpe.a

endif

LIBS += lib_$(ARCH)/lib$(ARCH).a

LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \

fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/ext4/libext4fs.a

LIBS += net/libnet.a

LIBS += disk/libdisk.a

LIBS += drivers/bios_emulator/libatibiosemu.a

LIBS += drivers/block/libblock.a

LIBS += drivers/dma/libdma.a

LIBS += drivers/hwmon/libhwmon.a

LIBS += drivers/i2c/libi2c.a

LIBS += drivers/input/libinput.a

LIBS += drivers/misc/libmisc.a

LIBS += drivers/mmc/libmmc.a

LIBS += drivers/mtd/libmtd.a

LIBS += drivers/mtd/nand/libnand.a

LIBS += drivers/mtd/nand_legacy/libnand_legacy.a

LIBS += drivers/mtd/onenand/libonenand.a

LIBS += drivers/mtd/ubi/libubi.a

LIBS += drivers/mtd/spi/libspi_flash.a


上面是类似代码的一小部分,添加相关库文件


ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) $(obj)u-boot.dis

ifeq ($(ARCH),blackfin)

ALL += $(obj)u-boot.ldr

endif


添加make操作的原料,通过执行make命令生成u-boot.srec、u-boot.bin、System.map、u-boot.dis、u-boot.ldr等文件



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

当执行make x210_sd_config时,unconfig作为依赖先被执行,而unconfig又同时是一个目标,作用和我们写简单Makefile中的clean作用相同的,就是删除已经生成的相关的配置文件,这样即使是在已经配置后仍可以在进行配置,因为在进行真正的配置操作时,上次的配置生成的文件已经被删除


在执行配置命令时引入了$(MKCONFIG)这个就是uboot下的mkconfig脚本

$(@:_config=) arm s5pc11x x210 samsung s5pc110 这些是传入mkconfig的参数


这里$(@:_config=)需要解释:这条命令的意思就是将目标字符串中的_config用空字节代替,所以,传入mkconfig中的6个参数为:

x210_sd arm s5pc11x x210 samsung s5pc110

$1 $2 $3 $4 $5 $6


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的结果是匹配到*)跳出while;


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

判断${BOARD_NAME}返回值是否为真,若为假,则BOARD_NAME=$1

在这里BOARD_NAME="" 所以BOARD_NAME=x210_sd


[ $# -lt 4 ] && exit 1

[ $# -gt 6 ] && exit 1

说明传入mkconfig的参数个数为4~6个才能正确执行,否则,会发生错误



if [ "$SRCTREE" != "$OBJTREE" ] ; then

mkdir -p ${OBJTREE}/include

mkdir -p ${OBJTREE}/include2

cd ${OBJTREE}/include2

rm -rf asm

ln -s ${SRCTREE}/include/asm-$2 asm

LNPREFIX="../../include2/asm/"

cd ../include

rm -rf asm-$2

rm -rf asm

mkdir asm-$2

ln -s asm-$2 asm

else

cd ./include

rm -rf asm

ln -s asm-$2 asm

fi


建立一个符号链接 asm -> asm-arm


if [ -z "$6" -o "$6" = "NULL" ] ; then

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

else

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

fi


我们的$6既不是空也不是“NULL”,所以会建立一个链接

asm-arm -> arch-s5pc110


# create link for s5pc11x SoC

if [ "$3" = "s5pc11x" ] ; then

rm -f regs.h

ln -s $6.h regs.h

rm -rf asm-$2/arch

ln -s arch-$3 asm-$2/arch

fi


开始创建与SOC相关的链接 regs.h -> s5pc110.h和

arch -> arch-s5pc11x



# 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



导出 ARCH = arm

CPU = s5pc11x

BOARD = x210

VENDOR = samsung

SOC = s5pc110

到include下的config.mk文件中,注意的是原来在include下是不存在

config.mk文件的,这个文件是由echo创建并传入内容的

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



$APPEND在定义时为no,所以会创建一个新的config.h文件

这个 文件的内容为

/* Automatically generated - do not edit */

#include <configs/x210_sd.h>

这里的configs目录下的x210_sd.h为具体开发板所需要的宏定义,譬如:


#define CONFIG_SECURE_ROOTFS_SIZE 0x0013D000

#endif


#define BOOT_ONENAND 0x1

#define BOOT_NAND 0x2

#define BOOT_MMCSD 0x3

#define BOOT_NOR 0x4

#define BOOT_SEC_DEV 0x5


#define AT070TN92 1

#define VGA_800X600 2

#define VGA_1024X768 3

#define TRULY043 4

#define VGA_1440X900 5

#define VGA_1280X1024 6


#define DISP_MODE AT070TN92

//#define DISP_MODE VGA_800X600

//#define DISP_MODE VGA_1024X768

//#define DISP_MODE VGA_1440X900

//#define DISP_MODE TRULY043

//#define DISP_MODE VGA_1280X1024