学习目标:
uboot顶层Makefile分析
学习内容:
学习使用了正点原子的I.MX6ULL教程及开发平台。
uboot顶层Makefile分析
1、版本号
2、MAKEFLAGES
3、命令输出
4、静默输出
5、设置编译结果输出目录
6、代码检查
7、模块编译
8、获取主机架构和系统
9、设置目标架构、交叉编译器和配置文件
10、调用scripts/Kbuild.include
11、交叉编译工具变量的设置
12、导出其他变量
13、MAKECMDGOALS变量
14、ARCH、CPU、BOARD、VENDOR、SOC
学习时间:
2022-06-04
学习产出:
1、版本号
顶层Makefile代码中,一开始就是uboot的版本号,如下图所示。
VERSION是主版本号;
PATCHLEVEL是补丁版本号;
SUBLEVEL是次版本号;
这三个一起构成了uboot的版本号,当前的uboot版本就是2016.03版本。
EXTRAVERSION是附加信息,NAME是和名字相关,一般不使用这两个。
2、MAKEFLAGES
make是支持递归调用的,也就是在makefile中使用make命令执行其他的Makefile文件,这个文件一般都是子目录的Makefile文件。加入在当前目录下有一个subdir子目录,这个目录中又有Makefile文件,那么在工程编译的时候其主目录中的Makefile就可以调用子目录中的Makefile,以此来完成子目录中的Makefile编译。主目录中可以使用如下命令来执行子目录中的Makefile:
$(MAKE) -C subdir
$(MAKE)就是调用make命令,-C是指定子目录。
有时候我们需要向子目录中的Makefile传递变量,就需要使用export来导出要传递给子Makefile的变量。如果不希望某个变量传递给子Makefile的话就需要使用unexport来声明不导出。
export VARIABLE //导出变量VARIABLE给其他子Makefile使用
unexport VARIABLE //不导出变量VARIABLE
这里,在Makefile中有两个特殊的变量:SHELL和MAKEFLAGS,默认情况下这两个变量的值始终导出给子Makefile使用,除非使用unexport声明这两个变量不导出。
在顶层Makefile中有如下代码:
上述代码中使用+=给变量MAKEFLAGS追加了值,-rR表示禁止使用内置的隐含规则和表达式,–include-dir指明搜索路径.
$(CURDIR)表示当前目录。
3、命令输出
uboot默认在编译时是不会在终端显示完整的命令的,都是短命令。可以在使用make命令时加入V=1来实现完整命令的输出,这在调试uboot的时候很有用。
实现这一块的代码在顶层Makefile中,如下图所示。
上述代码中先使用ifeq来判断
$(origin V)和command line是否相等。这里用到了Makefile的函数origin,此函数用于告诉变量是哪来的,语法为:
$(origin variable)
variable是变量名,origin的返回值就是变量的来源,因此
$(origin V)就是变量V的来源。如果变量V来源于命令行,就和command line相等。那么变量KBUILD_VERBOSR的值就是V的值,KBUILD_VERBOSR=1。如果命令行没有输入V=1则KBUILD_VERBOSR=0。
下面再判断KBUILD_VERBOSR是否为1,如果为1,那么变量quiet和Q的值都为空;如果KBUILD_VERBOSR的值为0,则quiet的值为quiet_,Q的值为@。
综上所述,
V=1 的话:
KBUILD_VERBOSE=1
quiet= 空 。
Q= 空。
V=0 或者命令行不定义 V 的话:
KBUILD_VERBOSE=0
quiet= quiet_。
Q= @。
可以在编译Makefile时,通过打印查看这些值,编译脚本中是写了V=1的,打印结果如下图所示。
Makefile中会用到变量quiet和Q来控制编译时是否在终端输出完整的命令,在顶层Makefile中有许多如下命令:
如果V=0或者在命令行中省略V的话,这行命令展开就是:
@ make $(build)=tools
在这行命令前面加了@就不会在终端上输出命令了。当V=1的时候,Q就为空,上述命令展开就是:
make $(build)=tools
因此,在make执行的过程中,命令会被完整的输出在终端上。
4、静默输出
在使用make命令是加入-s参数,即可实现静默输出功能,即在编译uboot的时候不会输出命令。在顶层Makefile下有如下代码,如图所示。
这段代码就是实现静默输出功能的,首先判断当前编译器的把那本号是否为4.x。这里用到了Makefile中的函数filter,这是个过滤函数,函数格式如下:
$(filter pattern…,text)
filter函数表示以pattern模式过滤text字符串中的单词,仅保留符合模式pattern的单词,可以有多个模式。函数的返回值就是符合pattern的字符串。因此
这句话的含义就是在MAKE_VERSION中找出符合4.%(%为通配符)的字符,MAKE_VERSION是make工具的版本号,目前ubuntu16.04中自带的make工具版本号为4.1,可以通过make -v命令查看,如图所示。
回到顶层Makefile代码中,
这句话就是不为空的,继续向下判断,
这里又用到了一个新的函数firstword,函数firstword用于获取首单词,函数格式如下:
$(firstword text)
firstword用于取出text字符串中的第一个单词,函数的返回值就是获取到的单词,在使用make -s编译的时候,-s会作为MAKEFLAGS变量的一部分传递给Makefile。在顶层Makefile中添加如下打印代码。
注意!要在make时加入-s。
回到顶层Makefile,因此判断条件成立,不为空。当加入-s参数在make时,quiet=silent_。
最后一行导出环境变量。
最后去掉-s参数,方便查看make编译时的信息,目前导出的环境变量值如下。
5、设置编译结果输出目录
uboot可以将编译出来的目标文件输出到指定的目录中,在make时使用-0=dir来指定,就是设置目标文件输出到dir目录中。这么做的目的是为了将源文件和编译产生的文件分开,当然如果不指定的话,编译产生的文件和源文件都将在同一个目录内,一般我们不会指定-O参数。实现这一部分的顶层Makefile代码如下。
首先通过打印可以知道KBUILD_SRC的值为空,然后判断O是否来源于命令行,如果来源于命令行,条件成立,KBUILD_OUTPUT的值就为
$(O),我们未设置-O,因此KBUILD_OUTPUT的值为空。
下面再判断KBUILD_OUTPUT是否为空,如果不为空的话saved-output的值就是KBUILD_OUTPUT的值,且根据KBUILD_OUTPUT的值创建目录,至此,通过-O指定的目录就会存在。
6、代码检查
uboot支持代码检查,使用命令make C=1使能代码检查,检查那些需要重新编译的文件。make C=2用于检查所有的源文件,顶层Makefile中的代码如下:
首先判断C是否来源于命令行,如果C来源于命令行那么就将C的值赋值给KBUILD_CHECKSRC,如果没有的话,KBUILD_CHECKSRC的值就为0。
7、模块编译
在uboot中允许单独编译某个模块,使用命令make M=dir即可,就的语法make SUBDIRS=dir也是支持的。顶层Makefile有如下代码:
首先判断是否定义了SUBDIRS,如果定义了SUBDIRS,变量KBUILD_EXTMOD的值就是SUBDIRS的值,这是为了支持老语法。
下面继续判断M是否来源于命令行,来源于命令行的话,KBUILD_EXTMOD的值就是M的值。
再判断KBUILD_EXTMOD是否为空,为空的话继续执行下面。默认目标_all依赖于all,因此会先编译出all。不为空的话,默认目标_all依赖于modules,要先编译出modules,也就是模块编译。一般情况下,不会再uboot中使用模块编译。所以会先编译all这个目标。
下面判断KBUILD_SRC是否为空,如果为空的话就设置变量srctree为当前目录,即srctree为.,一般也不设置KBUILD_SRC。
下面设置objtree为.。src和obj也为.。设置VPATH的值,然后导出环境变量。
导出的环境变量的值如下图所示。
8、获取主机架构和系统
接下来顶层Makefile会获取ubuntu的主机架构和系统,有如下代码。
定义了一个变量HOSTARCH用于保存主机架构,这里调用shell命令uname -m获取主机架构,如图所示。
可以看出当前主机架构是x86_64的。shell中的 | 表示管道,意思是将左边的输出作为右边的输入,sed -e是替换命令,“sed -e s/i.86/x86”表示将管道输入的字符串中的i.86替换为x86。当前此主机架构就为HOSTARCH=x86_64。
定义变量HOSTOS用来保存主机的操作系统,先使用shell命令获取主机的操作系统,如下图所示。
可以看出当前主机的操作系统为Linux,"tr ‘[:upper]’‘[:lower:]’"表示将所有的大写字母替换为小写字母,因此HOSTOS的值为linux。
最后导出HOSTARCH为x86_64,HOSTOS为linux。
9、设置目标架构、交叉编译器和配置文件
在编译uboot的时候需要设置目标板的架构和交叉编译器,“make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-”,就是用于设置ARCH和CROSS_COMPILE的值,再顶层Makefile中代码如下。
首先判断HOSTARCH和ARCH是否相等,主机的HOSTARCH是x86_64,ARCH是arm,肯定不相等。所以CROSS_COMPILE=arm-linux-gnueabihf-。这里我们也可以在顶层Makefile中直接设置ARCH和CROSS_COMPILE的值,这样就不用在每次make时设置这两个变量的值,如图所示。
下面定义变量KCONFIG_CONFIG的值为.config,uboot是可以配置的,这里的配置文件就是.config,.config文件默认是没有的,需要使用命令make xxx_defcong,对uboot配置生成.config文件。默认情况下,.config文件和xxx_defconfig内容是一样的,因为.config文件就是从xxx_defconfg文件复制过来的。如果后面Makefile在配置过程中调整了一些参数,这些调整的参数就会写道.config文件中,而不是xxx_defconfig文件中。相当于xxx_defconfig只是一些初始参数的配置,而.config中才是实时有效的配置。
10、调用scripts/Kbuild.include
顶层Makefile会调用文件scripts/Kbuild.include文件,代码如下。
上图中使用include包含了文件scripts/Kbuild.include,此文件中定义了很多变量,如图所示。
在uboot编译的过程中会用到这些变量。
11、交叉编译工具变量的设置
在上面设置交叉编译器的时候,只是设置了CROSS_COMPILE的名字,但是交叉编译器的其他工具都还没有设置,顶层Makefile下有如下代码。
12、导出其他变量
接下来Makefile会导出大量的变量,代码如下:
将uboot需要打印的环境变量全部打印出其值。
在顶层Makefile中最后中加入打印信息。
info:
$(info MAKEFLAGS=$(MAKEFLAGS))
$(info SHELL=$(SHELL))
$(info LC_COLLATE =$(LC_COLLATE))
$(info LC_NUMERIC=$(LC_NUMERIC))
$(info quiet =$(quiet))
$(info Q=$(Q))
$(info KBUILD_VERBOSE=$(KBUILD_VERBOSE))
$(info srctree =$(srctree))
$(info objtree=$(objtree))
$(info VPATH=$(VPATH))
$(info HOSTARCH =$(HOSTARCH))
$(info HOSTOS=$(HOSTOS))
$(info KCONFIG_CONFIG=$(KCONFIG_CONFIG))
$(info KBUILD_MODULES =$(KBUILD_MODULES))
$(info KBUILD_BUILTIN=$(KBUILD_BUILTIN))
$(info KBUILD_CHECKSRC =$(KBUILD_CHECKSRC))
$(info KBUILD_SRC =$(KBUILD_SRC))
$(info KBUILD_EXTMOD=$(KBUILD_EXTMOD))
$(info VERSION =$(VERSION))
$(info PATCHLEVEL =$(PATCHLEVEL))
$(info SUBLEVEL =$(SUBLEVEL))
$(info UBOOTRELEASE =$(UBOOTRELEASE))
$(info UBOOTVERSION=$(UBOOTVERSION))
$(info ARCH =$(ARCH))
$(info CPU =$(CPU))
$(info BOARD =$(BOARD))
$(info VENDOR =$(VENDOR))
$(info SOC=$(SOC))
$(info CPUDIR =$(CPUDIR))
$(info BOARDDIR=$(BOARDDIR))
$(info CONFIG_SHELL =$(CONFIG_SHELL))
$(info HOSTCC =$(HOSTCC))
$(info HOSTCFLAGS =$(HOSTCFLAGS))
$(info HOSTLDFLAGS =$(HOSTLDFLAGS))
$(info CROSS_COMPILE =$(CROSS_COMPILE))
$(info AS =$(AS))
$(info LD =$(LD))
$(info CC=$(CC))
$(info CPP =$(CPP))
$(info AR=$(AR))
$(info NM =$(NM))
$(info LDR =$(LDR))
$(info STRIP=$(STRIP))
$(info OBJCOPY =$(OBJCOPY))
$(info OBJDUMP =$(OBJDUMP))
$(info MAKE =$(MAKE))
$(info AWK =$(AWK))
$(info PERL =$(PERL))
$(info PYTHON =$(PYTHON))
$(info HOSTCXX =$(HOSTCXX))
$(info HOSTCXXFLAGS =$(HOSTCXXFLAGS))
$(info DTC =$(DTC))
$(info CHECK =$(CHECK))
$(info CHECKFLAGS =$(CHECKFLAGS))
$(info KBUILD_CPPFLAGS =$(KBUILD_CPPFLAGS))
$(info NOSTDINC_FLAGS =$(NOSTDINC_FLAGS))
$(info UBOOTINCLUDE =$(UBOOTINCLUDE))
$(info OBJCOPYFLAGS =$(OBJCOPYFLAGS))
$(info LDFLAGS =$(LDFLAGS))
$(info KBUILD_CFLAGS =$(KBUILD_CFLAGS))
$(info KBUILD_AFLAGS =$(KBUILD_AFLAGS))
$(info MODVERDIR =$(MODVERDIR))
$(info RCS_FIND_IGNORE =$(RCS_FIND_IGNORE))
$(info RCS_TAR_IGNORE =$(RCS_TAR_IGNORE))
$(info KBUILD_DEFCONFIG =$(KBUILD_DEFCONFIG))
$(info KBUILD_KCONFIG =$(KBUILD_KCONFIG))
$(info PLATFORM_LIBS =$(PLATFORM_LIBS))
$(info PLATFORM_LIBGCC =$(PLATFORM_LIBGCC))
$(info HOST_TOOLS_ALL=y =$(HOST_TOOLS_ALL=y))
$(info CROSS_BUILD_TOOLS=y =$(CROSS_BUILD_TOOLS=y))
然后将编译的脚本文件修改为:
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
#make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- info
执行此脚本,如下所示。
MAKEFLAGS=rR -I/home/maqinggong/linux/IMX6ULL/uboot/alientek_uboot --no-print-directory -- CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm V=1
SHELL=/bin/sh
LC_COLLATE =C
LC_NUMERIC=C
quiet =
Q=
KBUILD_VERBOSE=1
srctree =.
objtree=.
VPATH=.
HOSTARCH =x86_64
HOSTOS=linux
KCONFIG_CONFIG=.config
KBUILD_MODULES =
KBUILD_BUILTIN=1
KBUILD_CHECKSRC =0
KBUILD_SRC =
KBUILD_EXTMOD=
VERSION =2016
PATCHLEVEL =03
SUBLEVEL =
UBOOTRELEASE =
UBOOTVERSION=2016.03
ARCH =arm
CPU =armv7
BOARD =mx6ullevk
VENDOR =freescale
SOC=mx6
CPUDIR =arch/arm/cpu/armv7
BOARDDIR=freescale/mx6ullevk
CONFIG_SHELL =/bin/bash
HOSTCC =cc
HOSTCFLAGS =-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTLDFLAGS =
CROSS_COMPILE =arm-linux-gnueabihf-
AS =arm-linux-gnueabihf-as
LD =arm-linux-gnueabihf-ld.bfd
CC=arm-linux-gnueabihf-gcc
CPP =arm-linux-gnueabihf-gcc -E
AR=arm-linux-gnueabihf-ar
NM =arm-linux-gnueabihf-nm
LDR =arm-linux-gnueabihf-ldr
STRIP=arm-linux-gnueabihf-strip
OBJCOPY =arm-linux-gnueabihf-objcopy
OBJDUMP =arm-linux-gnueabihf-objdump
MAKE =make
AWK =awk
PERL =perl
PYTHON =python
HOSTCXX =c++
HOSTCXXFLAGS =-O2
DTC =dtc
CHECK =sparse
CHECKFLAGS =-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise -Wno-return-void -D__CHECK_ENDIAN__ -nostdinc -isystem /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.4/include
KBUILD_CPPFLAGS =-D__KERNEL__ -D__UBOOT__
NOSTDINC_FLAGS = -nostdinc -isystem /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.4/include
UBOOTINCLUDE =-Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h
OBJCOPYFLAGS = -j .text -j .secure_text -j .rodata -j .hash -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn
LDFLAGS =
KBUILD_CFLAGS =-Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time
KBUILD_AFLAGS =-D__ASSEMBLY__ -g
MODVERDIR =.tmp_versions
RCS_FIND_IGNORE =\( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o
RCS_TAR_IGNORE =--exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git
KBUILD_DEFCONFIG =
KBUILD_KCONFIG =
PLATFORM_LIBS =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
PLATFORM_LIBGCC =-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
HOST_TOOLS_ALL=y =
CROSS_BUILD_TOOLS=y =
13、MAKECMDGOALS变量
此变量是makefile中的一个特殊变量,该变量保存了命令行参数指定的终极目标列表,没有指定目标时,该变量为空。
在顶层makefile中有如下代码。
no-dot-config-targets := clean clobber mrproper distclean \
help %docs check% coccicheck \
ubootversion backup
$(info #########################1#############################)
$(info no-dot-config-targets=$(no-dot-config-targets))
$(info MAKECMDGOALS=$(MAKECMDGOALS))
config-targets := 0
mixed-targets := 0
dot-config := 1
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endif
$(info dot-config=$(dot-config))
$(info KBUILD_EXTMOD=$(KBUILD_EXTMOD))
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(words $(MAKECMDGOALS)),1)
mixed-targets := 1
endif
endif
endif
$(info config-targets=$(config-targets))
$(info mixed-targets=$(mixed-targets))
ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.
PHONY += $(MAKECMDGOALS) __build_one_by_one
$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
@:
__build_one_by_one:
$(Q)set -e; \
for i in $(MAKECMDGOALS); do \
$(MAKE) -f $(srctree)/Makefile $$i; \
done
else
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
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.
ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf
# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
-include include/config/auto.conf.cmd
# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
@# If the following part fails, include/config/auto.conf should be
@# deleted so "make silentoldconfig" will be re-run on the next build.
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
{ rm -f include/config/auto.conf; false; }
@# include/config.h has been updated after "make silentoldconfig".
@# We need to touch include/config/auto.conf so it gets newer
@# than include/config.h.
@# Otherwise, 'make silentoldconfig' would be invoked twice.
$(Q)touch include/config/auto.conf
-include include/autoconf.mk
-include include/autoconf.mk.dep
# We want to include arch/$(ARCH)/config.mk only when include/config/auto.conf
# is up-to-date. When we switch to a different board configuration, old CONFIG
# macros are still remaining in include/config/auto.conf. Without the following
# gimmick, wrong config.mk would be included leading nasty warnings/errors.
ifneq ($(wildcard $(KCONFIG_CONFIG)),)
ifneq ($(wildcard include/config/auto.conf),)
autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \
include/config/auto.conf)
$(info autoconf_is_old=$(autoconf_is_old))
ifeq ($(autoconf_is_old),)
$(info ##########################################2################################################)
include config.mk
include arch/$(ARCH)/Makefile
endif
endif
endif
变量no-dot-config-targets保存的值为:
clean clobber mrproper distclean
help %docs check% coccicheck
ubootversion backup
变量config-targets的初值为0;
变量mixed-targets的初值为0;
变量dot-config的初值为1。
(1)、make distclean
在执行此条命令时,因为MAKECMDGOALS保存的是命令行的目标,所以其值为distclean。则下面
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
此条语句,从MAKECMDGOALS中过滤处符合no-dot-config-targets的值,很明显distclean在变量no-dot-config-targets中,结果不为空。继续执行下面的语句。
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
这条语句判断MAKECMDGOALS中除了符合变量no-dot-config-targets中的值外还有没有其他的目标,很明显目标中除了distclean没有其它的目标了,此处条件成立。所以下面dot-config := 0
。
KBUILD_EXTMOD用于模块编译,当前未使用,其值为空,则ifeq ($(KBUILD_EXTMOD),)
成立,继续向下执行ifneq ($(filter config %config,$(MAKECMDGOALS)),)
,这里将MAKECMDGOALS中符合config和%config的部分过滤出来,如果不为空继续执行,此处为空,不执行剩下的两个判断。
到此为止,
dot-config=0;
config-targets=0;
mixed-targets=0。
下面判断ifeq ($(mixed-targets),1)
,很明显不相等,不执行ifeq条件里面的语句。继续判断else ifeq ($(config-targets),1)
,很明显也不相等,继续下一个语句else ifeq ($(dot-config),1)
,很明显也不相等。
至此上面的这块代码在在make clean时结束。
(2)、make mx6ull_14x14_ddr512_emmc_defconfig
执行此条配置命令时,这条语句ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
,因为MAKECMDGOALS的值为mx6ull_14x14_ddr512_emmc_defconfig,在变量no-dot-config-targets中没有与之匹配的,所以不会执行语句内的内容,因此变量dot-config值仍为1。
之后判断ifeq ($(KBUILD_EXTMOD),)
,条件成立,继续执行ifneq ($(filter config %config,$(MAKECMDGOALS)),)
,条件成立,使config-targets的值为1,然后执行ifneq ($(words $(MAKECMDGOALS)),1)
,这条语句统计MAKECMDGOALS中的单词个数,MAKECMDGOALS中的单词个数为1,条件不成立。
至此,
config-targets=1;
mixed-targets=0。
下面执行ifeq ($(mixed-targets),1)
,条件不成立,继续判断else ifeq ($(config-targets),1)
,条件成立,执行其中的语句,里面的语句详解,请看后面一篇make xxx_defconfig的分析。
(3)、make
首先判断ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
,很明显条件不成立,此时dot-config=1。接下来判断ifeq ($(KBUILD_EXTMOD),)
,是否为空,条件成立。再判断ifneq ($(filter config %config,$(MAKECMDGOALS)),)
,条件不成立,config-targets=0,mixed-targets=0。然后判断ifeq ($(mixed-targets),1)
,条件不成立,继续判断else ifeq ($(config-targets),1)
,条件不成立,继续判断else ifeq ($(dot-config),1)
,条件成立,进入执行ifneq ($(wildcard $(KCONFIG_CONFIG)),)
,这句话是判断是否存在.config文件,条件成立,继续判断ifneq ($(wildcard include/config/auto.conf),)
,是否存在auto.conf,条件成立,继续。autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \ include/config/auto.conf)
,这句话当.config文件比include/config/auto.conf新的时候,autoconf_is_old 为.config,否则为空。因为.config文件在配置uboot的时候已经生成,而include/config/auto.conf文件是在执行语句$(Q)touch include/config/auto.conf
时刚生成的,所以autoconf_is_old的值为空。继续判断语句ifeq ($(autoconf_is_old),)
,条件成立,继续执行语句include config.mk
和include arch/$(ARCH)/Makefile
,这里的ARCH的值就是arm。
综上,在执行make编译时,包含了文件config.mk和arch/arm/Makefile。
14、ARCH、CPU、BOARD、VENDOR、SOC
之前使用make命令在打印makefile中导出的变量值时,会发现ARCH、CPU、BOARD、VENDOR和SOC并没有子makefile中被赋值。
注意!!这几个环境变量的值只有在完成make xxx_defconfig,然后再make时才可正确打印,因为几个导出的变量需要在配置时生成的.config文件和在make时包含的config.mk文件。
前面已经分析过,在make时会包含config.mk文件,通过配置生成.config文件的过程下一篇会写,这里先知道有这个事情。
在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
CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)
定义ARCH变量时,值为$(CONFIG_SYS_ARCH:“%”=%),也就是提取CONFIG_SYS_ARCH里面双引号之间的内容,然后赋值给ARCH。比如CONFIG_SYS_ARCH的值为“arm”,那么,ARCH=arm。
同理,
CPU := $(CONFIG_SYS_CPU:"%"=%)
BOARD := $(CONFIG_SYS_BOARD:"%"=%)
VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
SOC := $(CONFIG_SYS_SOC:"%"=%)
CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)
那么接下来需要确认,CONFIG_SYS_ARCH、CONFIG_SYS_CPU、CONFIG_SYS_BOARD、CONFIG_SYS_VENDOR、CONFIG_SYS_SOC这五个的值。这五个变量的值在.config中有定义,
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="mx6"
CONFIG_SYS_VENDOR="freescale"
CONFIG_SYS_BOARD="mx6ullevk"
由此,
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 (此文件不存在)