完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
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所示的内容: 图31.3.12.1 输出变量值 修改好顶层Makefile以后执行如下命令: make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mytest 结果如图31.3.12.2所示: 图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所示: 图31.3.13.1 版本号文件 第423行定义了变量timestamp_h,此变量保存时间戳文件,此文件也是自动生成的。文件include/generated/timestamp_autogenerated.h内容如图31.3.13.2所示: 图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 很明显,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 uboot配置过程 从图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 此函数用于在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个变量的值打印出来: 图31.3.14.1 输出变量 执行如下命令: make mx6ull_14x14_ddr512_emmc_defconfig V=1 结果如图31.3.14.2所示: 图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所示: 图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所示: 图31.3.14.4 makexxx_defconfig执行流程图 至此,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 '%sn''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所示内容输出: 图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/u***/dwc3/built-in.o drivers/u***/emul/built-in.o drivers/u***/eth/built-in.o drivers/u***/gadget/built-in.o drivers/u***/gadget/udc/built-in.o drivers/u***/host/built-in.o drivers/u***/mu***-new/built-in.o drivers/u***/mu***/built-in.o drivers/u***/phy/built-in.o drivers/u***/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命令流程 图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的流程。至于更具体的实现,有兴趣的可以参考一下其他资料。 |
|
相关推荐
|
|
1042 浏览 0 评论
IaaS+on+DPU(IoD)+下一代高性能算力底座技术白皮书
2035 浏览 0 评论
飞凌嵌入式-ELFBOARD 常用的USB接口及其不同版本介绍第1期
1074 浏览 0 评论
【Vision Board创客营连载体验】RA8D1-Vision Board上OSPI-Flash实践
1533 浏览 0 评论
I.MX6ULL-飞凌 ElfBoard ELF1板卡- 应用层更改引脚复用的方法
3755 浏览 0 评论
65237 浏览 21 评论
嵌入式热门DIY项目:智能机器人开源资料合集(原理图、代码、论文)
67782 浏览 22 评论
57821 浏览 32 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-18 06:21 , Processed in 0.620848 second(s), Total 58, Slave 44 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号