1.make at91rm9200dk_config
2.make all arm
以上两步是编译u-boot的步骤。
第一步是让make 生成相应的开发板配置。
第二步是让make 生成开发板上所需的所有目标,以及开发cpu目标。
Makefile基本知识:
# CURDIR这个变量是Makefile提供的,代表了make当前的工作路径。
现在先从第一步开始分析:
前面关于变量的设定比较简单。主要部分还是ifdef config.mk else 的大语句。
#########################################################################
## Atmel AT91RM9200 Systems
#########################################################################
at91rm9200dk_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t at91rm9200dk atmel at91rm9200
$(@:_config=) 的意思是讲_config 替换为空
at91rm9200dk_config 目标对应的规则如上:
@$(MKCONFIG) 的定义可以由以下几句推导出来,即Makefile 所在目录下的mkconfig.
SRCTREE := $(CURDIR)
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
接下来继续分析mkconfig:
# Script to create header files and links to configure
# U-Boot for a specific board.
# 这是一个用于为特定开发板创建头文件和连接的脚本
# Parameters: Target Architecture CPU Board [VENDOR] [SOC]
APPEND=no # Default: Create new config file 每次都创建新的配置文件
BOARD_NAME="" # Name to print in make output 开发板的名字
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;; #如果第一个参数为-- 什么也不做
-a) shift ; APPEND=yes ;; #如果第一个参数为-a 则在原有的config.h上添加内容
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;; #如果是-n,则把开发板的名字定义为 $1删除_config后的东西 ##和%%的区别就是一个是从左删除一个从右删除。
*) break ;;
esac
done
[ "${BOARD_NAME}" ] || BOARD_NAME="$1" #设定为board name
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1 #如果参数不在4 和 6之间则退出
#
# Create link to architecture specific headers
#
if [ "$SRCTREE" != "$OBJTREE" ] ; then
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include
rm -f asm
ln -s asm-$2 asm #创建到asm-$2的链接 asm
fi
#创建 arch 链接
rm -f asm-$2/arch
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
#创建proc链接
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
#
# Create include file for Make 创建config.mk文件
#
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
#
# Create board specific header file 创建config.h文件
#
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
总的来说第一步,在include 文件夹下,建立了asm, arch, proc的软链接,创建了一个config.mk文件,一个config.h文件。
第二步分析
make all arm
对于存在config.mk情况下的变量设定:
# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export ARCH CPU BOARD VENDOR SOC
# load other configuration 包含CPU、板级的配置文件,设定编译选项,链接选项,编译规则
include $(TOPDIR)/config.mk
#########################################################################
# U-Boot objects....order is important (i.e. start must be first)
OBJS = cpu/$(CPU)/start.o
OBJS := $(addprefix $(obj),$(OBJS))
LIBS = lib_generic/libgeneric.a
#CPU ,片上系统和体系结构的库
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).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
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/spi/libspi_flash.a
LIBS += drivers/net/libnet.a
LIBS += drivers/net/sk98lin/libsk98lin.a
LIBS += drivers/pci/libpci.a
LIBS += drivers/pcmcia/libpcmcia.a
LIBS += drivers/spi/libspi.a
LIBS += drivers/rtc/librtc.a
LIBS += drivers/serial/libserial.a
LIBS += drivers/usb/libusb.a
LIBS += drivers/video/libvideo.a
#其他类型的库
LIBS += common/libcommon.a
LIBS += libfdt/libfdt.a
LIBS += api/libapi.a
LIBS += post/libpost.a
LIBS := $(addprefix $(obj),$(LIBS))
LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a
LIBBOARD := $(addprefix $(obj),$(LIBBOARD))
# Add GCC lib
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
ifeq ($(CONFIG_NAND_U_BOOT),y)
NAND_SPL = nand_spl
U_BOOT_NAND = $(obj)u-boot-nand.bin
endif
ifeq ($(CONFIG_ONENAND_U_BOOT),y)
ONENAND_IPL = onenand_ipl
U_BOOT_ONENAND = $(obj)u-boot-onenand.bin
endif
__OBJS := $(subst $(obj),,$(OBJS))
__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
目标 all以及根据依赖规则导出的所有相关目标,从上到下的方法。
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)
ifeq ($(ARCH),blackfin)
ALL += $(obj)u-boot.ldr
endif
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.ldr: $(obj)u-boot
$(LDR) -T $(CONFIG_BFIN_CPU) -f -c $@ $< $(LDR_FLAGS)
$(obj)u-boot.ldr.hex: $(obj)u-boot.ldr
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ -I binary
$(obj)u-boot.ldr.srec: $(obj)u-boot.ldr
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ -I binary
$(obj)u-boot.img: $(obj)u-boot.bin
./tools/mkimage -A $(ARCH) -T firmware -C none /
-a $(TEXT_BASE) -e 0 /
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | /
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') /
-d $< $@
$(obj)u-boot.sha1: $(obj)u-boot.bin
$(obj)tools/ubsha1 $(obj)u-boot.bin
$(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
$(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | /
sed -n -e 's/.*/($(SYM_PREFIX)__u_boot_cmd_.*/)/-u/1/p'|sort|uniq`;/
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) /
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) /
-Map u-boot.map -o u-boot
#需要注意的是链接中使用了LDFLAGS,LDFLAGS的具体值可以参考下面在config.mk的中定义。其中最重要的两点是
#1. 定义了一个相关board的链接脚本
#2. -Ttext $(TEXT_BASE) 定义了text section 的起始地址,覆盖了链接脚本中的起始地址0x000.
#对于at91RM9200dkconfig 来说,text的起始地址定义在board/atmel/at91rm9200dk/config.mk 中
TEXT_BASE = 0x21f00000
$(OBJS): depend $(obj)include/autoconf.mk
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS): depend $(obj)include/autoconf.mk
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(LIBBOARD): depend $(LIBS) $(obj)include/autoconf.mk
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS): depend $(obj)include/autoconf.mk
$(MAKE) -C $@ all
$(LDSCRIPT): depend $(obj)include/autoconf.mk
$(MAKE) -C $(dir $@) $(notdir $@)
$(NAND_SPL): $(VERSION_FILE) $(obj)include/autoconf.mk
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin $(obj)include/autoconf.mk
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
$(ONENAND_IPL): $(VERSION_FILE) $(obj)include/autoconf.mk
$(MAKE) -C onenand_ipl/board/$(BOARDDIR) all
$(U_BOOT_ONENAND): $(ONENAND_IPL) $(obj)u-boot.bin $(obj)include/autoconf.mk
cat $(obj)onenand_ipl/onenand-ipl-2k.bin $(obj)u-boot.bin > $(obj)u-boot-onenand.bin
cat $(obj)onenand_ipl/onenand-ipl-4k.bin $(obj)u-boot.bin > $(obj)u-boot-flexonenand.bin
$(VERSION_FILE):
@( printf '#define U_BOOT_VERSION "U-Boot %s%s"/n' "$(U_BOOT_VERSION)" /
'$(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion $(TOPDIR))' /
) > [email protected]
@cmp -s $@ [email protected] && rm -f [email protected] || mv -f [email protected] $@
gdbtools:
$(MAKE) -C tools/gdb all || exit 1
updater:
$(MAKE) -C tools/updater all || exit 1
env:
$(MAKE) -C tools/env all MTD_VERSION=${MTD_VERSION} || exit 1
depend dep: $(VERSION_FILE)
for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
#
# Auto-generate the autoconf.mk file (which is included by all makefiles)
#
# This target actually generates 2 files; autoconf.mk and autoconf.mk.dep.
# the dep file is only include in this top level makefile to determine when
# to regenerate the autoconf.mk file.
$(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 $(HOST_CFLAGS) $(CPPFLAGS) /
-MQ $(obj)include/autoconf.mk include/common.h > $@
#通过对include/common.h文件预处理后输出的内容进行SED操作后生成 autoconf.mk
$(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 > $@
sinclude $(obj)include/autoconf.mk.dep
----------------$(TOPDIR)/config.mk 的具体分析----------------
#根据体系结构给变量PLATFROM_CPPFLAGS赋值
ifeq ($(ARCH),arm)
ifeq ($(CROSS_COMPILE),powerpc-netbsd-)
PLATFORM_CPPFLAGS+= -D__ARM__
endif
ifeq ($(CROSS_COMPILE),powerpc-openbsd-)
PLATFORM_CPPFLAGS+= -D__ARM__
endif
endif
#定义与主机相关的一些变量
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; /
else if [ -x /bin/bash ]; then echo /bin/bash; /
else echo sh; fi ; fi)
ifeq ($(HOSTOS)-$(HOSTARCH),darwin-ppc)
HOSTCC = cc
else
HOSTCC = gcc
endif
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTSTRIP = strip
#
# Option checker (courtesy linux kernel) to ensure
# only supported compiler options are used
#
cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null /
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
#
# Include the make variables (CC, etc...)
#根据CROSS_COMPILE定义交叉编译工具的变量
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
# Load generated board configuration
#这个文件时根据include/config.h文件生成的,生成规则在TOP Makefile中
sinclude $(OBJTREE)/include/autoconf.mk
#包含体系结构相关的配置
ifdef ARCH
sinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rules
endif
#包含CPU相关的配置
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include CPU specific rules
endif
#包含与片上系统相关的配置
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk # include SoC specific rules
endif
#包含与板级配置相关的配置
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
endif
#定义AR命令选项的变量
ifneq (,$(findstring s,$(MAKEFLAGS)))
ARFLAGS = cr
else
ARFLAGS = crv
endif
RELFLAGS= $(PLATFORM_RELFLAGS)
#定义调式选项变量
DBGFLAGS= -g # -DDEBUG
#定义优化选项变量
OPTFLAGS= -Os
#定义LDSCRIPT变量,这个跟板级配置相关
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
OBJCFLAGS += --gap-fill=0xff
#定义GCC的include 文件所在路径
gccincdir := $(shell $(CC) -print-file-name=include)
#定义C++预编译选项
CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) /
-D__KERNEL__
ifneq ($(TEXT_BASE),)
CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
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)
#定义C编译选项
ifdef BUILD_TAG
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes /
-DBUILD_TAG='"$(BUILD_TAG)"'
else
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes
endif
CFLAGS += $(call cc-option,-fno-stack-protector)
# avoid trigraph warnings while parsing pci.h (produced by NIOS gcc-2.9)
# this option have to be placed behind -Wall -- that's why it is here
ifeq ($(ARCH),nios)
ifeq ($(findstring 2.9,$(shell $(CC) --version)),2.9)
CFLAGS := $(CPPFLAGS) -Wall -Wno-trigraphs
endif
endif
#定义汇编选项变量
# $(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 += -Bstatic -T $(LDSCRIPT) $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(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)-$(HOSTARCH),darwin-ppc)
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
ifeq ($(PCI_CLOCK),PCI_66M)
CFLAGS := $(CFLAGS) -DPCI_66M
endif
#导出上述定义的变量到Shell中去
#########################################################################
export CONFIG_SHELL HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE /
AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP /
MAKE
export TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS
#########################################################################
#定义编译规则
$(obj)%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
$(obj)%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<