uboot研读笔记 | 13 - uboot编译构建Makefile分析研读(2016.03版本)
Posted Mculover666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uboot研读笔记 | 13 - uboot编译构建Makefile分析研读(2016.03版本)相关的知识,希望对你有一定的参考价值。
一、uboot的编译
首先来回顾一下uboot如何编译。
(1)设置临时环境变量
export ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
(2)指定板级配置,生成.config文件
make xxx_defconfig
(3)编译
make -j8
(4)清除构建
make distclean
接下来,我们深入研读uboot根目录下的顶层Makefile文件,来探讨这三条编译命令背后发生了什么。
二、Makefile第一部分——make相关设置
1. uboot版本信息
VERSION = 2016
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
NAME =
- VERSION:主版本号
- PATCHLEVEL:补丁版本号
- SUBLEVEL :次版本号
- EXTRAVERSION:附加版本信息
- NAME:名称
2. MAKEFLAGS
# o Do not use make's built-in rules and variables
# (this increases performance and avoids hard-to-debug behaviour);
# o Look for make include files relative to root of kernel src
MAKEFLAGS += -rR --include-dir=$(CURDIR)
+=
:MAKEFLAGS变量追加值-rR
:禁止使用make内置的隐含规则和变量定义--include-dir
:指明搜索路径$(CURDIR)
:表示当前目录
3. 递归构建设置
# 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
# 避免干扰shell环境设置
unexport GREP_OPTIONS
make支持递归构建,调用子目录下的Makefile来完成子目录的编译,使用-C
参数指定子目录,语法如下:
$(MAKE) -C subdir
在调用子Makefile时,可以用export
指定传递哪些变量,使用unexport
指定不传递哪些变量。但是SHELL
变量和MAKEFLAGS
这两个变量默认会传递给子Makefile,除非使用unexport显示指定不传递。
4. 美化输出
# Use 'make V=1' to see the full commands
# 使用 'make V=1' 来看到uboot执行的完整命令
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
# If the user is running make -s (silent mode), suppress echoing of
# commands
# 如果用户运行make -s(静默模式),则禁止命令回显
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
(1)判断用户是否指定变量V的值
Makefile中函数origin
用来获取变量是哪里来的,如果变量V是在命令行定义的,那么它的来源就是"command line",进而将变量V的值赋给KBUILD_VERBOSE,设定日志输出是否详细。
如果用户没有定义变量V,则默认KBUILD_VERBOSE的值等于0。
(2)控制make日志输出
Makefile中用了一个比较骚的操作,来用变量quier和Q控制是否在终端输出完整的命令,比如:
$(Q)$(MAKE) $(build)=scripts/basic
如果V=1的情况下Q为空,这条命令执行时会被完整的输出在终端上;当V=0的情况下,Q=@,命令变为:
@make $(build) = scripts/basic
这时命令执行就不会被输出到终端上了。
(3)静默输出
在V=0的情况下,uboot终端中显示的是短命令,但还是会输出日志,使用make -s
参数即可设置静默输出,任何日志都没有。
(4)导出变量 quiet
、Q
、KBUILD_VERBOSE
给子Makefile,使他们保持一样的日志设置。
5. 设置编译输出目录
# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
# 在OBJ目录中调用make时设置KBUILD SRC
# KBUILD SRC不打算被普通用户使用(目前)
ifeq ($(KBUILD_SRC),)
# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
# 设置 KBUILD_OUTPUT 环境变量
ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif
# That's our default target when none is given on the command line
# 当命令行没有传递参数时,这是我们默认的目标
PHONY := _all
_all:
# Cancel implicit rules on top Makefile
# 取消顶部Makefile的隐含规则
$(CURDIR)/Makefile Makefile: ;
ifneq ($(KBUILD_OUTPUT),)
# Invoke a second make in the output directory, passing relevant variables
# check that the output directory actually exists
# 在输出目录中调用第二个make,传递相关变量检查输出目录是否确实存在
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \\
&& /bin/pwd)
$(if $(KBUILD_OUTPUT),, \\
$(error failed to create output directory "$(saved-output)"))
PHONY += $(MAKECMDGOALS) sub-make
$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
@:
sub-make: FORCE
$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \\
-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))
# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)
kbuild支持保存编译输出的文件到单独的目录,为了在单独的目录中定位输出文件,支持两种语法:
(1)O=
make O=dir/to/store/output/files/
(2)设置KBUILD_OUTPUT
环境变量
export KBUILD_OUTPUT=dir/to/store/output/files/
make
使用O=
指定要比 KBUILD_OUTPUT 环境变量的优先级要高。
6. 代码检查
# Call a source code checker (by default, "sparse") as part of the
# C compilation.
# 调用源代码检查器(默认情况下是“sparse”)作为C编译的一部分。
#
# Use 'make C=1' to enable checking of only re-compiled files.
# Use 'make C=2' to enable checking of *all* source files, regardless
# of whether they are re-compiled or not.
#
# See the file "Documentation/sparse.txt" for more details, including
# where to get the "sparse" utility.
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
使用参数C=
来使能代码检查:
- 1:检查需要重新编译的文件
- 2:检查所有的源码文件
同样,如果参数C来源于命令行,就将C赋值给环境变量 KBUILD_CHECKSRC
,如果没有则变量KBUILD_CHECKSRC
为0。
7. 模块编译
# If building an external module we do not care about the all: rule
# but instead _all depend on modules
# 如果指定了模块编译,则先编译模块,再编译all
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
使用参数M=dir
来指定外部模块编译输出目录,如果命令行有M参数,则将M的值赋给KBUILD_EXTMOD,若无,则KBUILD_EXTMOD为空,直接编译all。
三、Makefile第二部分——编译前的准备
1. 获取主机的CPU架构和操作系统
# 获取主机架构
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
2. 设置编译器和配置文件
还记得吗?uboot在编译前要指定ARCH和CROSS_COMPILE的值,这里就要派上用场了!
比较上一步获得的HOSTARCH和用户指定的ARCH:
(1)相等则表示在本机编译,直接使用本地编译器,交叉编译器不需要,设置为空;KCONFIG_CONFIG表示使用.config配置文件。
# set default to nothing for native builds
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
(2)如果主机操作是darwin(MAC OS的内核),则进行相关设置。
# Mac OS X / Darwin's C preprocessor is Apple specific. It
# generates numerous errors and warnings. We want to bypass it
# and use GNU C's cpp. To do this we pass the -traditional-cpp
# option to the compiler. Note that the -traditional-cpp flag
# DOES NOT have the same semantics as GNU C's flag, all it does
# is invoke the GNU preprocessor in stock ANSI/ISO C fashion.
#
# Apple's linker is similar, thanks to the new 2 stage linking
# multiple symbol definitions are treated as errors, hence the
# -multiply_defined suppress option to turn off this error.
#
ifeq ($(HOSTOS),darwin)
# get major and minor product version (e.g. '10' and '6' for Snow Leopard)
DARWIN_MAJOR_VERSION = $(shell sw_vers -productVersion | cut -f 1 -d '.')
DARWIN_MINOR_VERSION = $(shell sw_vers -productVersion | cut -f 2 -d '.')
os_x_before = $(shell if [ $(DARWIN_MAJOR_VERSION) -le $(1) -a \\
$(DARWIN_MINOR_VERSION) -le $(2) ] ; then echo "$(3)"; else echo "$(4)"; fi ;)
# Snow Leopards build environment has no longer restrictions as described above
HOSTCC = $(call os_x_before, 10, 5, "cc", "gcc")
HOSTCFLAGS += $(call os_x_before, 10, 4, "-traditional-cpp")
HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress")
# since Lion (10.7) ASLR is on by default, but we use linker generated lists
# in some host tools which is a problem then ... so disable ASLR for these
# tools
HOSTLDFLAGS += $(call os_x_before, 10, 7, "", "-Xlinker -no_pie")
endif
3. 引入通用的一些定义
# We need some generic definitions (do not try to remake the file).
# 我们需要一些通用的定义
scripts/Kbuild.include: ;
include scripts/Kbuild.include
Kbuild.include文件中都是后续编译过程中会用到的一些定义。
4. 制作变量——编译器完整名称
# Make variables (CC, etc...)
# 制作变量
AS = $(CROSS_COMPILE)as
# Always use GNU ld
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
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
AWK = awk
PERL = perl
PYTHON = python
DTC = dtc
CHECK = sparse
如果是交叉编译,这里就显得非常重要,环境变量CROSS_COMPILE的值为arm-linux-gnueabi-hf-,那么制作出的编译器就是:
CC = arm-linux-gnueabi-hf-gcc
其余工具名称同理。
5. 导出编译需要的变量给子Makefile
export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
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
export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS KBUILD_AFLAGS
这其中有的变量已经定义了,有的变量从未出现,比如第二行的变量,而这几个变量就是从根目录下的config.mk来的:
ARCH := $(CONFIG_SYS_ARCH:"%"=%)
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_TEGRA
CPU := arm720t
endif
endif
BOARD := $(CONFIG_SYS_BOARD:"%"=%)
ifneq ($(CONFIG_SYS_VENDOR),)
VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
endif
ifneq ($(CONFIG_SYS_SOC),)
SOC := $(CONFIG_SYS_SOC:"%"=%)
endif
这里面的CONFIG_SYS_xxx
变量是从配置文件.config
来的,如下:
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="mx6"
CONFIG_SYS_VENDOR="freescale"
CONFIG_SYS_BOARD="mx6ullatk"
CONFIG_SYS_CONFIG_NAME="mx6ullatk"
经过实际编译时候打印,这些变量的实际值如下:
至此,你应该已经理解了,uboot编译之前为什么要设置ARCH和CROSS_COMPILE两个环境变量。
export ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
四、make xxx_defconfig背后的过程
1. %config目标依赖
首先进行匹配,如果匹配到make命令的参数是config或者xxx_config,则将标志位config-targets置1:
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(words $(MAKECMDGOALS)),1)
mixed-targets := 1
endif
endif
endif
如果标志位config-targets为1,则进入对应目标:
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG
config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
else
可以看到,xxx_config的目标是%config,依赖是scripts_basic outputmakefile FORCE
这三项,构建命令是:
$(Q)$(MAKE) $(build)=scripts/kconfig $@
(1)scripts_basic依赖,在Makefile中可以找出该依赖的定义:
# Rules shared between *config targets and build targets
# *config目标和编译目标之间的共享规则
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
其中,Q是用于日志打印的、MAKE就是make,build 在scripts/Kbuild
文件中定义:
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
srctree变量是由顶层Makefile传递过来的,定义如下:
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
因为KBUILD_SRC变量为空,所以srctree变量的值为.
。
综上,scripts_basic的构建规则可以展开如下:
make -f ./scripts/Makefile.build obj=scripts/basic
这行命令会进而调用Makefile.build脚本,后面分析。
(2)outputmakefile依赖,同样在Makefile中可以找出该依赖的定义:
PHONY += outputmakefile
# outputmakefile generates a Makefile in the output directory, if using a
# separate output directory. This allows convenient use of make in the
# output directory.
outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)ln -fsn $(srctree) source
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \\
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif
该依赖的构建规则中,进来首先判断 KBUILD_SRC 是否为空,经过前面的分析该变量是空的,所以该依赖构建没啥用。
(3)FORCE依赖,同样在Makefile中可以找出该依赖的定义:
PHONY += FORCE
FORCE:
FORCE是没有规则和依赖的,所以每次都会重新生成FORCE,当FORCE作为其它目标的依赖时,由于FORCE总是被更新过的,所以依赖所在的规则总是会执行的。
好了,分析完三个依赖,我们将%config的构建规则展开如下吗,其中#@
是shell脚本语法,表示传进来的所有参数列表。
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
可以看到,这条命令同样也是调用 ./scripts/Makefile.build
脚本进行构建,后续再分析。
可以看到,第1、2行命令是在构建scripts_basic依赖,第3行命令是在构建%config目标。
2.Makefile.build脚本
(1)scripts_basic目标
make -f ./scripts/Makefile.build obj=scripts/basic
作用:编译出script/basic/fixdep 这个软件。
(2)%config目标
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
作用:使用xxx_defconfig文件,将xxx_defconfig文件的内容输出到配置文件.config中,生成.config中。
至此,你应该已经理解了,uboot编译之前make xxx_defconfig是如何生成.config文件的。
五、重头戏——uboot编译过程
前面的四个章节,uboot的顶层Makefile设置好了各种编译需要的变量,生成了.config文件,万事俱备,接下来开始编译uboot,生成可执行文件。
1. 依赖关系
(1)all目标
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
(2)all目标依赖的ALL-y
# Always append ALL so that arch config.mk's can add custom ones
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin
ifeq ($(CONFIG_SPL_FSL_PBL),y)
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot-with-spl-pbl.bin
else
ifneq ($(CONFIG_SECURE_BOOT), y)
# For Secure Boot The Image needs to be signed and Header must also
# be included. So The image has to be built explicitly
ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl
endif
endif
ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb
ifeq ($(CONFIG_SPL_FRAMEWORK),y)
ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
endif
ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb
ifneq ($(CONFIG_SPL_TARGET),)
ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%)
endif
ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf
ALL-$(CONFIG_EFI_APP) += u-boot-app.efi
ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi
ifneq ($(BUILD_ROM),)
ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom
endif
(3)u-boot.bin目标
ifeq ($(CONFIG_OF_SEPARATE),y)
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)
u-boot.bin: u-boot-dtb.bin FORCE
$(call if_changed,copy)
else
u-boot.bin: u-boot-nodtb.bin FORCE
$(call if_changed,copy)
endif
这里区分了用户使用设备树,本文中imx6ull未用到,所以依赖于u-boot-nodtb.bin文件。
(4)u-boot-nodtb.bin目标
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
(5)u-boot目标
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依赖于u-boot-init、u-boot-main和u-boot.lfs。
u-boot-init、u-boot-main是两个变量,在顶层Makefile中:
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
head-y
没有定义,该变量和CPU架构有关,在相关架构下的子Makefile中定义,比如arch/arm/Makefile中定义如下:
head-y := arch/arm/cpu/$(CPU)/start.o
libs-y在顶层Makefile中:
libs-y += lib/
libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += fs/
libs-y += net/
libs-y += disk/
libs-y += drivers/
libs-y += drivers/dma/
libs-y += drivers/spi/
# ...
libs-y += cmd/
libs-y += common/
libs-$(CONFIG_API) += api/
libs-$(CONFIG_HAS_POST) += post/
libs-y += test/
libs-y += test/dm/
libs-$(CONFIG_UT_ENV) += test/env/
libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
libs-y := $(sort $(libs-y))
u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples
u-boot-alldirs := $(sort $(u-boot-dirs) $(patsubst %/,%,$(filter %/, $(libs-))))
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
代码段可以看出,libs-y
是uboot各子目录中built-in.o的集合。
u-boot.lds在各个架构目录下,比如arch/arm/cpu/u-boot.lds。
综上,u-boot目标是以u-boot.lds为链接脚本,将arch/arm/cpu/armv7/start.o和各个子目录下的built-in.o链接在一起生成u-boot。
2. built-in.o文件如何生
以上是关于uboot研读笔记 | 13 - uboot编译构建Makefile分析研读(2016.03版本)的主要内容,如果未能解决你的问题,请参考以下文章
uboot研读笔记 | 12 - uboot目录结构分析(2016.03版本)
uboot研读笔记 | 03 - 初步移植uboot 2012.04到JZ2440(修改时钟,配置串口)
uboot研读笔记 | 04 - 移植uboot 2012.04到JZ2440(支持Nor Flash读写)
uboot研读笔记 | 02 - 详细探索uboot启动过程(基于S3C2410处理器)