20.U-boot顶层Makefile简要分析

二、顶层Makefile前面部分分析

1.递归调用make(20-29)

​ 在源码内有许许多多的目录,顶层Makefile也要调用子目录(subdir)中的makefile。

$(MAKE) -C subdir

​ export :用于给子makefile传入变量

​ unexport :用于不给子makefile导入变量

​ SHELL / MAKEFLAGS :无论用不用export , 都会将变量直接传给子makefile的。

MAKEFLAGS += -rR --include-dir=$(CURDIR)

# Avoid funny character set dependencies
unexport LC_ALL
LC_COLLATE=C
LC_NUMERIC=C
export LC_COLLATE LC_NUMERIC

# Avoid interference with shell env settings
unexport GREP_OPTIONS
2.命令行编译V=1的用处(73-86)

​ 看代码不难发先,它会比较V在命令行中输入的值,如果为非0,就会给KBUILD_VERBOSE变量赋值。为1的时候就会给quiet与Q附一个空值。也就是说在给每一个编译命令都会调用quiet与Q之来判断是否要打印出详细的命令代码。其中Q=@。在makefile中,如果在命令前面使用@,就不会打印在终端了。其中quiet_cmd_socboot , 与cmd_socboot命令等效,quiet=quiet_的话,输出较短版本的命令。

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif

$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
	-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))
quiet_cmd_socboot = SOCBOOT $@
cmd_socboot = cat	spl/u-boot-spl.sfp spl/u-boot-spl.sfp	\
			spl/u-boot-spl.sfp spl/u-boot-spl.sfp	\
			u-boot.img > $@ || rm -f $@
3.静默编译(91-101)

​ 使用make -s可以执行静默编译,编译全程不会打印命令信息,很少用。quiet = silent_。

ifneq ($(filter 4.%,$(MAKE_VERSION)),)	# make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
  quiet=silent_
endif
else					# make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
  quiet=silent_
endif
endif

export quiet Q KBUILD_VERBOSE
4.O变量设置(120-164)

​ 编译的时候可以将编译的输出文件存到某一目录下,就可以使用0=/dir。如果不使用O,就会在当前目录中。

ifeq ($(KBUILD_SRC),)
ifeq ("$(origin O)", "command line")
  KBUILD_OUTPUT := $(O)
endif
PHONY := _all
_all:
$(CURDIR)/Makefile Makefile: ;
ifneq ($(KBUILD_OUTPUT),)
#... ...
endif
endif

5.C变量设置(176-181)

​ 用于源码检查,C=1使能检查用于重新编译连接的代码。C=2检查所有的代码。

ifeq ("$(origin C)", "command line")
  KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif
6.M变量设置(183-220)

​ uboot编译模块,我们也使不上。有模块编译外部模块需要建立一些依赖源,最后会导出一些srctree objtree变量。

PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif

ifeq ($(KBUILD_SRC),)
        # building in the source tree
        srctree := .
else
        ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
                # building in a subdirectory of the source tree
                srctree := ..
        else
                srctree := $(KBUILD_SRC)
        endif
endif
objtree		:= .
src		:= $(srctree)
obj		:= $(objtree)

VPATH		:= $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))

export srctree objtree VPATH
7.获取主机架构与系统(225-241)

​ 获取系统架构,我们电脑的架构是x86 ,利用管道符进行替换i.86 。最终导出变量HOSTARCH=x86_64,HOSTOS=linux。

HOSTARCH := $(shell uname -m | \
	sed -e s/i.86/x86/ \
	    -e s/sun4u/sparc64/ \
	    -e s/arm.*/arm/ \
	    -e s/sa110/arm/ \
	    -e s/ppc64/powerpc/ \
	    -e s/ppc/powerpc/ \
	    -e s/macppc/powerpc/\
	    -e s/sh.*/sh/)

HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
	    sed -e 's/\(cygwin\).*/cygwin/')

export	HOSTARCH HOSTOS
8.默认设置(244-264)

​ 为了方便可以在Makefile的这里指定架构ARCH与CROSS_COMPILE。其余还有一些主机相关的信息不管。

ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif

KCONFIG_CONFIG	?= .config
export KCONFIG_CONFIG

# SHELL used by kbuild
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
	  else if [ -x /bin/bash ]; then echo /bin/bash; \
	  else echo sh; fi ; fi)

HOSTCC       = cc
HOSTCXX      = c++
HOSTCFLAGS   = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2

ifeq ($(HOSTOS),cygwin)
HOSTCFLAGS	+= -ansi
endif
9.初始化定义(328-376)

​ 引用了Kbuild.include一个文件,以及定义好多熟悉的变量以及导出CPU信息相关的变量。但是ARCH这些事哪里导出来的呢?在config.mk文件里有定义变量,那些变量最终是存在.config文件中的。

