u-boot-2014.10在做完xxx_defconfig后,它会根据configs/<board>_defconfig创建的.config配置文件。接着使用make命令进行编译,则执行默认目标all
# That's our default target when none is given on thecommand line
PHONY := _all
_all:
…
# We process the rest of the Makefile if this is thefinal invocation of make
ifeq ($(skip-makefile),)
# If building an external module we do not care about theall: rule
# but instead _all depend on modules
PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
其中skip-makefile和KBUILD_EXTMOD都未定义,所以运行_all:all
all: $(ALL-y)
需要依赖条件$(ALL-y),而$(ALL-y)的定义如下
ALL-y += u-boot.srec u-boot.bin System.mapbinary_size_check
l 需要依赖条件u-boot.srec
u-boot.hex u-boot.srec: u-boot FORCE
$(call if_changed,objcopy)
l 需要依赖条件u-boot.bin
u-boot.bin: u-boot FORCE
$(call if_changed,objcopy)
$(callDO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
l 需要依赖条件System.map
System.map: u-boot
@$(call SYSTEM_MAP,$<) > $@
l 需要依赖条件binary_size_check
binary_size_check: u-boot.bin FORCE
@file_size=$(shell wc -c u-boot.bin | awk '{print $$1}') ; \
map_size=$(shell cat u-boot.map | \
awk '/_image_copy_start/{start = $$1} /_image_binary_end/ {end = $$1} END {if (start != ""&& end != "") print "ibase=16; " toupper(end)" - " toupper(start)}' \
| sed 's/0X//g' \
| bc); \
if [ "" != "$$map_size" ]; then \
if test $$map_size -ne $$file_size; then \
echo "u-boot.mapshows a binary size of $$map_size" >&2 ; \
echo " but u-boot.bin shows $$file_size" >&2 ; \
exit 1; \
fi \
fi
依赖u-boot.srec u-boot.bin System.map都需要u-boot这个elf文件其依赖关系如下
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds
$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
$(call cmd,smap)
$(call cmd,u-boot__) common/system_map.o
endif
要生成u-boot elf文件需要用到$(u-boot-init) $(u-boot-main) u-boot.lds依赖关系,
u-boot-init依赖定义为
u-boot-init := $(head-y)
其中head-y定义为
head-y := $(CPUDIR)/start.o
u-boot-init指向start.s第一个启动文件
u-boot-main依赖定义为
u-boot-main := $(libs-y)
其中libs-y定义为各种库和驱动。
u-boot.lds依赖定义为
u-boot.lds: $(LDSCRIPT) prepare FORCE
$(callif_changed_dep,cpp_lds)
LDSCRIPT依赖定义为
ifndef LDSCRIPT
#LDSCRIPT :=$(srctree)/board/$(BOARDDIR)/u-boot.lds.debug
ifdefCONFIG_SYS_LDSCRIPT
# need to stripoff double quotes
LDSCRIPT := $(srctree)/$(CONFIG_SYS_LDSCRIPT:"%"=%)
endif
endif
# If there is no specified link script, we look in anumber of places for it
ifndef LDSCRIPT
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds
endif
endif
当配置文件中定义了CONFIG_SYS_LDSCRIPT,则使用指定的,如果没有定义,到这三个位置寻找连接文件。
Prepare依赖等于为
# All the preparing..
prepare: prepare0
prepare0依赖定义为
prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
Archprepare依赖定义为
archprepare: prepare1scripts_basic
scripts_basic依赖定义为
make -f scripts/Makefile.build obj=scripts/basic
rm -f .tmp_quiet_recordmcount
详细见u-boot-2014-10 Makefile配置过程分析
prepare1依赖定义为
prepare1: prepare2 $(version_h) $(timestamp_h) include/config/auto.conf
其中version_h为
version_h := include/generated/version_autogenerated.h
timestamp_h为
timestamp_h := include/generated/timestamp_autogenerated.h
prepare2依赖定义为
prepare2: prepare3outputmakefile
其中outputmakefile得不到执行(详细见u-boot-2014-10 Makefile配置过程分析)
prepare3依赖定义为
prepare3: include/config/uboot.release
其中nclude/config/uboot.release依赖为
include/config/uboot.release: include/config/auto.conf FORCE
$(call filechk,uboot.release)
现在有两个地方都使用了include/config/auto.conf依赖,其定义如下
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefilesilentoldconfig
其中KCONFIG_CONFIG =.config
依赖$(KCONFIG_CONFIG) include/config/auto.conf.cmd被强制更新
# To avoid any implicit rule to kick in, define an emptycommand
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
接着执行命令
make -f ./Makefilesilentoldconfig
接着会在顶层Makefile中匹配
%config: scripts_basicoutputmakefile FORCE
+$(Q)$(CONFIG_SHELL) $(srctree)/scripts/multiconfig.sh $@
这里的流程与配置很相似,scripts_basic依赖是调用makefile.build编译scripts/basic目录下的文件,ouputmakefile依赖和FORCE不会执行。
接着调用scripts/multiconfig.sh脚本,其参数为silentoldconfig。(这部分分析可以参考Makefile配置流程分析)
progname=multiconfig.sh
target=silentoldconfig
case $target in
*_defconfig)
do_board_defconfig $target;;
*_config)
# backwardcompatibility
do_board_defconfig ${target%_config}_defconfig;;
<span style="color:#ff0000;">silentoldconfig)
do_silentoldconfig;;</span>
defconfig)
do_defconfig;;
savedefconfig)
do_savedefconfig;;
*)
do_others$target;;
esac
接下来调用do_silentoldconfig函数进行配置
do_silentoldconfig () {
run_make_config silentoldconfig
subimages=$(get_enabled_subimages)
for obj in $subimages
do
mkdir -p $obj/include/config $obj/include/generated
run_make_config silentoldconfig $obj
done
# If thefollowing part fails, include/config/auto.conf should be
# deleted so"make silentoldconfig" will be re-run on the next build.
autoconf includeinclude/autoconf.mk include/autoconf.mk.dep ||{
rm -finclude/config/auto.conf
exit 1
}
#include/config.h has been updated after "make silentoldconfig".
# We need totouch include/config/auto.conf so it gets newer
# thaninclude/config.h.
# Otherwise,'make silentoldconfig' would be invoked twice.
touch include/config/auto.conf
for obj in $subimages
do
autoconf$obj/include $obj/include/autoconf.mk || {
rm -f include/config/auto.conf
exit 1
}
done
}
这里需要关注run_make_config函数和autoconf函数
首先调用run_make_config进行配置
target=$1
objdir=$2
# Linux expects defconfig files inarch/$(SRCARCH)/configs/ directory,
# but U-Boot has them in configs/ directory.
# Give SRCARCH=.. to fake scripts/kconfig/Makefile.
options="SRCARCH=..KCONFIG_OBJDIR=$objdir"
if [ "$objdir" ]; then
options="$optionsKCONFIG_CONFIG=$objdir/$KCONFIG_CONFIG"
mkdir -p $objdir
fi
build scripts/kconfig $options$target
拓展后
target= silentoldconfig
objdir=
make -f ./scripts/Makefile.build obj="scripts/kconfigsilentoldconfig"
接着使用 ./scripts /Makefile .build调用 scripts/kconfig目录下的Makefile文件进行接下来的配置, scripts/kconfig/Makefile规则匹配
silentoldconfig: $(obj)/conf
$(Q)mkdir -p include/config include/generated
$< --$@ $(Kconfig)
拓展后
silentoldconfig: /scripts/kconfig/conf
mkdir -p include/config include/generated
/scripts/kconfig/conf --silentoldconfigKconfig
其先创建两个文件,然后再使用conf进行接下来的配置。Conf源码在scripts/kconfig目录下,当conf运行后,首先解析—silentoldconfig
while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
input_mode = (enum input_mode)opt;
switch (opt) {
case silentoldconfig:
sync_kconfig= 1;
break;
case defconfig:
case savedefconfig:
defconfig_file= optarg;
break;
......
}
sync_kconfig 这个变量会为 1
调用函数conf_parse(name);将Kconfig中的配置信息放到一个链表中。
接着获取.config中的配置信息
if (sync_kconfig) {
name = conf_get_configname();
if (stat(name, &tmpstat)) {
fprintf(stderr, _("***\n"
"***Configuration file \"%s\" not found!\n"
"***\n"
"*** Pleaserun some configurator (e.g. \"make oldconfig\" or\n"
"***\"make menuconfig\" or \"make xconfig\").\n"
"***\n"), name);
exit(1);
}
}
接着的input_mode为silentoldconfig,所以会执行conf_read(NULL)函数;conf_read(NULL);函数用来读取 .config 文件。读取的各种相关内容主要存放在一个 struct symbol 结构链表里,而各个结构的相关指针则放在一个 symbol_hash[] 的数组中,对于数组中元素的寻找通过 fnv32 哈希算法进行定位。
switch (input_mode) {
.....
case savedefconfig:
case silentoldconfig:
case oldaskconfig:
case oldconfig:
case listnewconfig:
case olddefconfig:
conf_read(NULL);
break;
case allnoconfig:
case allyesconfig:
.....
}
由于sync_kconfig变量为1所以在最后进入下面分支
if (sync_kconfig) {
/* silentoldconfigis used during the build so we shall update autoconf.
* Allother commands are only used to generate a config.
*/
if (conf_get_changed() && conf_write(NULL)) {
fprintf(stderr, _("\n*** Errorduring writing of the configuration.\n\n"));
exit(1);
}
if (conf_write_autoconf()) {
fprintf(stderr, _("\n*** Errorduring update of the configuration.\n\n"));
return 1;
}
在 if(conf_get_changed() && conf_write(NULL)) 这个判断里,conf_get_changed()函数判断 .config 文件是否做过变动,如果是,那么会调用 conf_write(NULL) 来重新写.config 文件。接着调用conf_write_autoconf()函数,在该函数里面会创建auto.conf.cmd、autoconf.h、tristate.conf、auto.conf等文件,并将注释写入到其中
conf_write_heading(out, &kconfig_printer_cb, NULL);
conf_write_heading(tristate, &tristate_printer_cb, NULL);
conf_write_heading(out_h, &header_printer_cb, NULL);
然后通过for_all_symbols(I,sym)循环的往后3个文件分别写入相关的内容
for_all_symbols(i, sym) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
continue;
/* write symbol toauto.conf, tristate and header files */
conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
}
Conf运行完成后,返回到scripts/multiconfig.sh脚本中的do_silentoldconfig函数,并接着向下运行
Run_make_config函数讲解完成后,现在分析autoconf函数
# If thefollowing part fails, include/config/auto.conf should be
# deleted so"make silentoldconfig" will be re-run on the next build.
autoconfinclude include/autoconf.mk include/autoconf.mk.dep || {
rm -f include/config/auto.conf
exit 1
}
当前半部分为真则不执行下半部分的内容。这里的autoconf函数定义如下
autoconf () {
debug $progname: $MAKE -f $srctree/scripts/Makefile.autoconf obj="$@"
$MAKE -f $srctree/scripts/Makefile.autoconf obj="$@"
}
其调用的是makefile.autoconf
拓展后得到
make -f ./scripts/Makefile.autoconf obj="includeinclude/autoconf.mk include/autoconf.mk.dep"
由于没有传递目标到Makefile.autoconf,所以Makefile.autoconf采用默认配置
include/config.h: scripts/Makefile.autoconfcreate_symlink FORCE
$(call filechk,config_h)
依赖scripts/Makefile.autoconfcreate_symlink
create_symlink:
ifneq ($(KBUILD_SRC),)
$(Q)mkdir -p include/asm
endif
$(Q)ln -fsn $(srctree)/arch/$(ARCH)/include/asm/arch-$(if $(SOC),$(SOC),$(CPU)) \
$(if $(KBUILD_SRC),,arch/$(ARCH)/)include/asm/arch
将其拓展后
create_symlink:
ln-fsn arch/arm/include/asm/arch-s3c24x0 arch/arm/include/asm/arch
可以得到这里是创建一个软连接。
整体流程解析完成后,接着就是编译,生成u-boot
arm-linux-ld -pie --gc-sections -Bstatic -Ttext 0x0 \
-o u-boot -T u-boot.lds arch/arm/cpu/arm920t/start.o \
--start-group arch/arm/cpu/built-in.o \
arch/arm/cpu/arm920t/built-in.o \
arch/arm/cpu/arm920t/s3c24x0/built-in.o \
arch/arm/lib/built-in.o \
board/samsung/common/built-in.o \
board/samsung/smdk2410/built-in.o \
common/built-in.o disk/built-in.o drivers/built-in.o \
drivers/dma/built-in.o drivers/gpio/built-in.o \
drivers/i2c/built-in.o drivers/mmc/built-in.o \
drivers/mtd/built-in.o drivers/mtd/nand/built-in.o \
drivers/mtd/onenand/built-in.o drivers/mtd/spi/built-in.o \
drivers/mtd/ubi/built-in.o drivers/net/built-in.o \
drivers/net/phy/built-in.o drivers/pci/built-in.o \
drivers/power/built-in.o drivers/power/battery/built-in.o \
drivers/power/fuel_gauge/built-in.o drivers/power/mfd/built-in.o \
drivers/power/pmic/built-in.o drivers/serial/built-in.o \
drivers/spi/built-in.o drivers/usb/eth/built-in.o \
drivers/usb/gadget/built-in.o drivers/usb/host/built-in.o \
drivers/usb/musb-new/built-in.o drivers/usb/musb/built-in.o \
drivers/usb/phy/built-in.o drivers/usb/ulpi/built-in.o \
fs/built-in.o lib/built-in.o lib/libfdt/built-in.o net/built-in.o\
test/built-in.o test/dm/built-in.o --end-group arch/arm/lib/eabi_compat.o \
-L /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t -lgcc -Map u-boot.map