前言:
此时各位老铁们对“uboot命令行截取字符串”大体比较关心,我们都想要了解一些“uboot命令行截取字符串”的相关知识。那么小编同时在网上汇集了一些对于“uboot命令行截取字符串””的相关文章,希望朋友们能喜欢,你们快快来学习一下吧!1)实验平台:正点原子Linux开发板
2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》
关注官方微信号公众号,获取更多资料:正点原子
31.3.11 交叉编译工具变量设置
上面我们只是设置了CROSS_COMPILE的名字,但是交叉编译器其他的工具还没有设置,顶层Makefile中相关代码如下:
示例代码31.3.11.1 顶层Makefile代码
331 # Make variables (CC, etc...)
332
333 AS = $(CROSS_COMPILE)as
334 # Always use GNU ld
335 ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2>/dev/null),)
336 LD = $(CROSS_COMPILE)ld.bfd
337else
338 LD = $(CROSS_COMPILE)ld
339 endif
340 CC = $(CROSS_COMPILE)gcc
341 CPP = $(CC)-E
342 AR = $(CROSS_COMPILE)ar
343 NM = $(CROSS_COMPILE)nm
344 LDR = $(CROSS_COMPILE)ldr
345 STRIP = $(CROSS_COMPILE)strip
346 OBJCOPY = $(CROSS_COMPILE)objcopy
347 OBJDUMP = $(CROSS_COMPILE)objdump
31.3.12 导出其他变量
接下来在顶层Makefile会导出很多变量,代码如下:
示例代码31.3.12.1 顶层Makefile代码
368export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
369export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
370export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
371export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
372export MAKE AWK PERL PYTHON
373export HOSTCXX HOSTCXXFLAGS DTC CHECK CHECKFLAGS
374
375export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
376export KBUILD_CFLAGS KBUILD_AFLAGS
这些变量中大部分都已经在前面定义了,我们重点来看一下下面这几个变量:
ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
这7个变量在顶层Makefile是找不到的,说明这7个变量是在其他文件里面定义的,先来看一下这7个变量都是什么内容,在顶层Makefile中输入如图31.3.12.1所示的内容:
修改好顶层Makefile以后执行如下命令:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mytest
结果如图31.3.12.2所示:
从图31.3.12.2可以看到这7个变量的值,这7个变量是从哪里来的呢?在uboot根目录下有个文件叫做config.mk,这7个变量就是在config.mk里面定义的,打开config.mk内容如下:
示例代码31.3.12.2 config.mk代码
1 #
2 # (C) Copyright 2000-2013
3 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 #
5 # SPDX-License-Identifier: GPL-2.0+
6 #
7 #########################################################################
8
9 # This file is included from ./Makefile and spl/Makefile.
10 # Clean the state to avoid the same flags added twice.
11 #
12 # (Tegra needs different flags for SPL.
13 # That's the reason why this file must be included from spl/Makefile too.
14 # If we did not have Tegra SoCs, build system would be much simpler...)
15 PLATFORM_RELFLAGS :=
16 PLATFORM_CPPFLAGS :=
17 PLATFORM_LDFLAGS :=
18 LDFLAGS :=
19 LDFLAGS_FINAL :=
20 OBJCOPYFLAGS :=
21 # clear VENDOR for tcsh
22 VENDOR :=
23 #########################################################################
24
25 ARCH := $(CONFIG_SYS_ARCH:"%"=%)
26 CPU := $(CONFIG_SYS_CPU:"%"=%)
27 ifdef CONFIG_SPL_BUILD
28 ifdef CONFIG_TEGRA
29 CPU := arm720t
30 endif
31 endif
32 BOARD := $(CONFIG_SYS_BOARD:"%"=%)
33 ifneq ($(CONFIG_SYS_VENDOR),)
34 VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
35 endif
36 ifneq ($(CONFIG_SYS_SOC),)
37 SOC := $(CONFIG_SYS_SOC:"%"=%)
38 endif
39
40 # Some architecture config.mk files need to know what CPUDIR is set to,
41 # so calculate CPUDIR before including ARCH/SOC/CPU config.mk files.
42 # Check if arch/$ARCH/cpu/$CPU exists, otherwise assume arch/$ARCH/cpu contains
43 # CPU-specific code.
44 CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)
45
46 sinclude $(srctree)/arch/$(ARCH)/config.mk
47 sinclude $(srctree)/$(CPUDIR)/config.mk
48
49 ifdef SOC
50 sinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk
51 endif
52 ifneq ($(BOARD),)
53 ifdef VENDOR
54 BOARDDIR = $(VENDOR)/$(BOARD)
55else
56 BOARDDIR = $(BOARD)
57 endif
58 endif
59 ifdef BOARD
60 sinclude $(srctree)/board/$(BOARDDIR)/config.mk # include board specific rules
61 endif
62
63 ifdef FTRACE
64 PLATFORM_CPPFLAGS +=-finstrument-functions -DFTRACE
65 endif
66
67 # Allow use of stdint.h if available
68 ifneq ($(USE_STDINT),)
69 PLATFORM_CPPFLAGS +=-DCONFIG_USE_STDINT
70 endif
71
72 #########################################################################
73
74 RELFLAGS := $(PLATFORM_RELFLAGS)
75
76 PLATFORM_CPPFLAGS += $(RELFLAGS)
77 PLATFORM_CPPFLAGS +=-pipe
78
79 LDFLAGS += $(PLATFORM_LDFLAGS)
80 LDFLAGS_FINAL +=-Bstatic
81
82export PLATFORM_CPPFLAGS
83export RELFLAGS
84export LDFLAGS_FINAL
第25行定义变量ARCH,值为$(CONFIG_SYS_ARCH:"%"=%),也就是提取CONFIG_SYS_ARCH里面双引号“”之间的内容。比如CONFIG_SYS_ARCH=“arm”的话,ARCH=arm。
第26行定义变量CPU,值为$(CONFIG_SYS_CPU:"%"=%)。
第32行定义变量BOARD,值为(CONFIG_SYS_BOARD:"%"=%)。
第34行定义变量VENDOR,值为$(CONFIG_SYS_VENDOR:"%"=%)。
第37行定义变量SOC,值为$(CONFIG_SYS_SOC:"%"=%)。
第44行定义变量CPUDIR,值为arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)。
第46行sinclude和include的功能类似,在Makefile中都是读取指定文件内容,这里读取文件$(srctree)/arch/$(ARCH)/config.mk的内容。sinclude读取的文件如果不存在的话不会报错。
第47行读取文件$(srctree)/$(CPUDIR)/config.mk的内容。
第50行读取文件$(srctree)/$(CPUDIR)/$(SOC)/config.mk的内容。
第54行定义变量BOARDDIR,如果定义了VENDOR那么BOARDDIR=$(VENDOR)/$(BOARD),否则的BOARDDIR=$(BOARD)。
第60行读取文件$(srctree)/board/$(BOARDDIR)/config.mk。
接下来需要找到CONFIG_SYS_ARCH、CONFIG_SYS_CPU、CONFIG_SYS_BOARD、CONFIG_SYS_VENDOR和CONFIG_SYS_SOC这5个变量的值。这5个变量在uboot根目录下的.config文件中有定义,定义如下:
示例代码31.3.12.3 .config文件代码
23 CONFIG_SYS_ARCH="arm"
24 CONFIG_SYS_CPU="armv7"
25 CONFIG_SYS_SOC="mx6"
26 CONFIG_SYS_VENDOR="freescale"
27 CONFIG_SYS_BOARD="mx6ullevk "
28 CONFIG_SYS_CONFIG_NAME="mx6ullevk"
根据示例代码31.3.12.3可知:
ARCH = arm
CPU = armv7
BOARD = mx6ullevk
VENDOR = freescale
SOC = mx6
CPUDIR = arch/arm/cpu/armv7
BOARDDIR = freescale/mx6ullevk
在config.mk中读取的文件有:
arch/arm/config.mk
arch/arm/cpu/armv7/config.mk
arch/arm/cpu/armv7/mx6/config.mk (此文件不存在)
board/ freescale/mx6ullevk/config.mk (此文件不存在)
31.3.13 make xxx_defconfig过程
在编译uboot之前要使用“makexxx_defconfig”命令来配置uboot,那么这个配置过程是如何运行的呢?在顶层Makefile中有如下代码:
示例代码31.3.13.1 顶层Makefile代码段
414 # To make sure we donot include .config for any of the *config targets
415 # catch them early,and hand them over to scripts/kconfig/Makefile
416 # It is allowed to specify more targets when calling make, including
417 # mixing *config targets and build targets.
418 # For example 'make oldconfig all'.
419 # Detect when mixed targets is specified,and make a second invocation
420 # of make so .config is not included in thiscase either (for*config).
421
422 version_h := include/generated/version_autogenerated.h
423 timestamp_h := include/generated/timestamp_autogenerated.h
424
425 no-dot-config-targets := clean clobber mrproper distclean \
426 help %docs check% coccicheck \
427 ubootversion backup
428
429 config-targets :=0
430 mixed-targets :=0
431 dot-config :=1
432
433 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
434 ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
435 dot-config :=0
436 endif
437 endif
438
439 ifeq ($(KBUILD_EXTMOD),)
440 ifneq ($(filter config %config,$(MAKECMDGOALS)),)
441 config-targets :=1
442 ifneq ($(words $(MAKECMDGOALS)),1)
443 mixed-targets :=1
444 endif
445 endif
446 endif
447
448 ifeq ($(mixed-targets),1)
449 # ================================================================
450 # We're called with mixed targets (*config and build targets).
451 # Handle them one by one.
452
453 PHONY += $(MAKECMDGOALS) __build_one_by_one
454
455 $(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
456 @:
457
458 __build_one_by_one:
459 $(Q)set -e; \
460for i in $(MAKECMDGOALS);do \
461 $(MAKE)-f $(srctree)/Makefile $$i; \
462 done
463
464else
465 ifeq ($(config-targets),1)
466 # ================================================================
467 # *config targets only - make sure prerequisites are updated,and descend
468 # in scripts/kconfig to make the *config target
469
470 KBUILD_DEFCONFIG := sandbox_defconfig
471export KBUILD_DEFCONFIG KBUILD_KCONFIG
472
473 config: scripts_basic outputmakefile FORCE
474 $(Q)$(MAKE) $(build)=scripts/kconfig $@
475
476%config: scripts_basic outputmakefile FORCE
477 $(Q)$(MAKE) $(build)=scripts/kconfig $@
478
479else
480 #==================================================================
481 # Build targets only -this includes vmlinux, arch specific targets, clean
482 # targets and others. In general all targets except *config targets.
483
484 ifeq ($(dot-config),1)
485 # Read in config
486-include include/config/auto.conf
......
第422行定义了变量version_h,这变量保存版本号文件,此文件是自动生成的。文件include/generated/version_autogenerated.h内容如图31.3.13.1所示:
第423行定义了变量timestamp_h,此变量保存时间戳文件,此文件也是自动生成的。文件include/generated/timestamp_autogenerated.h内容如图31.3.13.2所示:
第425行定义了变量no-dot-config-targets。
第429行定义了变量config-targets,初始值为0。
第430行定义了变量mixed-targets,初始值为0。
第431行定义了变量dot-config,初始值为1。
第433行将MAKECMDGOALS中不符合no-dot-config-targets的部分过滤掉,剩下的如果不为空的话条件就成立。MAKECMDGOALS是make的一个环境变量,这个变量会保存你所指定的终极目标列表,比如执行“make mx6ull_alientek_emmc_defconfig”,那么MAKECMDGOALS就为mx6ull_alientek_emmc_defconfig。很明显过滤后为空,所以条件不成立,变量dot-config依旧为1。
第439行判断KBUILD_EXTMOD是否为空,如果KBUILD_EXTMOD为空的话条件成立,经过前面的分析,我们知道KBUILD_EXTMOD为空,所以条件成立。
第440行将MAKECMDGOALS中不符合“config”和“%config”的部分过滤掉,如果剩下的部分不为空条件就成立,很明显此处条件成立,变量config-targets=1。
第442行统计MAKECMDGOALS中的单词个数,如果不为1的话条件成立。此处调用Makefile中的words函数来统计单词个数,words函数格式如下:
$(words <text>)
很明显,MAKECMDGOALS的单词个数是1个,所以条件不成立,mixed-targets继续为0。综上所述,这些变量值如下:
config-targets =1
mixed-targets = 0
dot-config = 1
第448行如果变量mixed-targets为1的话条件成立,很明显,条件不成立。
第465行如果变量config-targets为1的话条件成立,很明显,条件成立,执行这个分支。
第473行,没有目标与之匹配,所以不执行。
第476行,有目标与之匹配,当输入“makexxx_defconfig”的时候就会匹配到%config目标,目标“%config”依赖于scripts_basic、outputmakefile和FORCE。FORCE在顶层Makefile的1610行有如下定义:
示例代码31.3.13.2 顶层Makefile代码段
1610 PHONY += FORCE
1611 FORCE:
可以看出FORCE是没有规则和依赖的,所以每次都会重新生成FORCE。当FORCE作为其他目标的依赖时,由于FORCE总是被更新过的,因此依赖所在的规则总是会执行的。
依赖scripts_basic和outputmakefile在顶层Makefile中的内容如下:
示例代码31.3.13.3 顶层Makefile代码段
394 # Basic helpers built in scripts/
395 PHONY += scripts_basic
396 scripts_basic:
397 $(Q)$(MAKE) $(build)=scripts/basic
398 $(Q)rm -f .tmp_quiet_recordmcount
399
400 # To avoid any implicit rule to kick in, define an empty command.
401 scripts/basic/%: scripts_basic ;
402
403 PHONY += outputmakefile
404 # outputmakefile generates a Makefile in the output directory,if
405 # using a separate output directory. This allows convenient use of
406 # make in the output directory.
407 outputmakefile:
408 ifneq ($(KBUILD_SRC),)
409 $(Q)ln -fsn $(srctree) source
410 $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
411 $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
412 endif
第408行,判断KBUILD_SRC是否为空,只有变量KBUILD_SRC不为空的时候outputmakefile才有意义,经过我们前面的分析KBUILD_SRC为空,所以outputmakefile无效。只有scripts_basic是有效的。
第396~398行是scripts_basic的规则,其对应的命令用到了变量Q、MAKE和build,其中:
Q=@或为空
MAKE=make
变量build是在scripts/Kbuild.include文件中有定义,定义如下:
示例代码31.3.13.3 Kbuild.include代码段
177 ###
178 # Shorthand for $(Q)$(MAKE)-f scripts/Makefile.build obj=
179 # Usage:
180 # $(Q)$(MAKE) $(build)=dir
181 build :=-f $(srctree)/scripts/Makefile.build obj
从示例代码31.3.13.3可以看出build=-f $(srctree)/scripts/Makefile.build obj,经过前面的分析可知,变量srctree为”.”,因此:
build=-f ./scripts/Makefile.build obj
scripts_basic展开以后如下:
scripts_basic:
@make -f ./scripts/Makefile.build obj=scripts/basic //也可以没有@,视配置而定
@rm -f . tmp_quiet_recordmcount //也可以没有@
scripts_basic会调用文件./scripts/Makefile.build,这个我们后面在分析。
接着回到示例代码31.3.13.1中的%config处,内容如下:
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
将命令展开就是:
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
同样也跟文件./scripts/Makefile.build有关,我们后面再分析此文件。使用如下命令配置uboot,并观察其配置过程:
make mx6ull_14x14_ddr512_emmc_defconfig V=1
配置过程如图31.3.13.1所示:
从图31.3.13.1可以看出,我们的分析是正确的,接下来就要结合下面两行命令重点分析一下文件scripts/Makefile.build。
①、scripts_basic目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/basic
②、%config目标对应的命令
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
31.3.14 Makefile.build脚本分析
从上一小节可知,“makexxx_defconfig“配置uboot的时候如下两行命令会执行脚本scripts/Makefile.build:
@make -f ./scripts/Makefile.build obj=scripts/basic
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
依次来分析一下:
1、scripts_basic目标对应的命令
scripts_basic目标对应的命令为:@make -f ./scripts/Makefile.build obj=scripts/basic。打开文件scripts/Makefile.build,有如下代码:
示例代码31.3.14.1 Makefile.build代码段
8 # Modified for U-Boot
9 prefix := tpl
10 src := $(patsubst $(prefix)/%,%,$(obj))
11 ifeq ($(obj),$(src))
12 prefix := spl
13 src := $(patsubst $(prefix)/%,%,$(obj))
14 ifeq ($(obj),$(src))
15 prefix :=.
16 endif
17 endif
第9行定义了变量prefix值为tpl。
第10行定义了变量src,这里用到了函数patsubst,此行代码展开后为:
$(patsubst tpl/%,%, scripts/basic)
patsubst是替换函数,格式如下:
$(patsubst <pattern>,<replacement>,<text>)
此函数用于在text中查找符合pattern的部分,如果匹配的话就用replacement替换掉。pattenr是可以包含通配符“%”,如果replacement中也包含通配符“%”,那么replacement中的这个“%”将是pattern中的那个“%”所代表的字符串。函数的返回值为替换后的字符串。因此,第10行就是在“scripts/basic”中查找符合“tpl/%”的部分,然后将“tpl/”取消掉,但是“scripts/basic”没有“tpl/”,所以src= scripts/basic。
第11行判断变量obj和src是否相等,相等的话条件成立,很明显,此处条件成立。
第12行和第9行一样,只是这里处理的是“spl”,“scripts/basic”里面也没有“spl/”,所以src继续为scripts/basic。
第15行因为变量obj和src相等,所以prefix=.。
继续分析scripts/Makefile.build,有如下代码:
示例代码31.3.14.2 Makefile.build代码段
56 # The filename Kbuild has precedence over Makefile
57 kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
58 kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
59 include $(kbuild-file)
将kbuild-dir展开后为:
$(if $(filter /%, scripts/basic), scripts/basic, ./scripts/basic),
因为没有以“/”为开头的单词,所以$(filter /%, scripts/basic)的结果为空,kbuild-dir=./scripts/basic。
将kbuild-file展开后为:
$(if $(wildcard ./scripts/basic/Kbuild), ./scripts/basic/Kbuild, ./scripts/basic/Makefile)
因为scrpts/basic目录中没有Kbuild这个文件,所以kbuild-file= ./scripts/basic/Makefile。最后将59行展开,即:
include./scripts/basic/Makefile
也就是读取scripts/basic下面的Makefile文件。
继续分析scripts/Makefile.build,如下代码:
示例代码31.3.14.3 Makefile.build代码段
116 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
117 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
118 $(subdir-ym) $(always)
119 @:
__build是默认目标,因为命令“@make -f ./scripts/Makefile.build obj=scripts/basic”没有指定目标,所以会使用到默认目标:__build。在顶层Makefile中,KBUILD_BUILTIN为1,KBUILD_MODULES为0,因此展开后目标__build为:
__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:
可以看出目标__build有5个依赖:builtin-target、lib-target、extra-y、subdir-ym和always。这5个依赖的具体内容我们就不通过源码来分析了,直接在scripts/Makefile.build中输入图31.3.14.1所示内容,将这5个变量的值打印出来:
执行如下命令:
make mx6ull_14x14_ddr512_emmc_defconfig V=1
结果如图31.3.14.2所示:
从上图可以看出,只有always有效,因此__build最终为:
__build: scripts/basic/fixdep
@:
__build依赖于scripts/basic/fixdep,所以要先scripts/basic/fixdep.c编译,生成fixdep,前面已经读取了scripts/basic/Makefile文件。
综上所述,scripts_basic目标的作用就是编译出scripts/basic/fixdep这个软件。
2、%config目标对应的命令
%config目标对应的命令为:@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig,各个变量值如下:
src= scripts/kconfig
kbuild-dir =./scripts/kconfig
kbuild-file =./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile
可以看出,Makefilke.build会读取scripts/kconfig/Makefile中的内容,此文件有如下所示内容:
示例代码31.3.14.4 scripts/kconfig/Makefile代码段
113%_defconfig: $(obj)/conf
114 $(Q)$< $(silent)--defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
115
116 # Added for U-Boot (backward compatibility)
117%_config:%_defconfig
118 @:
目标%_defconfig刚好和我们输入的xxx_defconfig匹配,所以会执行这条规则。依赖为$(obj)/conf,展开后就是scripts/kconfig/conf。接下来就是检查并生成依赖scripts/kconfig/conf。conf是主机软件,到这里我们就打住,不要纠结conf是怎么编译出来的,否则就越陷越深,太绕了,像conf这种主机所使用的工具类软件我们一般不关心它是如何编译产生的。如果一定要看是conf是怎么生成的,可以输入如下命令重新配置uboot,在重新配置uboot的过程中就会输出conf编译信息。
make distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_
defconfig V=1
结果如图31.3.14.3所示:
得到scripts/kconfig/conf以后就要执行目标%_defconfig的命令:
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
相关的变量值如下:
silent=-s或为空
SRCARCH=..
Kconfig=Kconfig
将其展开就是:
@ scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
上述命令用到了xxx_defconfig文件,比如mx6ull_alientek_emmc_defconfig。这里会将mx6ull_alientek_emmc_defconfig中的配置输出到.config文件中,最终生成uboot根目录下的.config文件。
这个就是命令makexxx_defconfig执行流程,总结一下如图31.3.14.4所示:
至此,makexxx_defconfig就分析完了,接下来就要分析一下u-boot.bin是怎么生成的了。
31.3.15 make过程
配置好uboot以后就可以直接make编译了,因为没有指明目标,所以会使用默认目标,主Makefile中的默认目标如下:
示例代码31.3.15.1 顶层Makefile代码段
128 # That's our default target when none is given on the command line
129 PHONY := _all
130 _all:
目标_all又依赖于all,如下所示:
示例代码31.3.15.2 顶层Makefile代码段
194 # If building an external module we donot care about the all: rule
195 # but instead _all depend on modules
196 PHONY += all
197 ifeq ($(KBUILD_EXTMOD),)
198 _all: all
199else
200 _all: modules
201 endif
如果KBUILD_EXTMOD为空的话_all依赖于all。这里不编译模块,所以KBUILD_EXTMOD肯定为空,_all的依赖就是all。在主Makefile中all目标规则如下:
示例代码31.3.15.2 顶层Makefile代码段
802 all: $(ALL-y)
803 ifneq ($(CONFIG_SYS_GENERIC_BOARD),y)
804 @echo "===================== WARNING ======================"
805 @echo "Please convert this board to generic board."
806 @echo "Otherwise it will be removed by the end of 2014."
807 @echo "See doc/README.generic-board for further information"
808 @echo "===================================================="
809 endif
810 ifeq ($(CONFIG_DM_I2C_COMPAT),y)
811 @echo "===================== WARNING ======================"
812 @echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
813 @echo "(possibly in a subsequent patch in your series)"
814 @echo "before sending patches to the mailing list."
815 @echo "===================================================="
816 endif
从802行可以看出,all目标依赖$(ALL-y),而在顶层Makefile中,ALL-y如下:
示例代码31.3.15.3 顶层Makefile代码段
730 # Always append ALL so that arch config.mk's can add custom ones
731 ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
732
733 ALL-$(CONFIG_ONENAND_U_BOOT)+= u-boot-onenand.bin
734 ifeq ($(CONFIG_SPL_FSL_PBL),y)
735 ALL-$(CONFIG_RAMBOOT_PBL)+= u-boot-with-spl-pbl.bin
736else
737 ifneq ($(CONFIG_SECURE_BOOT), y)
738 # For Secure Boot The Image needs to be signedand Header must also
739 # be included. So The image has to be built explicitly
740 ALL-$(CONFIG_RAMBOOT_PBL)+= u-boot.pbl
741 endif
742 endif
743 ALL-$(CONFIG_SPL)+= spl/u-boot-spl.bin
744 ALL-$(CONFIG_SPL_FRAMEWORK)+= u-boot.img
745 ALL-$(CONFIG_TPL)+= tpl/u-boot-tpl.bin
746 ALL-$(CONFIG_OF_SEPARATE)+= u-boot.dtb
747 ifeq ($(CONFIG_SPL_FRAMEWORK),y)
748 ALL-$(CONFIG_OF_SEPARATE)+= u-boot-dtb.img
749 endif
750 ALL-$(CONFIG_OF_HOSTFILE)+= u-boot.dtb
751 ifneq ($(CONFIG_SPL_TARGET),)
752 ALL-$(CONFIG_SPL)+= $(CONFIG_SPL_TARGET:"%"=%)
753 endif
754 ALL-$(CONFIG_REMAKE_ELF)+= u-boot.elf
755 ALL-$(CONFIG_EFI_APP)+= u-boot-app.efi
756 ALL-$(CONFIG_EFI_STUB)+= u-boot-payload.efi
757
758 ifneq ($(BUILD_ROM),)
759 ALL-$(CONFIG_X86_RESET_VECTOR)+= u-boot.rom
760 endif
761
762 # enable combined SPL/u-boot/dtb rules for tegra
763 ifeq ($(CONFIG_TEGRA)$(CONFIG_SPL),yy)
764 ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin
765 ALL-$(CONFIG_OF_SEPARATE)+= u-boot-dtb-tegra.bin
766 endif
767
768 # Add optional build target if defined in board/cpu/soc headers
769 ifneq ($(CONFIG_BUILD_TARGET),)
770 ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
771 endif
从示例代码代码31.3.15.3可以看出,ALL-y包含u-boot.srec、u-boot.bin、u-boot.sym、System.map、u-boot.cfg 和binary_size_check这几个文件。根据uboot的配置情况也可能包含其他的文件,比如:
ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin
CONFIG_ONENAND_U_BOOT就是uboot中跟ONENAND配置有关的,如果我们使能了ONENAND,那么在.config配置文件中就会有“CONFIG_ONENAND_U_BOOT=y”这一句。相当于CONFIG_ONENAND_U_BOOT是个变量,这个变量的值为“y”,所以展开以后就是:
ALL-y += u-boot-onenand.bin
这个就是.config里面的配置参数的含义,这些参数其实都是变量,后面跟着变量值,会在顶层Makefile或者其他Makefile中调用这些变量。
ALL-y里面有个u-boot.bin,这个就是我们最终需要的uboot二进制可执行文件,所作的所有工作就是为了它。在顶层Makefile中找到u-boot.bin目标对应的规则,如下所示:
示例代码31.3.15.4 顶层Makefile代码段
825 ifeq ($(CONFIG_OF_SEPARATE),y)
826 u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
827 $(call if_changed,cat)
828
829 u-boot.bin: u-boot-dtb.bin FORCE
830 $(call if_changed,copy)
831else
832 u-boot.bin: u-boot-nodtb.bin FORCE
833 $(call if_changed,copy)
834 endif
第825行判断CONFIG_OF_SEPARATE是否等于y,如果相等,那条件就成立,在.config中搜索“CONFIG_OF_SEPARAT”,没有找到,说明条件不成立。
第832行就是目标u-boot.bin的规则,目标u-boot.bin依赖于u-boot-nodtb.bin,命令为$(call if_changed,copy),这里调用了if_changed,if_changed是一个函数,这个函数在scripts/Kbuild.include中有定义,而顶层Makefile中会包含scripts/Kbuild.include文件,这个前面已经说过了。
if_changed在Kbuild.include中的定义如下:
示例代码31.3.15.5 Kbuild.include代码段
226 ###
227 # if_changed - execute command if any prerequisite is newer than
228 # target,or command line has changed
229 # if_changed_dep - as if_changed, but uses fixdep to reveal
230 # dependencies including used config symbols
231 # if_changed_rule - as if_changed but execute rule instead
232 # See Documentation/kbuild/makefiles.txt for more info
233
234 ifneq ($(KBUILD_NOCMDDEP),1)
235 # Check if both arguments has same arguments. Result is empty string if equal.
236 # User may overridethis check using make KBUILD_NOCMDDEP=1
237 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
238 $(filter-out $(cmd_$@), $(cmd_$(1))))
239else
240 arg-check = $(if $(strip $(cmd_$@)),,1)
241 endif
242
243 # Replace >$< with >$$< to preserve $ when reloading the .cmd file
244 # (needed for make)
245 # Replace >#< with >\#< to avoid starting a comment in the .cmd file
246 # (needed for make)
247 # Replace >'< with >'\''< to be able to enclose the whole string in '...'
248 # (needed for the shell)
249 make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1)))))
250
251 # Find any prerequisites that is newer than target or that does not exist.
252 # PHONY targets skipped in both cases.
253 any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
254
255 # Execute command if command has changed or prerequisite(s) are updated.
256 #
257 if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
258 @set -e; \
259 $(echo-cmd) $(cmd_$(1)); \
260 printf '%s\n''cmd_$@ := $(make-cmd)'> $(dot-target).cmd)
261
第227行为 if_changed的描述,根据描述,在一些先决条件比目标新的时候,或者命令行有改变的时候,if_changed就会执行一些命令。
第257行就是函数if_changed,if_changed函数引用的变量比较多,也比较绕,我们只需要知道它可以从u-boot-nodtb.bin生成u-boot.bin就行了。
既然u-boot.bin依赖于u-boot-nodtb.bin,那么肯定要先生成u-boot-nodtb.bin文件,顶层Makefile中相关代码如下:
示例代码31.3.15.6 顶层Makefile代码段
866 u-boot-nodtb.bin: u-boot FORCE
867 $(call if_changed,objcopy)
868 $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
869 $(BOARD_SIZE_CHECK)
目标u-boot-nodtb.bin又依赖于u-boot,顶层Makefile中u-boot相关规则如下:
示例代码31.3.15.7 顶层Makefile代码段
1170 u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
1171 $(call if_changed,u-boot__)
1172 ifeq ($(CONFIG_KALLSYMS),y)
1173 $(call cmd,smap)
1174 $(call cmd,u-boot__) common/system_map.o
1175 endif
目标u-boot依赖于u-boot_init、u-boot-main和u-boot.lds,u-boot_init和u-boot-main是两个变量,在顶层Makefile中有定义,值如下:
示例代码31.3.15.8 顶层Makefile代码段
678 u-boot-init := $(head-y)
679 u-boot-main := $(libs-y)
$(head-y)跟CPU架构有关,我们使用的是ARM芯片,所以head-y在arch/arm/Makefile中被指定为:
head-y := arch/arm/cpu/$(CPU)/start.o
根据31.3.12小节的分析,我们知道CPU=armv7,因此head-y展开以后就是:
head-y := arch/arm/cpu/armv7/start.o
因此:
u-boot-init= arch/arm/cpu/armv7/start.o
$(libs-y)在顶层Makefile中被定义为uboot所有子目录下build-in.o的集合,代码如下:
示例代码31.3.15.9 顶层Makefile代码段
620 libs-y += lib/
621 libs-$(HAVE_VENDOR_COMMON_LIB)+= board/$(VENDOR)/common/
622 libs-$(CONFIG_OF_EMBED)+= dts/
623 libs-y += fs/
624 libs-y += net/
625 libs-y += disk/
626 libs-y += drivers/
627 libs-y += drivers/dma/
628 libs-y += drivers/gpio/
629 libs-y += drivers/i2c/
......
660 libs-y += cmd/
661 libs-y += common/
662 libs-$(CONFIG_API)+= api/
663 libs-$(CONFIG_HAS_POST)+= post/
664 libs-y += test/
665 libs-y += test/dm/
666 libs-$(CONFIG_UT_ENV)+= test/env/
667
668 libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
669
670 libs-y := $(sort $(libs-y))
671
672 u-boot-dirs := $(patsubst %/,%,$(filter %/, $(libs-y))) tools examples
673
674 u-boot-alldirs := $(sort $(u-boot-dirs) $(patsubst %/,%,$(filter %/, $(libs-))))
675
676 libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
从上面的代码可以看出,libs-y都是uboot各子目录的集合,最后:
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
这里调用了函数patsubst,将libs-y中的“/”替换为”/built-in.o”,比如“drivers/dma/”就变为了“drivers/dma/built-in.o”,相当于将libs-y改为所有子目录中built-in.o文件的集合。那么u-boot-main就等于所有子目录中built-in.o的集合。
这个规则就相当于将以u-boot.lds为链接脚本,将arch/arm/cpu/armv7/start.o和各个子目录下的built-in.o链接在一起生成u-boot。
u-boot.lds的规则如下:
示例代码31.3.15.10 顶层Makefile代码段
u-boot.lds: $(LDSCRIPT) prepare FORCE
$(call if_changed_dep,cpp_lds)
接下来的重点就是各子目录下的built-in.o是怎么生成的,以drivers/gpio/built-in.o为例,在drivers/gpio/目录下会有个名为.built-in.o.cmd的文件,此文件内容如下:
示例代码31.3.15.11 drivers/gpio/.built-in.o.cmd代码
1 cmd_drivers/gpio/built-in.o := arm-linux-gnueabihf-ld.bfd -r -o drivers/gpio/built-in.o drivers/gpio/mxc_gpio.o
从命令“cmd_drivers/gpio/built-in.o”可以看出,drivers/gpio/built-in.o这个文件是使用ld命令由文件drivers/gpio/mxc_gpio.o生成而来的,mxc_gpio.o是mxc_gpio.c编译生成的.o文件,这个是NXP的I.MX系列的GPIO驱动文件。这里用到了ld的“-r”参数,参数含义如下:
-r –relocateable: 产生可重定向的输出,比如,产生一个输出文件它可再次作为‘ld’的输入,这经常被叫做“部分链接”,当我们需要将几个小的.o文件链接成为一个.o文件的时候,需要使用此选项。
最终将各个子目录中的built-in.o文件链接在一起就形成了u-boot,使用如下命令编译uboot就可以看到链接的过程:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_
defconfig V=1
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- V=1
编译的时候会有如图31.3.15.1所示内容输出:
将其整理一下,内容如下:
arm-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x87800000 \
-o u-boot -T u-boot.lds \
arch/arm/cpu/armv7/start.o \
--start-group arch/arm/cpu/built-in.o \
arch/arm/cpu/armv7/built-in.o \
arch/arm/imx-common/built-in.o \
arch/arm/lib/built-in.o \
board/freescale/common/built-in.o \
board/freescale/mx6ull_alientek_emmc/built-in.o \
cmd/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/spi/built-in.o \
drivers/usb/dwc3/built-in.o \
drivers/usb/emul/built-in.o \
drivers/usb/eth/built-in.o \
drivers/usb/gadget/built-in.o \
drivers/usb/gadget/udc/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 \
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/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.4 -lgcc -Map u-boot.map
可以看出最终是用arm-linux-gnueabihf-ld.bfd命令将arch/arm/cpu/armv7/start.o和其他众多的built_in.o链接在一起,形成u-boot。
目标all除了u-boot.bin以外还有其他的依赖,比如u-boot.srec 、u-boot.sym 、System.map、u-boot.cfg和binary_size_check等等,这些依赖的生成方法和u-boot.bin很类似,大家自行查看一下顶层Makefile,我们就不详细的讲解了。
总结一下“make”命令的流程,如图31.3.15.2所示:
图31.3.15.2就是“make”命令的执行流程,关于uboot的顶层Makefile就分析到这里,重点是“makexxx_defconfig”和“make”这两个命令的执行流程:
makexxx_defconfig:用于配置uboot,这个命令最主要的目的就是生成.config文件。
make:用于编译uboot,这个命令的主要工作就是生成二进制的u-boot.bin文件和其他的一些与uboot有关的文件,比如u-boot.imx等等。
关于uboot的顶层Makefile就分析到这里,有些内容我们没有详细、深入的去研究,因为我们的重点是使用uboot,而不是uboot的研究者,我们要做的是缕清uboot的流程。至于更具体的实现,有兴趣的可以参考一下其他资料。
标签: #uboot命令行截取字符串