U-Boot-1.1.6顶层Makefile分析(一)

笔者对Makefile不熟,一点一点分析代码,要是出错了麻烦各位大佬在评论指出。感激不尽。
第一篇,先把Makefile前面的变量和环境分析完吧。分析到all目标,然后后面的就跟着make时的流程走应该会比较好理解。

VERSION = 1										
PATCHLEVEL = 1
SUBLEVEL = 6
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/macppc/ppc/)

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

export  HOSTARCH HOSTOS

VERSION:主版本号
PATCHLEVEL:补丁版本号
SUBLEVEL:次版本号
EXTRAVERSION:附加版本信息
U_BOOT_VERSION:1.1.6
HOSTARCH:使用uname -m(获取CPU架构,这个看自己的电脑),通过管道输入到sed命令,sed命令将i.86替换为i386,将sun4u替换为sparc64…
HOSTOS:使用uname -s(获取操作系统),通过管道输入到tr,tr命令将大写字符转换成小写字符,通过管道输入到sed,sed将"(cygwin).*“替换为"cygwin”。
接着,使用export将主机架构和操作系统传递到子Makefile。
将这些变量输出的结果为
添加变量打印
执行make mytest
在这里插入图片描述

# Deal with colliding definitions from tcsh etc.    处理来自tcsh等的冲突定义
VENDOR=

#########################################################################
#
# 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),)

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

ifeq ("$(origin O)", “command line”): 如果O的内容是来自命令行的,也就是在执行make的时候带了O参数。
BUILD_DIR := $(O): 将O的内容赋给BUILD_DIR变量。

ifneq ($(BUILD_DIR),): 如果BUILD_DIR不为空。
saved-output := $(BUILD_DIR): 则将BUILD_DIR变量中的内容保存在saved-output变量中,此时saved-output变量保存的肯定是从命令行输入的O的内容。

$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}): 然后用-d 参数测试BUILD_DIR变量内容是不是一个目录,并且建立这个目录(如果目录不存在的话)。
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd): 切换到目标目录下,使用pwd命令获取路径并且再次复制给BUILD_DIR,代码里给出的解释是“Verify if it was successful”,应该是验证上面创建文件夹的操作是否成功。

$(if $(BUILD_DIR),,$(error output directory “$(saved-output)” does not exist)): 如果BUILD_DIR有数据,则不作任何操作,如果没有输出错误信息提示目标文件夹不存在。
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)): 如果BUILD_DIR有数据,则将BUILD_DIR付给OBJTREE变量,否则OBJTREE为当前路径。
SRCTREE := $(CURDIR): SRCTREE为当前路径 = 顶层Makefile所在路径。
TOPDIR := $(SRCTREE): TOPDIR = SRCTREE = 当前路径 = 顶层Makefile所在路径。
LNDIR := $(OBJTREE): LNDIR = OBJTREE = 设置的目标文件夹或者= 顶层Makefile所在路径。
export TOPDIR SRCTREE OBJTREE: 导出到子Makefile。
MKCONFIG := $(SRCTREE)/mkconfig: MKCONFIG为顶层Makefile所在路径下的mkconfig工具。
export MKCONFIG: 导出MKCONFIG到子Makefile。

ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD := 1
export REMOTE_BUILD
endif:
如果OBJTREE不等于SRCTREE,也就是在make时使用O参数指定了目标文件夹,则REMOTE_BUILD赋值为1,并且将REMOTE_BUILD导出。

  其实在上面的英文说明也有讲到O参数是用来设置编译uboot产生的目标文件路径
  我在uboot-1.1.6版本的uboot中没有找到help参数,在最新的uboot-2020.07版本中有help参数,可以将uboot提供的操作输出出来。这里贴出输出的部分信息,其中就有O参数的说明:
在这里插入图片描述

# $(obj) and (src) are defined in config.mk but here in main Makefile
# we also need them before config.mk is included which is the case for
# some targets like unconfig, clean, clobber, distclean, etc.
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src

ifneq ($(OBJTREE),$(SRCTREE)): 如果在,make时使用O变量指定了目标文件夹路径,则:
obj := $(OBJTREE)/: obj赋值为目标文件夹路径。
src := $(SRCTREE)/: src为当前路径= 顶层Makefile所在路径。
else
obj :=
src :=
endif:
否则,obj和src都为空。
export obj src: 导出obj和src。
  后面的分析以不使用O变量指定目标文件夹路径为准。

ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))

# load ARCH, BOARD, and CPU configuration
include $(OBJTREE)/include/config.mk
export  ARCH CPU BOARD VENDOR SOC

ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),ppc)
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = powerpc-linux-
endif
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
endif
ifeq ($(ARCH),i386)
ifeq ($(HOSTARCH),i386)
CROSS_COMPILE =
else
CROSS_COMPILE = i386-linux-
endif
endif
ifeq ($(ARCH),mips)
CROSS_COMPILE = mips_4KC-
endif
ifeq ($(ARCH),nios)
CROSS_COMPILE = nios-elf-
endif
ifeq ($(ARCH),nios2)
CROSS_COMPILE = nios2-elf-
endif
ifeq ($(ARCH),m68k)
CROSS_COMPILE = m68k-elf-
endif
ifeq ($(ARCH),microblaze)
CROSS_COMPILE = mb-
endif
ifeq ($(ARCH),blackfin)
CROSS_COMPILE = bfin-elf-
endif
ifeq ($(ARCH),avr32)
CROSS_COMPILE = avr32-
endif
endif
endif

