imx6ull:uboot顶层Makefile分析

版本号

MAKEFLAGES变量

20 MAKEFLAGS += -rR --include-dir=$(CURDIR)
  • Makefile有两个特殊的变量:“SHELL”和“MAKEFLAGS”,这两个变量除非使用“unexport”声明,否则的话在整个make的执行过程中,它们的值始终自动的传递给子make。
  • 在 Makefile 中使用“make”命令来执行其他的 Makefile文件
  • 上述代码使用“+=”来给变量 MAKEFLAGS 追加了一些值,“-rR”表示禁止使用内置的隐含规则和变量定义,“--include-dir”指明搜索路径,”$(CURDIR)”表示当前目录。

命令输出

  • uboot 默认编译是不会在终端中显示完整的命令,都是短命令。例如CC xxx.o和SYM u-boot.sym
  • 可以通过设置变量“V=1“来实现完整的命令输出

实现源码 

73 ifeq ("$(origin V)", "command line")
74 KBUILD_VERBOSE = $(V)
75 endif
76 ifndef KBUILD_VERBOSE
77 KBUILD_VERBOSE = 0
78 endif
79
80 ifeq ($(KBUILD_VERBOSE),1)
81 quiet =
82 Q =
83 else
84 quiet=quiet_
85 Q = @
86 endif
  • 代码中先使用 ifeq 来判断"$(origin V)"和"command line"是否相等
  • 函数origin 用于告诉你变量是哪来的。语法为:
    $(origin )
    variable 是变量名,o 函数的返回值就是变量来源,因此$(origin V)就是变量 V 的来源
  • 当这两个相等的时候变量 KBUILD_VERBOSE 就等于 V 的值,比如在命令行中输 入 “ V=1 “ 的 话 那 么 KBUILD_VERBOSE=1 。如果没有在命令行输入V的话KBUILD_VERBOSE=0
  • 第 80 行判断 KBUILD_VERBOSE 是否为 1,如果 KBUILD_VERBOSE 为 1 的话变量 quiet和 Q 都为空,如果 KBUILD_VERBOSE=0 的话变量 quiet 为“quiet_“,变量 Q 为“@”
  • Makefile 中会用到变量 quiet 和 Q 来控制编译的时候是否在终端输出完整的命令
  • Q的作用。在顶层Makefile 中有很多如下所示的命令:$(Q)$(MAKE) $(build)=tools
    当 V=0 的话上述命令展开就是“@ make $(build)=tools”,make 在执行的时候默认会在终端输出命令,但是在命令前面加上“@”就不会在终端输出命令了。
    当 V=1 的时候 Q 就为空,上述命令就是“make $(build)=tools”,因此在 make 执行的过程,命令会被完整的输出在终端上
  • quiet的作用。有些命令会有两个版本,比如:
    quiet_cmd_sym ?= SYM $@
    cmd_sym ?= $(OBJDUMP) -t $< > $@
    sym 命令分为“quiet_cmd_sym”和“cmd_sym”两个版本,这两个命令的功能都是一样的,区别在于 make 执行的时候输出的命令不同。quiet_cmd_xxx 命令输出信息少,也就是短命令,而 cmd_xxx 命令输出信息多,也就是完整的命令。那么Makefile中就会使用变量quiet来指向这两个版本中的其中一个,进而控制命令的输出形式
  • 如果变量 quiet 为空的话,整个命令都会输出。
    如果变量 quiet 为“quiet_”的话,仅输出短版本。
    如果变量 quiet 为“silent_”的话,整个命令都不会输出

静默输出

  • 编译的时候使用“make -s”即可实现静默输出

实现源码

88 # If the user is running make -s (silent mode), suppress echoing of
89 # commands
90
91 ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
92 ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
93 quiet=silent_
94 endif
95 else # make-3.8x
96 ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
97 quiet=silent_
98 endif
99 endif
100
101 export quiet Q KBUILD_VERBOSE
  • 第91行判断当前正在使用的编译器版本号是否为4.x
  •  filter 函数是个过滤函数,函数格式如下:
    $(filter ,)
    filter 函数表示以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,可以有多个模式。函数返回值就是符合 pattern 的字符串。
  • $(filter 4.%,$(MAKE_VERSION))的含义就是在字符串“MAKE_VERSION”中找出符合“4.%”的字符(%为通配符),MAKE_VERSION 是编译器的版本号,我们当前使用的交叉编译器版本号为 4.9.4,所以肯定可以找出“4.%”。因此$(filter 4.%,$(MAKE_VERSION))不为空,条件成立
  • 第 92 行判断MAKEFLAGS的第一个单词中是否包含s
  • 函数 firstword 是获取首单词,函数格式如下:
    $(firstword )
    firstword 函数用于取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词
  • 当使用“make -s”编译的时候,“-s”会作为 MAKEFLAGS 变量的一部分传递给 Makefile
  • 第 101 行  使用 export 导出变量 quiet、Q 和 KBUILD_VERBOSE