scripts/Kbuild.include: ;
include scripts/Kbuild.include
AS		= $(CROSS_COMPILE)as

ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
LD		= $(CROSS_COMPILE)ld.bfd
else
LD		= $(CROSS_COMPILE)ld
endif
CC		= $(CROSS_COMPILE)gcc
#... ...
export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
export MAKE AWK PERL PYTHON
export HOSTCXX HOSTCXXFLAGS DTC CHECK CHECKFLAGS
#... ...

三、编译处理过程

​ make xxx_defconfig

​ make V=1

10.xxx_defconfig编译规则(395-480)

​ 主要还是后面%config这两行,%是通配符。前面省略的有scripts_basic outputmakefile目标变量的生成规则。FORCE变量是总是执行。

KBUILD_SRC为空,则outputmakefile变量无效。

scripts_basic中的build变量在Kbuile.include中的build := -f $(srctree)/scripts/Makefile.build obj

最终make defconfig执行的是:

PHONY += scripts_basic
scripts_basic:
	$(Q)$(MAKE) $(build)=scripts/basic
	$(Q)rm -f .tmp_quiet_recordmcount
PHONY += outputmakefile

outputmakefile:
ifneq ($(KBUILD_SRC),)
	$(Q)ln -fsn $(srctree) source
	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
	    $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

%config: scripts_basic outputmakefile FORCE
	$(Q)$(MAKE) $(build)=scripts/kconfig $@
PHONY += FORCE
FORCE:

#最终执行的是
#@make -f $(srctree)/scripts/Makefile.build obj=scripts/basic
#@make -f $(srctree)/scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

第一条命令:)/scripts/Makefile.build的obj与src进行比较。prefix=.执行默认规则,则执行__build。__build对应于scipts/basic/fixdep对应的fixdep.c软件

​ src = scripts/basic用于编译出fixdep.c。在scripts/basic/下的Makefile用于编译。

第二条命令:

​ src肯定会改变。在makefile.build中的

%_defconfig:scripts/kconfig/conf

	$(Q)$< $(silent) --defconfig=arch/../configs/xxx_defconfig
11.make(802-816)

​ 默认目标_all , 依赖于all ,又依赖于ALL-y,有很多。

PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all

ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check

all:		$(ALL-y)
ifneq ($(CONFIG_SYS_GENERIC_BOARD),y)
	@echo "===================== WARNING ======================"
	@echo "Please convert this board to generic board."
	@echo "Otherwise it will be removed by the end of 2014."
	@echo "See doc/README.generic-board for further information"
	@echo "===================================================="
endif
ifeq ($(CONFIG_DM_I2C_COMPAT),y)
	@echo "===================== WARNING ======================"
	@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
	@echo "(possibly in a subsequent patch in your series)"
	@echo "before sending patches to the mailing list."
	@echo "===================================================="
endif

编译ALL会生成很多东西,我们主要来看u-boot.bin的依赖。

u-boot.bin: u-boot-nodtb.bin FORCE 。其中u-boot.bin依赖于u-boot-nodtb.bin。而它又依赖u-boot

u-boot-nodtb.bin: u-boot FORCE
	$(call if_changed,objcopy)
	$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
	$(BOARD_SIZE_CHECK)

u-boot:	$(u-boot-init) $(u-boot-main) u-boot.lds FORCE
	$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
	$(call cmd,smap)
	$(call cmd,u-boot__) common/system_map.o
endif

u-boot-init := $(head-y)
u-boot-main := $(libs-y)
#在arch/arm/Makefile中
#即head-y := arch/arm/cpu/armv7/start.o
head-y := arch/arm/cpu/$(CPU)/start.o	
#libs-y的依赖
libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += fs/
libs-y += net/
#... ...
libs-y	:= $(patsubst %/, %/built-in.o, $(libs-y))
#... ...

libs-y就是将大量的built-in.o保存下来。那么u-boot就是将built-in.o与start.o的链接一起,生成u-boot。

​ 那么问题来了,start.o是由start.s得来,built-in.o是从何而来?

在drivers/下的每个外设下有built-in.o.cmd文件,存放命令。

cmd_drivers/mmc/built-in.o :=  \
		arm-linux-gnueabihf-ld.bfd \
		-r -o drivers/mmc/built-in.o \
		drivers/mmc/fsl_esdhc.o drivers/mmc/mmc.o \
		drivers/mmc/mmc_write.o 
12.make dtbs(818-820)
PHONY += dtbs
dtbs dts/dt.dtb: checkdtc u-boot
	$(Q)$(MAKE) $(build)=dts dtbs
链接脚本

​ 链接脚本u-boot.lds。链接首地址是0x87800000。链接的是start.o 与大量built-in.o

​ 0x87800000在include/configs/mx6-common.h文件中定义。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值