嵌入式Linux -- 分析uboot中主Makefile

此主Makefile引用九鼎S5PV210中uboot的Makefile进行分析
1、版本号、主机CPU架构以及主机操作系统部分
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION = XXXXX
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、PATCHLEVEL、SUBLEVEL、EXTRAVERSION组合生成,形成最终的版本号U_BOOT_VERSION。此例中生成的版本号U_BOOT_VERSION = 1.3.4XXXXX,VERSION_FILE指定路径,在下面的代码中进行相应操作,在路径为uboot/include的version_autogenerated.h文件中写入宏定义来定义版本号,此宏定义为#define U_BOOT_VERSION "U-Boot 1.3.4XXXXX"

​ HOSTARCH表示主机的CPU架构,此代码用shell uname -m得到此主机的CPU版本号,用管道" | "把管道前面的一个运算式的输出作为后面的一个输入,然后用sed进行操作,将CPU的架构内容存在环境变量HOSTARCH中(sed -e s/a/b就是把a替换为b)。

​ HOSTOS表示主机的操作系统,用shell uname -s得到主机的操作系统,再用管道将其大写内容全部转换为小写,然后存入环境变量HOSTOS中。

2、静默编译
# Allow for silent builds
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif

​ 使用静默编译可以在编译过程中不打印编译信息,实现代码如上,使用方法是在编译make时在后面加-s,这个-s会作为MAKEFLAGS参数传到里面,findstring s找到s符号,ifeq里面的内容不成立,从而执行else的代码,令XECHO为空即可实现静默编译。

3、原地编译和指定输出目录编译
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif

ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)

$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)

OBJTREE		:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE		:= $(CURDIR)
TOPDIR		:= $(SRCTREE)
LNDIR		:= $(OBJTREE)
export	TOPDIR SRCTREE OBJTREE

MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD	:= 1
export REMOTE_BUILD
endif

ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src

# Make sure CDPATH settings don't interfere
unexport CDPATH

​ 原地编译和指定目录输出编译部分代码如上,如果要实现指定目录编译,则有两个方法,第一种是在编译时输入“make O=输出目录”;第二种则是导入环境变量“export BUILD_DIR=输出目录”,然后再make。如果两个都指定了编译输出目录,则第一种方法指定的目录具有更高的优先级。

OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))的含义是如果BUILD_DIR被赋值,则将其作为OBJTREE的目录,如果未赋值就把CURDIR作为其目录。

​ 代码中的OBJTREE是编译出的.o文件存放的目录,SRCTREE和TOPDIR是源码的根目录,也就是uboot目录,使用原地编译时OBJTREE和SRCTREE相等,使用指定目录编译时OBJTREE就是指定的那个输出目录,而SRCTREE是根目录。

​ 下面将根目录下的mkconfig赋值给MKCONFIG。接着判断是否使用原地编译,如果未使用原地编译,则在REMOTE_BUILD中写入1,如果用原地编译则不进行操作,最后再次判断是否使用原地编译,如果未使用原地编译就将OBJTREE赋值给obj,将SRCTREE赋值给src,如果用了就将obj和src赋值为空。

4、ARCH、CPU、BOARD、VENDOR、SOC配置值以及配置文件的生成
(1)头文件包含和配置
include $(obj)include/config.mk
export	ARCH CPU BOARD VENDOR SOC

x210_sd_config :	unconfig
	@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
	@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

​ 这里我们使用x210_sd_config的配置,先make x210_sd_config,使用uboot根目录下的mkconfig此配置文件),对应传入相应的参数,生成uboot/include/config.mk,里面的内容如下

ARCH   = arm	
CPU    = s5pc11x							   
BOARD  = x210								   
VENDOR = samsung							   
SOC    = s5pc110

​ 最后在uboot/board/samsung/x210/config.mk中输入链接地址
TEXT_BASE = 0xc3e00000

​ 其中ARCH是当前目标的CPU架构,它的选择会影响交叉编译工具链CROSS_COMPILE的选择,接着进行的一大段代码是判断ARCH是什么CPU架构并且选用相应的交叉编译工具链和包含相应的库文件和驱动代码的。

(2)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
​ 这个符号用来做为各个开发板配置目标的依赖,作用是为了以防上次的配置对这次造成影响,删除上次配置生成的配置文件以便这次配置正确。
5、uboot/include/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 > $@

​ 这段代码用uboot/include/config.h的内容作为原材料,自动生成uboot的相关配置信息文件autoconf.mk,而原材料文件uboot/include/config.h的内容为宏定义#include ,可以理解为这个配置信息的根本原材料在uboot/include/configs/x210_sd.h。而uboot/include/config.h文件以及文件的内容是在mkconfig配置文件中配置并且生成的,下面就来进行mkconfig配置文件的详解。

6、uboot/mkconfig配置文件详解
(1)用while判断传入参数并进行相应操作
while [ $# -gt 0 ] ; do
	case "$1" in
	--) shift ; break ;;
	-a) shift ; APPEND=yes ;;
	-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
	*)  break ;;
	esac
done

​ 如上代码,如果传参数大于0则进行相应匹配操作,操作完成后break跳出while循环。

(2)给板子赋名并且判断传参数量是否正确
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"

[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1

​ 判断板子是否有名字,没有则赋值$1的传参名,判断传参数量如果小于4或者大于6就说明传参数量是错的。

(3)打印信息并且判断是否是原地编译
echo "Configuring for ${BOARD_NAME} board..."

#
# 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
fi

rm -f asm-$2/arch

​ 打印“Configuring for (板名) board…”字样,判断SRCTREE和OBJTREE的值是否相等来判断是否是原地编译,如果不是原地编译就进行else下面的操作。最后删除uboot/include/asm-$2/arch。

(4)判断$6是否为空并且进行相应操作
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

​ 判断,若不为空就执行创建链接令uboot/include/asm-$2/arch指向include/asm-arm/arch-$6。

(5)创建相应的符号链接

在这里我们的$1-$6参数分别为$1:x210_sd、$2:arm、$3:s5pc11x、$4:x210 、$5:samsung 、$6:s5pc110,并且 $# = 6。

if [ "$3" = "s5pc1xx" ] ; then
        rm -f regs.h
        ln -s $6.h regs.h
        rm -f asm-$2/arch
        ln -s arch-$3 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then
	rm -f asm-$2/proc
	ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi

令uboot/include/regs.h文件指向uboot/include/s5pc110.h,然后再删除uboot/include/asm-arm/arch,再创建uboot/include/asm-arm/arch来指向include/asm-arm/arch-s5pc11x。

(6)创建uboot/include/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

​ 在uboot/include/config.mk中输入ARCH、CPU、BOARD、VENDOR、SOC等信息。创建这个文件是为了让Makefile去包含,对应上面第4部分的内容。

(7)判断是否需要创建uboot/include/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 $1.h>" >>config.h

​ 判断APPEND的值来确定是否有config.h这个文件,如果有就打印,如果没有就创建,然后在里面输入相应的内容。对应第5部分内容来理解。

7、uboot/config.mk作用

主要作用有两方面

(1)创建编译符号

​ 代码如下

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
(2)判断用哪个链接脚本
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

​ 代码如上,判断uboot/include/autoconf.mk中CONFIG_NAND_U_BOOT的值来确定用哪个链接脚本。

8、目标all

​ 此目标下面进行了各种编译工作。

你可能感兴趣的:(嵌入式Linux学习)