设置编译结果输出目录

  • uboot 可以将编译出来的目标文件输出到单独的目录中,在 make 的时候使用“O”来指定输出目录,比如“make O=out”就是设置目标文件输出到 out 目录中
  • 这么做是为了将源文件和编译产生的文件分开,当然也可以不指定 O 参数,不指定的话源文件和编译产生的文件都在同一个目录内

实现源码 

103 # kbuild supports saving output files in a separate directory.
104 # To locate output files in a separate directory two syntaxes are
supported.
105 # In both cases the working directory must be the root of the
kernel src.
106 # 1) O=
107 # Use "make O=dir/to/store/output/files/"
108 #
109 # 2) Set KBUILD_OUTPUT
110 # Set the environment variable KBUILD_OUTPUT to point to the
directory
111 # where the output files shall be placed.
112 # export KBUILD_OUTPUT=dir/to/store/output/files/
113 # make
114 #
115 # The O= assignment takes precedence over the KBUILD_OUTPUT
environment
116 # variable.
117
118 # KBUILD_SRC is set on invocation of make in OBJ directory
119 # KBUILD_SRC is not intended to be used by the regular user (for
now)
120 ifeq ($(KBUILD_SRC),)
121
122 # OK, Make called in directory where kernel src resides
123 # Do we want to locate output files in a separate directory?
124 ifeq ("$(origin O)", "command line")
125 KBUILD_OUTPUT := $(O)
126 endif
127
128 # That's our default target when none is given on the command line
129 PHONY := _all
130 _all:
131
132 # Cancel implicit rules on top Makefile
133 $(CURDIR)/Makefile Makefile: ;
134
135 ifneq ($(KBUILD_OUTPUT),)
136 # Invoke a second make in the output directory, passing relevant
variables
137 # check that the output directory actually exists
138 saved-output := $(KBUILD_OUTPUT)
139 KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd
$(KBUILD_OUTPUT) \
140 && /bin/pwd)
......
155 endif # ifneq ($(KBUILD_OUTPUT),)
156 endif # ifeq ($(KBUILD_SRC),)
  • 第 124 行判断“O”是否来自于命令行,如果来自命令行的话条件成立,KBUILD_OUTPUT就为$(O),因此变量 KBUILD_OUTPUT 就是输出目录
  • 第 135 行判断 KBUILD_OUTPUT 是否为空
  • 第 139 行调用 mkdir 命令,创建 KBUILD_OUTPUT 目录,并且将创建成功以后的绝对路径赋值给 KBUILD_OUTPUT。至此,通过 O 指定的输出目录就存在了

代码检查

  • uboot 支持代码检查,使用命令“make C=1”使能代码检查,检查那些需要重新编译的文件。“make C=2”用于检查所有的源码文件

实现源码 

166 # Call a source code checker (by default, "sparse") as part of the
167 # C compilation.
168 #
169 # Use 'make C=1' to enable checking of only re-compiled files.
170 # Use 'make C=2' to enable checking of *all* source files,
regardless
171 # of whether they are re-compiled or not.
172 #
173 # See the file "Documentation/sparse.txt" for more details,
including
174 # where to get the "sparse" utility.
175
176 ifeq ("$(origin C)", "command line")
177 KBUILD_CHECKSRC = $(C)
178 endif
179 ifndef KBUILD_CHECKSRC
180 KBUILD_CHECKSRC = 0
181 endif
  • 第 176 行判断 C 是否来源于命令行,如果 C 来源于命令行,那就将 C 赋值给变量KBUILD_CHECKSRC,如果命令行没有 C 的话 KBUILD_CHECKSRC 就为 0

模块编译

  • 在 uboot 中允许单独编译某个模块,使用命令“make M=dir”即可,旧语法“make SUBDIRS=dir”也是支持的

实现源码 

183 # Use make M=dir to specify directory of external module to build
184 # Old syntax make ... SUBDIRS=$PWD is still supported
185 # Setting the environment variable KBUILD_EXTMOD take precedence
186 ifdef SUBDIRS
187 KBUILD_EXTMOD ?= $(SUBDIRS)
188 endif
189
190 ifeq ("$(origin M)", "command line")
191 KBUILD_EXTMOD := $(M)
192 endif
193
194 # If building an external module we do not care about the all: rule
195 # but instead _all depend on modules
196 PHONY += all
197 ifeq ($(KBUILD_EXTMOD),)
198 _all: all
199 else
200 _all: modules
201 endif
202
203 ifeq ($(KBUILD_SRC),)
204 # building in the source tree
205 srctree := .
206 else
207 ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
208 # building in a subdirectory of the source tree
209 srctree := ..
210 else
211 srctree := $(KBUILD_SRC)
212 endif
213 endif
214 objtree := .
215 src := $(srctree)
216 obj := $(objtree)
217
218 VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
219
220 export srctree objtree VPATH
  • 第 186 行 判 断 是 否 定 义 了 SUBDIRS , 如 果 定 义 了 SUBDIRS , 变 量KBUILD_EXTMOD=SUBDIRS,这里是为了支持老语法“make SUBIDRS=dir”
  • 第 190 行判断是否在命令行定义了 M,如果定义了的话 KBUILD_EXTMOD=$(M)
  • 第 197 行判断 KBUILD_EXTMOD 是否为空,如果为空的话目标_all 依赖 all,因此要先编译出 all。否则的话默认目标_all 依赖 modules,要先编译出 modules,也就是编译模块。一般情况下我们不会在 uboot 中编译模块,所以此处会编译 all 这个目标
  • 第 203 行判断 KBUILD_SRC 是否为空,如果为空的话就设置变量 srctree 为当前目录,即srctree 为“.”,一般不设置 KBUILD_SRC
  • 第 214 行设置变量 objtree 为当前目录
  • 第 215 和 216 行分别设置变量 src 和 obj,都为当前目录
  • 第 218 行设置 VPATH
  • 第 220 行导出变量 scrtree、objtree 和 VPATH

