1、Makefile 语法分析 第一部分 VERSION = 2 # 给变量VERSION赋值 PATCHLEVEL = 6 # 给变量PATCHLEVEL赋值 SUBLEVEL = 22 # 给变量SUBLEVEL赋值 EXTRAVERSION = .6 # 给变量EXTRAVERSION赋值 NAME = Holy Dancing Manatees, Batman! # 给变量NAME赋值 # *DOCUMENTATION* # To see a list of typical targets execute "make help" # More info can
2、be located in ./README # Comments in this file are targeted only to the developer, do not # expect to learn how to build the kernel reading this file. # Do not: # o use make's built-in rules and variables # (this increases performance and avoid hard-to-debug behavour); # o print "Entering d
3、irectory ..."; MAKEFLAGS += -rR --no-print-directory # 操作符“+=”的作用是给变量(“+=”前面的MAKEFLAGS)追加值。 # 如果变量(“+=”前面的MAKEFLAGS)之前没有定义过,那么,“+=”会自动变成“=”; # 如果前面有变量(“+=”前面的MAKEFLAGS)定义,那么“+=”会继承于前次操作的赋值符; # 如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符 # 在执行make时的命令行选项参数被通过变量 “MAKEFLAGS”传递给子目录下的make程序。 # 对于这个变量除非使用指示符“un
4、export”对它们进行声明,它们在整个make的执行过程中始终被自动的传递给所有的子make。 # 还有个特殊变量SHELL与MAKEFLAGS一样,默认情况(没有用“unexport”声明)下在整个make的执行过程中被自动的传递给所有的子make。 # # -rR --no-print-directory # -r disable the built-in impilict rules. # -R disable the built-in variable setttings. # --no-print-directory。 # We are using a rec
5、ursive build, so we need to do a little thinking # to get the ordering right. # # Most importantly: sub-Makefiles should only ever modify files in # their own directory. If in some directory we have a dependency on # a file in another dir (which doesn't happen often, but it's often # unavoidab
6、le when linking the built-in.o targets which finally # turn into vmlinux), we will call a sub make in that other dir, and # after that we are sure that everything which is in that other dir # is now up to date. # # The only cases where we need to modify files which have global # effects are th
7、us separated out and done before the recursive # descending is started. They are now explicitly listed as the # prepare rule. # To put more focus on warnings, be less verbose as default # Use 'make V=1' to see the full commands ifdef V ifeq ("$(origin V)", "command line") KBUILD_VERBOSE = $(V
8、)
endif
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
# “ifdef”是条件关键字。语法是ifdef
9、并不操作变量的值,只是告诉你你的这个变量是哪里来的。
# 语法是: $(origin
10、 # # KBUILD_VERBOSE的值根据在命令行中是否定义了变量V, # 当没有定义时,默认为V=O,输出为short version;可以用make V=1 来输出全部的命令。 # # ifndef与ifdef语法类似,但功能恰好相反。ifndef是判断变量是不是没有被赋值。 # Call a source code checker (by default, "sparse") as part of the # C compilation. # # Use 'make C=1' to enable checking of only re-compiled fil
11、es. # Use 'make C=2' to enable checking of *all* source files, regardless # of whether they are re-compiled or not. # # See the file "Documentation/sparse.txt" for more details, including # where to get the "sparse" utility. ifdef C ifeq ("$(origin C)", "command line") KBUILD_CHECKSRC = $(C)
12、
endif
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
# ifdef是Makefile的条件关键字,其语法是:ifdef
13、BDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif
ifdef M
ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
endif
# ifdef是Makefile的条件关键字,其语法是:ifdef 14、name>;的值非空,那到表达式为真。否则,表达式为假。
#
# ifeq是Makefile的条件关键字,其语法是:ifeq ( 15、uild 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 th 16、e 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 i 17、n OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
ifeq ($(KBUILD_SRC),)
# ifeq是Makefile的条件关键字,其语法是:ifeq ( 18、tory?
ifdef O
ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif
endif
# ifdef是Makefile的条件关键字,其语法是:ifdef 19、法是:$(origin 20、此处为"make _all"。
ifneq ($(KBUILD_OUTPUT),)
# ifneq是Makefile的条件关键字,其语法是:ifneq ( 21、)
KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)
# 函数shell是make与外部环境的通讯工具,它用于命令的扩展。
# shell函数起着调用shell命令(cd $(KBUILD_OUTPUT) && /bin/pwd)和返回命令输出结果的参数的作用。
# Make仅仅处理返回结果,再返回结果替换调用点之前,make将每一个换行符或者一对回车/换行符处理为单个空格;
# 如果返回结果最后是换行符(和回车符),make将把它们去掉。
$(if $(KBUILD_OUTPUT),, \
$(error out 22、put directory "$(saved-output)" does not exist))
# 函数if对在函数上下文中扩展条件提供了支持(相对于GNU make makefile文件中的条件语句,例如ifeq指令。)
# if函数的语法是:$(if 23、串),那么$(error output directory "$(saved-output)" does not exist)会是整个函数的返回值,
# 此时如果 24、
#
# 命令“$(if $(KBUILD_OUTPUT),, \”中最后的“\”的作用是:紧接在“\”下面的“哪一行”的命令是“\”所在行的命令的延续。
# 如果要让前一个命令的参数等应用与下一个命令,那么这两个命令应该写在同一行,如果一行写不下两个命令,可以在第一行末尾添上符号"\",然后在下一行接着写。
# 如果是几个命令写在同一行,那么后面的命令是在前面命令的基础上执行。如 cd / ls 这两个命令写在同一行,那么ls显示的是根目录/下的文件和文件夹。
PHONY += $(MAKECMDGOALS)
# 将变量KBUILD_OUTPUT的值追加给变量saved-o 25、utput,
$(filter-out _all,$(MAKECMDGOALS)) _all:
$(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
KBUILD_SRC=$(CURDIR) \
KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
# 反过滤函数——filter-out,语法是:$(filter-out 26、有字符串后,剩下的作为返回值。
# 函数filter-out调用与伪目标_all在同一行。
# 伪目标_all下面的以tab开头的三行是命令,因为每行最后都有"\",所以这三行命令应该是写在同一行的,即后面的命令要受到处于它之前的那些命令的影响。
#
# $(if $(KBUILD_VERBOSE:1=),@) 含义是如果$(KBUILD_VERBOSE:1=) 不为空,则等于$@
# 自动化变量"$@"表示规则中的目标文件集,在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
# 自动化变量还有"$<"、"$%"、"$<"等。
#
# 宏变量$(M 27、AKE)的值为make命令和参数(参数可省)。
#
# 执行命令KBUILD_SRC=$(CURDIR)的结果是把变量CURDIR的值赋给变量KBUILD_SRC。
# CURDIR这个变量是Makefile提供的,代表了make当前的工作路径。
# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)
# 给变量skip-makefile追加值1.
# 命令endif # 28、 ifneq ($(KBUILD_OUTPUT),)的意思是这一行的endif与ifneq ($(KBUILD_OUTPUT),)相对应,
# 其实它本身已经解释清楚了,我只是让他变得明显一点而已。
# 命令endif # ifeq ($(KBUILD_SRC),)的意思是这一行的endif与ifeq ($(KBUILD_SRC),)相对应。
# We process the rest of the Makefile if this is the final invocation of make
ifeq ($(skip-makefile),)
# 判断变量skip-makefile 29、与空字符是否相同,即判断变量skip-makefile的值是否为空。
# If building an external module we do not care about the all: rule
# but instead _all depend on modules
PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
# 为变量PHONY追加值all。
# 判断变量KBUILD_EXTMOD的值与空字符是否相同,即判断变量KBUILD_EXTMOD的值是否为空。
# 30、定义两种不同情况下使用的规则_all: all和_all: modules
srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
TOPDIR := $(srctree)
# FIXME - TOPDIR is obsolete, use srctree/objtree
# 调用if函数,根据变量KBUILD_SRC的值是否为空,决定将变量KBUILD_SRC或者变量CURDIR的值赋给变量srctree
# 为变量TOPDIR追加变量srctree的值
objtree := $(CURDIR)
src := 31、 $(srctree)
obj := $(objtree)
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
# “VPATH”是Makefile文件中的特殊变量。
# ,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。
# 如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
export srctree objtree VPATH TOPDIR
# 为变量objtree、src、obj分别追加变量CURDIR、srctree、ob 32、jtree的值
# make使用“VPATH”变量来指定“依赖文件”的搜索路径。
# 为变量VPATH追加变量VPATH的值
# 关键词export用来声明变量,被声明的变量要被传递到下级Makefile中。
# export srctree objtree VPATH TOPDIR声明了四个变量,这四个变量在make嵌套时都将被传递到下级Makefile。
# SUBARCH tells the usermode build what the underlying arch is. That is set
# first, and if a usermode build is 33、 happening, the "ARCH=um" on the command
# line overrides the setting of ARCH below. If a native build is happening,
# then ARCH is assigned, getting whatever value it gets normally, and
# SUBARCH is subsequently ignored.
SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
34、e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
# 为变量SUBARCH追加调用shell执行sed后的返回值。
# sed 是一种在线编辑器,它一次处理一行内容。
# Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
# Cross compiling and selecting different set of gcc/bin-utils
# ----------- 35、
#
# When performing cross compilation for other architectures ARCH shall be set
# to the target architecture. (See arch/* for the possibilities).
# ARCH can be set during invocation of make:
# make ARCH=ia64
# Another way is to h 36、ave ARCH set in the environment.
# The default ARCH is the host where make is executed.
# Cross compiling and selecting different set of gcc/bin-utils
# ---------------------------------------------------------------------------
#
# When performing cross compilation for other architectures ARCH 37、 shall be set
# to the target architecture. (See arch/* for the possibilities).
# ARCH can be set during invocation of make:
# make ARCH=ia64
# Another way is to have ARCH set in the environment.
# The default ARCH is the host where make is executed.
# CROSS_COMPILE specify the prefix used fo 38、r all executables used
# during compilation. Only gcc and related bin-utils executables
# are prefixed with $(CROSS_COMPILE).
# CROSS_COMPILE can be set on the command line
# make CROSS_COMPILE=ia64-linux-
# Alternatively CROSS_COMPILE can be set in the environment.
# Default value for CROSS_C 39、OMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
# 上面已经说了,下面的这些是用于交叉编译(嵌入式linux的编译环境就是交叉编译)。
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
# 变量ARCH用来指明目标cpu的构架
# 设置变量ARCH的方法有两种,
# 一是:在命令行中 如:make ARCH=ia64;
# 二是:设置环境变量,在环境变量中默认的ARCH的值是执行mak 40、e的cpu构架
# 不论怎么弄,目的就是使编译出来的目标文件(可执行文件)面向的是你的目标平台(在嵌入式开发中)。
#
# 操作符“?= ”的作用是:如果ARCH未被定义过,那么将变量SUBARCH的值赋给变量ARCH,
# 如果变量ARCH已经被定义过,那么这条语句什么也不做。
#
# ARCH指定在嵌入式开发中你的目标板上的cpu类型(构架),如:arm,ppc,powerpc等
# 变量CROSS_COMPILE指定交叉编译用的交叉编译器,这里的CROSS_COMPILE就是让你指定交叉编译器的路径。
# 如果你设置好了PATH那么直接把这句加上就可以,如果没有那么 41、请指定路径,
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
# 将变量ARCH直接展开给变量UTS_MACHINE。
KCONFIG_CONFIG ?= .config
# 在变量KCONFIG_CONFIG没赋值的情况下,将.config赋给变量KCONFIG_CONFIG;如果已经赋值,那么什么也不做。
# SHELL used by kbuild
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ - 42、x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
# 将生成shell程序来执行if函数后返回的结果展开给变量CONFIG_SHELL;
# if函数中,在else中又嵌套了if函数。
HOSTCC = gcc
HOSTCXX = g++
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2
# 分别为变量HOSTCC 、HOSTCXX 、HOSTCFLAGS 、HOST 43、CXXFLAGS赋值。
# Decide whether to build built-in, modular, or both.
# Normally, just do built-in.
KBUILD_MODULES :=
KBUILD_BUILTIN := 1
# 分别为变量KBUILD_MODULES、KBUILD_BUILTIN 赋值。
# If we have only "make modules", don't compile built-in objects.
# When we're building modules with modversions, we n 44、eed to consider
# the built-in objects during the descend as well, in order to
# make sure the checksums are up to date before we record them.
ifeq ($(MAKECMDGOALS),modules)
KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
endif
# ifeq判断变量MAKECMDGOALS的值与modules是否相同;
# 第二行将调用if后返回的值展开给变量KBUILD_ 45、BUILTIN;
# if函数判断变量CONFIG_MODVERSIONS的值是否为非空字符串,如果是非空字符串,则执行逗号后面的1
# If we have "make 46、dif
# ifneq判断调用函数filter的返回值与空字符串是否相同。
# 如果相同,那么执行第二行,即把1赋给变量 KBUILD_MODULES
ifeq ($(MAKECMDGOALS),)
KBUILD_MODULES := 1
endif
# ifeq判断变量MAKECMDGOALS的值是否与空字符相同。如果相同,则执行第二行;
# 第二行是把1赋给变量KBUILD_MODULES。
export KBUILD_MODULES KBUILD_BUILTIN
export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
# 用关键 47、词export声明变量KBUILD_MODULES KBUILD_BUILTIN、KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD。
# 如果用关键词export声明了变量,那么被声明的变量将会被传递到下级Makefile中。
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By makin 48、g
# that echo $($(quiet)$(cmd)), we now have the possibility to set
# $(quiet) to choose other forms of output instead, e.g.
#
# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
#
# If $(quiet) is empty, the whole command will be prin 49、ted.
# If it is set to "quiet_", only the short version will be printed.
# If it is set to "silent_", nothing will be printed at all, since
# the variable $(silent_cmd_cc_o_c) doesn't exist.
#
# A simple variant is to prefix commands with $(Q) - that's useful
# for commands that shall be hidd 50、en in non-verbose mode.
#
# $(Q)ln $@ :<
#
# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
# If KBUILD_VERBOSE equals 1 then the above command is displayed.
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
# 函数ifeq判断变量KBUILD_VERBOSE的值与1是否相同。如果相同则执






