U-Boot 顶层 Makefile 分析一

  顶层 Makefile 也就是 uboot 根目录下的 Makefile 文件。

1、版本号

VERSION = 2016
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
NAME =

  VERSION 是主版本号, PATCHLEVEL 是补丁版本号, SUBLEVEL 是次版本号

2、递归调用makefile

  Makefile 中使用“make”命令来执行其他的 Makefile文件,一般都是子目录中的 Makefile 文件。

MAKEFLAGS += -rR --include-dir=$(CURDIR)

# Avoid funny character set dependencies
unexport LC_ALL
LC_COLLATE=C
LC_NUMERIC=C
export LC_COLLATE LC_NUMERIC

# Avoid interference with shell env settings
unexport GREP_OPTIONS

  上述代码使用“+=”来给变量 MAKEFLAGS 追加了一些值,“-rR”表示禁止使用内置的隐含规则和变量定义,“–include-dir”指明搜索路径, ”$(CURDIR)”表示当前目录。
  “export”导出要传递给子 make 的变量。
  “unexport”声明不导出变量传递给子makefile。

3、命令输出

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif

  uboot 默认编译是不会在终端中显示完整的命令,都是短命令。上述代码中先使用 ifeq 来判断"KaTeX parse error: Expected 'EOF', got '&' at position 110: …告诉你变量是哪来的,语法为: &̲emsp;&emsp;(origin < variable>)

  variable 是变量名,origin 函数的返回值就是变量来源,因此$ (origin V)就是变量 V 的来源。如果变量 V 是在命令行定义的那么它的来源就是"command line",这样"KaTeX parse error: Expected 'EOF', got '&' at position 156: …ILD_VERBOSE=0。 &̲emsp;&emsp;Make… (Q) $(MAKE) $(build)=tools
  如果 V=0 的话上述命令展开就是“@ make $(build)=tools”, make 在执行的时候默认会在终端输出命令,但是在命令前面加上“@”就不会在终端输出命令了。当 V=1 的时候 Q 就为空,上述命令就是“make $(build)=tools”,因此在 make 执行的过程,命令会被完整的输出在终端上。

4、静默输出

  设置 V=0 或者在命令行中不定义 V 的话,编译 uboot 的时候终端中显示的短命令,但是还是会有命令输出,有时候我们在编译 uboot 的时候不需要输出命令,这个时候就可以使用 uboot 的静默输出功能。编译的时候使用“make -s”即可实现静默输出,顶层 Makefile中相应的代码如下:

# If the user is running make -s (silent mode), suppress echoing of
# commands

ifneq ($(filter 4.%,$(MAKE_VERSION)),)	# make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
  quiet=silent_
endif
else					# make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
  quiet=silent_
endif
endif

export quiet Q KBUILD_VERBOSE

  首先判断当前正在使用的编译器版本号是否为 4.x,判断 $ (filter 4.%,$ (MAKE_VERSION))和“ ” (空)是否相等,如果不相等的话就成立,执行里面的语句。也就是说 $ (filter4.%,$ (MAKE_VERSION))不为空的话条件就成立,这里用到了 Makefile 中的 filter 函数,这是个过滤函数,函数格式如下:
  $ (filter <pattern…>, )
  filter 函数表示以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,可以有多个模式。函数返回值就是符合 pattern 的字符串。因此$ (filter 4.%,$ (MAKE_VERSION))的含义就是在字符串“MAKE_VERSION”中找出符合“ 4.%”的字符(%为通配符),MAKE_VERSION 是make工具的版本号
  判断语句如果$ (filter %s ,$ (firstword x$ (MAKEFLAGS)))不为空的话条件成立,变量 quiet 等于“silent_”。这里也用到了函数 filter,在$ (firstword x$ (MAKEFLAGS)))中过滤出符合“%s”的单词。到了函数firstword,函数 firstword 是获取首单词,函数格式如下:
  $(firstword )
  firstword 函数用于取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词。当使用“make -s”编译的时候,“-s”会作为 MAKEFLAGS 变量的一部分传递给 Makefile。

5、设置编译结果输出目录

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

# kbuild supports saving output files in a separate directory.
# To locate output files in a separate directory two syntaxes are supported.
# In both cases the working directory must be the root of the kernel src.
# 1) O=
# Use "make O=dir/to/store/output/files/"
#
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.

# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
ifeq ($(KBUILD_SRC),)

# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
ifeq ("$(origin O)", "command line")
  KBUILD_OUTPUT := $(O)
endif

# That's our default target when none is given on the command line
PHONY := _all
_all:

# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;

ifneq ($(KBUILD_OUTPUT),)
# Invoke a second make in the output directory, passing relevant variables
# check that the output directory actually exists
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \
								&& /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
     $(error failed to create output directory "$(saved-output)"))

PHONY += $(MAKECMDGOALS) sub-make

$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
	@:

sub-make: FORCE
	$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
	-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))

# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)

  首先判断“O”是否来自于命令行,如果来自命令行的话条件成立, KBUILD_OUTPUT就为$(O),因此变量 KBUILD_OUTPUT 就是输出目录。
  然后判断 KBUILD_OUTPUT 是否为空。
  再调用 mkdir 命令,创建 KBUILD_OUTPUT 目录,并且将创建成功以后的绝对路径赋值给 KBUILD_OUTPUT。至此,通过 O 指定的输出目录就存在了。

猜你喜欢

转载自blog.csdn.net/xxxx123041/article/details/119916872