u-boot之顶层Makefile分析(三)

u-boot之顶层Makefile分析(二)中分析了config.mk的生成过程,接着继续分析顶层Makefile

导出config.mk为环境变量

# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export	ARCH CPU BOARD VENDOR SOC
  • include/config.mk文件加载进来并将其内部的五个变量导出为环境变量

设置交叉编译工具链

ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = ppc_8xx-
endif
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-none-linux-gnueabi-
endif
…………
endif   # HOSTARCH,ARCH
endif   # CROSS_COMPILE

export  CROSS_COMPILE
include $(TOPDIR)/config.mk
  • 这是重要的工作之一---------设置交叉编译工具链
  • 上述代码只列表了前几行,其余用不上的平台判断用省略号代替
  • 由于我们前面设置的ARCH变量的值是arm,因此这里找到arm所在的判断语句并修改其中的CROSS_COMPILE变量值
  • 实际使用时也可以不在这里修改,而是通过make CROSS_COMPILE=xxx来设置交叉编译工具链
  • 导出CROSS_COMPILE变量为环境变量
  • 接下来分析config.mk文件的重点部分

config.mk文件重点部分分析

编译器设置

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
sinclude $(OBJTREE)/include/autoconf.mk
  • 进行了AS,LD等各种变量的赋值,这些值与前面配置的交叉编译工具链的变量组合起来形成编译器文件对源文件进行编译
  • 导入include/autoconf.mk文件,此文件现在是空的,但是Makefile使用sinclude来引入,这就造成了即使文件不存在也不会报错
  • include/autoconf.mk文件是在配置过程中生成的,它里面都是一些以CONFIG_XX开头的宏定义(可以理解为开关),用来指定uboot在编译过程中的走向,本文的最后有此文件的生成过程!

编译选项配置

ifdef	ARCH
sinclude $(TOPDIR)/$(ARCH)_config.mk	# include architecture dependend rules
endif
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
  • 根据不同的ARCH,CPU,SOC等添加不同的编译选择,下面是arm_config.mk中的内容PLATFORM_CPPFLAGS += -DCONFIG_ARM -D__ARM,其他的与之类似
  • 注意BOARD下的config.mk(board/samsung/x210/config.mk)文件内容TEXT_BASE = 0xc3e00000,这与顶层Makefile中的x210_sd_config任务写入的链接地址相同

链接脚本

ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
  • 这里我们没有定义CONFIG_NAND_U_BOOT变量,因此LDSCRIPT的值是u-boot.lds,这是一个链接脚本文件,分析uboot的编译过程时就要考虑这个链接脚本文件
  • 先把该文件放于下方,详细的说明请参阅u-boot之链接脚本博文,这里只说明.text段定义了程序的运行顺序,因此cpu/s5pc11x/start.o是第一个运行的文件
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x00000000;

	. = ALIGN(4);
	.text      :
	{
	  cpu/s5pc11x/start.o	(.text)
	  cpu/s5pc11x/s5pc110/cpu_init.o	(.text)
	  board/samsung/x210/lowlevel_init.o	(.text)
          cpu/s5pc11x/onenand_cp.o      (.text)                 
          cpu/s5pc11x/nand_cp.o (.text)                     
          cpu/s5pc11x/movi.o (.text) 
          common/secure_boot.o (.text) 
	  common/ace_sha1.o (.text)
	  cpu/s5pc11x/pmic.o (.text)
	  *(.text)
	}

	. = ALIGN(4);
	.rodata : { *(.rodata) }

	. = ALIGN(4);
	.data : { *(.data) }

	. = ALIGN(4);
	.got : { *(.got) }

	__u_boot_cmd_start = .;
	.u_boot_cmd : { *(.u_boot_cmd) }
	__u_boot_cmd_end = .;

	. = ALIGN(4);
	.mmudata : { *(.mmudata) }

	. = ALIGN(4);
	__bss_start = .;
	.bss : { *(.bss) }
	_end = .;
}

指定链接地址

ifneq ($(TEXT_BASE),)
CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
endif

ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif
  • 这里设置了u-boot链接时指定的链接地址
  • TEXT_BASE变量值在本篇中的编译选项配置小节中分析了来源

编译文件

ifndef REMOTE_BUILD

%.s:	%.S
	$(CPP) $(AFLAGS) -o $@ $<
%.o:	%.S
	$(CC) $(AFLAGS) -c -o $@ $<
%.o:	%.c
	$(CC) $(CFLAGS) -c -o $@ $<

else

$(obj)%.s:	%.S
	$(CPP) $(AFLAGS) -o $@ $<
$(obj)%.o:	%.S
	$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o:	%.c
	$(CC) $(CFLAGS) -c -o $@ $<
endif
  • 这里通过Makefile的自动推导规划编译目标文件

继续分析主Makefile

#########################################################################
# 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
……
LIBS += drivers/mtd/nand_legacy/libnand_legacy.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/sk98lin/libsk98lin.a
LIBS += drivers/pci/libpci.a
LIBS += drivers/pcmcia/libpcmcia.a
LIBS += drivers/spi/libspi.a
  • 接下来继续分析主Makefile
  • 注意看注释,order is important (i.e. start must be first),顺序很重要且start必须是第一个运行的文件。这与我们前面说的链接脚本中的.text段中定义的第一个运行文件相同。
  • 接下来添加各种运行库文件

第一个目标all

all:		$(ALL)

$(obj)u-boot.srec:	$(obj)u-boot
		$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@

$(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

$(SUBDIRS):	depend $(obj)include/autoconf.mk
		#$(error SUBDIRS)
		$(MAKE) -C $@ all
  • all是Makefile的第一个目标,因此执行make的作用等同于执行make all
  • $(ALL)变量的值经过打印得到u-boot.srec u-boot.bin System.map u-boot.dis,因此分别编译完成这四个任务才算完成
  • u-boot.srec依赖于u-boot,而u-boot又依赖于$(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT),SUBDIRS又依赖于include/autoconf.mk文件。
  • 这样一路依赖下去,然后倒着往回编译即可
  • 我们分析一下include/autoconf.mk文件是如何生成的,一则是许多目标都依赖于这个,二则是它是控制u-boot编译走向的开关文件

autoconf.mk文件的生成

#
# 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 > $@
	

$(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 > $@
  • 上述的规则用来生成autoconf.mk文件
  • (obj)include/autoconf.mk.dep 规则用不到
  • (obj)include/autoconf.mk规则用来生成autoconf.mk文件
  • 放开本篇第一个目标all小段中$(SUBDIRS)目标中的注释即可看到效果(要先删除include/autoconf.mk文件

在这里插入图片描述

  • 此时include/autoconf.mk文件已经生成,要想知道它的完整命令,即可以使用(先删除include/autoconf.mk文件make --trace 命令,运行两秒钟后按下Ctrl+z中断,然后往回找,下图红框中的内容就是完整的命令。
    在这里插入图片描述
  • 下图是该文件的内容示例。
    在这里插入图片描述

至此,主Makefile分析完成!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贱贱的剑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值