获取主机架构和系统

实现源码 

227 HOSTARCH := $(shell uname -m | \
228 sed -e s/i.86/x86/ \
229 -e s/sun4u/sparc64/ \
230 -e s/arm.*/arm/ \
231 -e s/sa110/arm/ \
232 -e s/ppc64/powerpc/ \
233 -e s/ppc/powerpc/ \
234 -e s/macppc/powerpc/\
235 -e s/sh.*/sh/)
236
237 HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
238 sed -e 's/\(cygwin\).*/cygwin/')
239
240 export HOSTARCH HOSTOS

设置目标架构、交叉编译器和配置文件

  • 编 译 uboot 的 时 候 需 要 设 置 目 标 板 架 构 和 交 叉 编 译 器 ,“ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-”就是用于设置 ARCH 和 CROSS_COMPILE

实现源码 

244 # set default to nothing for native builds
245 ifeq ($(HOSTARCH),$(ARCH))
246 CROSS_COMPILE ?=
247 endif
248
249 KCONFIG_CONFIG ?= .config
250 export KCONFIG_CONFIG
  • 第 245 行判断 HOSTARCH 和 ARCH 这两个变量是否相等,主机架构(变量 HOSTARCH)是x86_64,而我们编译的是 ARM 版本 uboot,肯定不相等,所以 CROS_COMPILE= arm-linux-gnueabihf-
  • 第 249 行定义变量 KCONFIG_CONFIG,uboot 是可以配置的,这里设置配置文件为.config,.config 默认是没有的,需要使用命令“make xxx_defconfig”对 uboot 进行配置,配
    置完成以后就会在 uboot 根目录下生成.config。默认情况下.config 和 xxx_defconfig 内容是一样的,因为.config 就是从 xxx_defconfig 复制过来的。如果后续自行调整了 uboot 的一些配置参数,那么这些新的配置参数就添加到了.config 中,而不是 xxx_defconfig。相当于 xxx_defconfig 只是一些初始配置,而.config 里面的才是实时有效的配置

调用scripts/Kbuild.include

  • 主 Makefile 会调用文件 scripts/Kbuild.include 这个文件

实现源码 

327 # We need some generic definitions (do not try to remake the file).
328 scripts/Kbuild.include: ;
329 include scripts/Kbuild.include
  • 使用“include”包含了文件 scripts/Kbuild.include,此文件里面定义了很多变量
  • 在 uboot 的编译过程中会用到 scripts/Kbuild.include 中的这些变量

交叉编译工具变量设置

实现源码 

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
337 else
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

 

导出其它变量

实现源码 

368 export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
369 export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
370 export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
371 export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
372 export MAKE AWK PERL PYTHON
373 export HOSTCXX HOSTCXXFLAGS DTC CHECK CHECKFLAGS
374
375 export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
376 export KBUILD_CFLAGS KBUILD_AFLAGS
  • 这些变量中大部分都已经在前面定义了
  • ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR这 7 个变量在顶层 Makefile 是找不到的,这 7 个变量就是在 uboot 根目录下的 config.mk 里面定义的,具体的值参考imx6ull:uboot根目录config.mk分析
  • 根据分析可知:
    ARCH = arm
    CPU = armv7
    BOARD = mx6ullevk
    VENDOR = freescale
    SOC = mx6
    CPUDIR = arch/arm/cpu/armv7
    BOARDDIR = freescale/mx6ullevk

imx6ull:uboot的make xxx_defconfig 过程分析

imx6ull:uboot顶层Makefile分析_第1张图片

总结:一通分析下来,绕来绕去,除了上图中的调用关系外,感觉没有得到什么有用的内容。这里需要明白的是make xxx_defconfig的执行过程中从顶层makefile开始,中间用到了许多./scripts目录下的文件以及有该目录下的某些文件得到的主机程序,最终我们看到的效果就是在uboot根目录下生成了一个.config文件,该文件中的部分内容就来自于xxx_defconfig

imx6ull:uboot的make过程分析 

imx6ull:uboot顶层Makefile分析_第2张图片

总结(待完善)

执行的操作

变量的含义

你可能感兴趣的:(嵌入式linux,linux,uboot)