主Makefile分析
——uboot源码是由九鼎创展移植的三星S5PV210(s5pc11x)板子的uboot。
uboot的主Makefile在uboot源码的根目录下。
首先是简介,随后是定义了四个变量,用来描述uboot的版本信息。
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h
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/ppc64/ppc/ \
-e s/macppc/ppc/)
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
export HOSTARCH HOSTOS
VERSION表示uboot的版本,PATCHLEVEL表示补丁版本,SUBLEVEL表示次级版本,EXTRAVERSION则是额外信息。
而uboot的总版本U_BOOT_VERSION则是$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)。
下一句根目录的include/version_autogenerated.h里面就存储了版本信息“#define U_BOOT_VERSION "U-Boot 1.3.4"
”这个文件是uboot编译后自动产生的,源码中并没有。
HOSTARCH表示主机架构,HOSTOS表示主机系统。这两个变量导出为外部变量,会在后面、config.mk等地方使用。
接下来是静默编译
MAKEFLAGS是Makefile的一个变量,用来存储flags,即make时附带的参数,静默编译就是make -s
当发现s参数时,Makefile就会将XECHO变量赋值空,不会产生编译信息。(只是不产生Makefile的编译信息,其他的CC、LD等工具还是会产生编译、链接等信息。)
# Allow for silent builds
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif
接下来是两种编译方式:原地编译和单独输出文件夹编译
# 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
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),)
上面都对应着单独输出的文件夹的建立和检查。需要注意的是下面的代码中定义的几个变量TOPDIR SRCTREE OBJTREE
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE)
LNDIR := $(OBJTREE)
export TOPDIR SRCTREE OBJTREE
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
TOPDIR SRCTREE OBJTREE分别对应着uboot源码的顶目录(根目录)、源码目录(其实就是源代码的根目录)、编译出的.o文件存放的根目录(在默认编译下,OBJTREE等于当前目录;在单独输出文件夹编译下,OBJTREE就等于设置的输出目录)
其中还定义了MKCONFIG变量指向mkconfig文件,mkconfig在源码目录中打开可以看到注释说明mkconfig文件用于创建头文件并且将之链接至configure。需要注意的是mkconfig是一个shell脚本而非Makefile文件。mkconfig文件的作用也是根据参数中的架构、CPU、板子选择对应的分支将对应的头文件导入并且之后还将配置信息导入到config.mk和config.h文件。
接下来根据架构信息(ARCH)选择对应的交叉编译琏工具,定义CROSS_COMPILE。需要注意的是这里定义的CROSS_COMPILE只是交叉编译链工具的前缀,后缀的定义在config.mk文件中。
ifeq ($(ARCH),powerpc)
ARCH = ppc
endif
ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk))
# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export ARCH CPU BOARD VENDOR SOC
ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = ppc_8xx-
endif
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
#中间的其他分支略……
ifeq ($(ARCH),sparc)
CROSS_COMPILE = sparc-elf-
endif # sparc
endif # HOSTARCH,ARCH
endif # CROSS_COMPILE
export CROSS_COMPILE
# load other configuration
include $(TOPDIR)/config.mk
由于uboot是已经被九鼎创展移植过的,所以可以看到CROSS_COMPILE配置的交叉编译琏工具目录以及之前三星移植时配置的目录。
# U-Boot objects....order is important (i.e. start must be first)
OBJS = cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/reset.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 += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
"board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
LIBS += cpu/$(CPU)/lib$(CPU).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
all:
$(ALL)
$(obj)u-boot.hex:
$(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec:
$(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
……
接下来就是主Makefile的all目标,这里生成了u-boot.bin,u-boot.dis等文件,u-boot.bin就是主要的烧录文件。到这里可以说Makefile基本分析完了,后面还有很多内容都是针对不同SoC型号进行的配置选项,比如九鼎移植的这个uboot就要配置x210_sd_config。后面还有一个伪目标unconfig,作用是清除配置文件,内容如下:
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