上一篇文章《u-boot的配置》了解了u-boot的配置过程,配置完成后,我们只需要一条简单的指令:
make all
就能实现对u-boot的编译,Makefile也类似于C编程,先包含一些头文件,或者引用一些标志,
我们先来分析哪些文件会先被引用:
# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export ARCH CPU BOARD VENDOR SOC
# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
# load other configuration
include $(TOPDIR)/config.mk
① 先包含u-boot配置生成的config.mk文件, 在/include/目录下,相当于确定了ARCH、CPU、BOARD、VENDOR、SOC
② 设定默认的交叉编译器
③ 加载顶层目录下的config.mk,它会根据①中的几个配置变量来确定编译器、编译选项,对我们理解有帮助的是BOARDDIR、 LDFLAGS的 值,内容如下:
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
endif
这说明BOARDDIR(移值开发板目录)的值为/freescale/mx31ads
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
说明LDSCRIPT(移值开发板的lds文件目录),这个 取决于配置,一般是u-boot.lds。包含了该文件,自然也就知道了u-boot的加载SDRAM的地址分配。
LDFLAGS += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif
所以LDFLAGS(u-boot加载地址标志)为:
LDFLAGS = -T board/ freescale/mx31ads/u-boot.lds -Ttext 0xxxxxx
上面的功能是“包含”和“引用”,接下来看,依赖对象:
OBJS = cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),ppc4xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
OBJS := $(addprefix $(obj),$(OBJS))
LIBS = lib_generic/libgeneric.a
LIBS += lib_generic/lzma/liblzma.a
LIBS += lib_generic/lzo/liblzo.a
LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
"board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
ifeq ($(CPU),ixp)
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/yaffs2/libyaffs2.a \
fs/ubifs/libubifs.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/fpga/libfpga.a
LIBS += drivers/gpio/libgpio.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/onenand/libonenand.a
LIBS += drivers/mtd/ubi/libubi.a
LIBS += drivers/mtd/spi/libspi_flash.a
LIBS += drivers/net/libnet.a
LIBS += drivers/net/phy/libphy.a
LIBS += drivers/net/sk98lin/libsk98lin.a
LIBS += drivers/pci/libpci.a
LIBS += drivers/pcmcia/libpcmcia.a
LIBS += drivers/power/libpower.a
LIBS += drivers/spi/libspi.a
ifeq ($(CPU),mpc83xx)
LIBS += drivers/qe/qe.a
endif
ifeq ($(CPU),mpc85xx)
LIBS += drivers/qe/qe.a
LIBS += cpu/mpc8xxx/ddr/libddr.a
TAG_SUBDIRS += cpu/mpc8xxx
endif
ifeq ($(CPU),mpc86xx)
LIBS += cpu/mpc8xxx/ddr/libddr.a
TAG_SUBDIRS += cpu/mpc8xxx
endif
LIBS += drivers/rtc/librtc.a
LIBS += drivers/serial/libserial.a
LIBS += drivers/twserial/libtws.a
LIBS += drivers/usb/gadget/libusb_gadget.a
LIBS += drivers/usb/host/libusb_host.a
LIBS += drivers/usb/musb/libusb_musb.a
LIBS += drivers/video/libvideo.a
LIBS += drivers/watchdog/libwatchdog.a
LIBS += common/libcommon.a
LIBS += libfdt/libfdt.a
LIBS += api/libapi.a
LIBS += post/libpost.a
从上面可以了解到,主要是依赖对象文件的定义,以及依赖库文件的定义。
OBJS的第一个值为“cpu/$(CPU)/start.o”,后面的LIBS就是平台、开发板相关的各个目录相应的文件,自然少不了/board/freescale/mx31ads/xxx文件。
OBJS、LIBS所代表的.o、.a文件就是u-boot的构成,它们由相应的源文件编译得到,对应的依赖关系如下:
$(OBJS): depend
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS): depend $(SUBDIRS)
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(LIBBOARD): depend $(LIBS)
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS): depend
$(MAKE) -C $@ all
现在OBJS对应\cpu\arm926ejs\start.S, LIBS自然对应前面的定义的文件。
当所有的OBJS、LIBS所表示的.o和.a文件都生成,接着就可以进行“连接”了,如下所示:
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(obj)u-boot.ldr: $(obj)u-boot
$(obj)tools/envcrc --binary > $(obj)env-ldr.o
$(LDR) -T $(CONFIG_BFIN_CPU) -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 $< $@
通过正规表达式,可以生成u-boot的各种工程格式。
编译流程总结:
(1)首先编译cpu/$(CPU)/start.S.
(2)对于平台、开发板相关的每个目录,每个通用目录都使用它们各自的Makefile生成相应的库文件。
(3)将前两部生成.o、.a文件按照board/$(BOARDDIR)/config.mk(也就是要移值的开发板的.mk文件)文件中指定的代码段起始地址、u-boot.lds连接脚本进行连接。
(4)上一步得到的是ELF格式的u-boot,再根据需要生成转换其他的格式。