export  CROSS_COMPILE

# load other configuration
include $(TOPDIR)/config.mk

ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk)): 先解释下wildcard,wildcard会匹配目录下的文件,匹配方式由后面的参数部分指定。如果没有匹配到相应的文件则返回空,否则返回匹配的文件,中间用空格隔开。因此,这一句的解释就是检查是否有OBJTREE)/include/config.mk这个文件。
记住这个ifeq,它很长,长到all目标那边
include $(OBJTREE)/include/config.mk: 包含config.mk文件,这个文件的内容其实就是目标板子的一些信息,如下所示:

ARCH   = arm 
CPU    = arm920t
BOARD  = smdk2410
SOC    = s3c24x0

注:config.mk文件是在执行make xxx_config时调用mkconfig脚本生成的。后面这四个变量以上述信息为例
export ARCH CPU BOARD VENDOR SOC: 导出到子Makefile中。
随后出现的十几行代码,都是在确定CROSS_COMPILE编译器类型,并且导出到子Makefile中。
include $(TOPDIR)/config.mk: 加载顶层目录下的config.mk文件,顶层目录下的config.mk根据ARCH、CPU、BOARD、SOC这四个变量确定了编译器和编译选项等信息。

#########################################################################
# 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),mpc83xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc86xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),bf533)
OBJS += cpu/$(CPU)/start1.o cpu/$(CPU)/interrupt.o  cpu/$(CPU)/cache.o
OBJS += cpu/$(CPU)/cplbhdlr.o   cpu/$(CPU)/cplbmgr.o    cpu/$(CPU)/flush.o
endif

OBJS := $(addprefix $(obj),$(OBJS))

LIBS  = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
LIBS += cpu/$(CPU)/lib$(CPU).a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).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
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
LIBS += drivers/sk98lin/libsk98lin.a
LIBS += post/libpost.a post/cpu/libcpu.a
LIBS += common/libcommon.a
LIBS += $(BOARDLIBS)

LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS)

OBJS = cpu/$(CPU)/start.o: OBJS = cpu/arm920t/start.o。
再根据CPU的类型往OBJS变量添加一些.o文件,这里CPU的类型为arm920t,所以此时的OBJS变量值为cpu/arm920t/start.o。
OBJS := $(addprefix ( o b j ) , (obj), (obj),(OBJS)): 调用文件名操作函数addprefix,在OBJS加上前缀obj,因为没有使用O变量,所以OBJS依然为cpu/arm920t/start.o。
接着,在LIBS变量中添加了相关的和通用的库文件,同样地给LIBS加上前缀obj。

# Add GCC lib
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc

-L加库路径(使用dirname变量获取编译器和各种参数的所在的路径),使用-lgcc 代表链接器将连接GCC的支持库libgcc.a。看解释说Add GCC lib,所以PLATFORM_LIBS 应该是作为一个参数的存在。

# The "tools" are needed early, so put this first
# Don't include stuff already done in $(LIBS)
SUBDIRS = tools \
      examples \
      post \
      post/cpu
.PHONY : $(SUBDIRS)

ifeq ($(CONFIG_NAND_U_BOOT),y)
NAND_SPL = nand_spl
U_BOOT_NAND = $(obj)u-boot-nand.bin
endif

__OBJS := $(subst $(obj),,$(OBJS))
__LIBS := $(subst $(obj),,$(LIBS))

SUBDIRS : tools examples post post/cpu。
ifeq ($(CONFIG_NAND_U_BOOT),y): 如果CONFIG_NAND_U_BOOT等于y,应该是在xxx_config文件里或者其他makefile中有这样定义:CONFIG_NAND_U_BOOT+=y
NAND_SPL = nand_spl: 则NAND_SPL =nand_spl
U_BOOT_NAND = $(obj)u-boot-nand.bin: U_BOOT_NAND = u-boot-nand.bin。
endif
__OBJS := $(subst ( o b j ) , , (obj),, (obj),,(OBJS)): __OBJS = 去掉obj前缀的OBJS。
__LIBS := $(subst ( o b j ) , , (obj),, (obj),,(LIBS)): __LIBS = 去掉obj前缀的LIBS。

#########################################################################
#########################################################################

ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)

all:        $(ALL)

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

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

$(obj)u-boot.bin:   $(obj)u-boot
        $(OBJCOPY) ${OBJCFLAGS} -O 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 $< $@

$(obj)u-boot.dis:   $(obj)u-boot
        $(OBJDUMP) -d $< > $@

$(obj)u-boot:       depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
        UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed  -n -e 's/.*\(__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

先说明下u-boot.srec为S-Record格式的image;
    u-boot.bin为原始二进制文件的image;
    System.map按链接地址由小到大的顺序列出了所有符号,可以称之为系统映射表;
    U_BOOT_NAND = u-boot-nand.bin,应该是烧录到nand flash的二进制格式的image;因此,
ALL: = u-boot.srec u-boot.bin System.map (u-boot-nand.bin如果CONFIG_NAND_U_BOOT不为y就没有)
all: $(ALL):这里就是编译uboot的目标all了,all目标没有相应命令,所以要实现的就是相关的依赖文件,也就是ALL了。

  未完待续。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mr_zhangsq

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

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

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

打赏作者

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

抵扣说明:

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

余额充值