Linux Makefile学习(一)

来源:互联网 发布:mac尘埃3汉化 编辑:程序博客网 时间:2024/05/17 23:10

本文是最近学习Linux Makefile的一些内容,Linux版本号为2.6.32。Makefile内容较多,分成了几个阶段。这里写下来,作为积累,

也想和大家分享下学习过程。

==============================================================================

 

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 22
EXTRAVERSION = .6
NAME = Holy Dancing Manatees, Batman!

# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
# More info can 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.

# *文档*
# 执行“make help”可以查看典型的目标
# 更多信息可以在./README中查看
# 这个文件的内容只适合不期望知道怎么构建内核的开发者来阅读。

# Do not:
# o  use make's built-in rules and variables
#    (this increases performance and avoid hard-to-debug behavour);
# o  print "Entering directory ...";

# 不做哪些: ps:下面列出的都是makefile做的事情
# o  使用内嵌规则和变量
  (这样做可以提高性能,同时便于调试)
# o  打印“Entering directory ...”

MAKEFLAGS += -rR --no-print-directory  r 取消所有内嵌的隐含规则
           R 取消 make 内嵌的隐含变量
       --no-print-directory 在 make 进入一个目录读取 Makefile 之前打印工作目录
      
# We are using a recursive 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
# unavoidable 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 thus separated out and done before the recursive
# descending is started. They are now explicitly listed as the
# prepare rule.

# 我们使用递归的形式构建,所以我们需要花些心思了解权限职责问题。
#
# 最主要的:子Makefiles应该只修改它们自己目录下的文件。如果在某个目录下,我们依赖另一个目录下的文件
# (这种情况不经常发生,但当链接built-in.o文件时,这是不可避免的,built-in.o文件最终链接进vmlinux),
# 我们将调用另一个目录下的子make,在那之后,我们确定在这个目录下的所有文件都是最新的。
#
# 唯一的情况我们需要修改会造成全局影响的文件,这种情况被分离出来,在递归开始前完成。他们被作为预备规
# 则明确列出来了。

# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands

# 为了专注于警告信息,默认信息为非冗余的。
# 用‘make V=1’可以看完整的命令。

ifdef V
  ifeq ("$(origin V)", "command line")  //判断V是否为命令行参数
    KBUILD_VERBOSE = $(V)
  endif
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

# 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 files.
# 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.

# 在C编译时使用代码检测工具(默认为“sparse”) sparse是由linux之父开发的, 目的就是提供一个静态检查
#                                               代码的工具, 从而减少linux内核的隐患
#
# 使用‘make C=1’使能仅检测预编译文件。
# 使用‘make C=2’使能检测所有文件,不论是不是预编译文件
#
# “Documentation/sparse.txt”中有更详细的描述,包括如何获取“sparse”效用。

ifdef C
  ifeq ("$(origin C)", "command line")
    KBUILD_CHECKSRC = $(C)
  endif
endif
ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif

# Use make M=dir to specify directory of external module to build
# Old syntax make ... SUBDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence

# 使用“make M=dir”来指明所要构建的外部模块目录。
# 旧的语法“make ... SUBDIRS=$PWD”仍然被支持
# 设置环境变量KBUILD_EXTMOD优先级更高。

ifdef SUBDIRS
  KBUILD_EXTMOD ?= $(SUBDIRS)   //KBUILD_EXTMOD没有定义时等于$(SUBDIRS) 
endif

ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif

# 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支持将输出文件保存在单独的目录下。
# 将输出文件防止在单独的目录下有两种语法被支持。
# 两种方法的工作目录必须是内核源码的根目录。
# 1) O=
# 使用"make O=dir/to/store/output/files/"
#
# 2) 设置KBUILD_OUTPUT变量
# 设置KBUILD_OUTPUT环境变量去指明输出文件放置的目录。
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# “O=”的方式比设置KBUILD_OUTPUT环境变量更优先考虑。


# 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)

# KBUILD_SRC在OBJ目录下调用make时设置的。
# KBUILD_SRC现在不是为了让一般用户使用的。
ifeq ($(KBUILD_SRC),)

# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?

# Make在内核源文件目录下调用。
# 我们是否想将输出文件放置到独立的目录中?
ifeq ("$(origin O)", "command line")  //判断O是否为命令行参数
  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
# 取消顶层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
PS:这个地方翻译不太理解,大致意思是检测KBUILD_OUTPUT目录是否存在。
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)  //KBUILD_OUTPUT变为绝对路径
$(if $(KBUILD_OUTPUT),, \     
     $(error output directory "$(saved-output)" does not exist))
//如果KBUILD_OUTPUT为空,打印错误输出*** output directory "xxx" does not exist。

PHONY += $(MAKECMDGOALS) sub-make   //MAKECMDGOALS指定make的终极目标

$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make 
 $(Q)@:             //过滤掉$(MAKECMDGOALS)中_all sub-make
               //$(CURDIR)/Makefile
sub-make: FORCE
 $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
 KBUILD_SRC=$(CURDIR) \
 KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile \
 $(filter-out _all sub-make,$(MAKECMDGOALS))
 
//(if $(KBUILD_VERBOSE:1=),@)使用了变量的替换引用。格式为“ $(VAR:A=B)”(或者“ ${VAR:A=B}”),意思是,
//替换变量“ VAR”中所有“ A”字符结尾的字为“ B”结尾的字。KBUILD_VERBOSE结尾为1时,整个表达式为空,否则
//为@,为@时是希望后面的命令能够静默执行。

# Leave processing to above invocation of make
# 离开处理到上面的make调用
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)

# We process the rest of the Makefile if this is the final invocation of make
# 如果这是最后的make调用,我们处理Makefile剩余部分
ifeq ($(skip-makefile),)

# If building an external module we do not care about the all: rule
# but instead _all depend on modules
# 如果是构建一个外部模块,我们不用关心all的规则,但是需要关系_all所以来的modules
PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif

srctree  := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
objtree  := $(CURDIR)
src  := $(srctree)
obj  := $(objtree)

VPATH  := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))

export srctree objtree VPATH


# SUBARCH tells the usermode build what the underlying arch is.  That is set
# first, and if a usermode build is 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通知自定义模式构建什么样的底层架构。这是最先设置的地方,如果自定义模式构建开始了,"ARCH=um"
# 命令行参数重写ARCH设置。如果本地构建开始了,ARCH被指定好了,不管获取到什么值,SUBARCH随后都会被忽
# 略。

SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
      -e s/arm.*/arm/ -e s/sa110/arm/ \
      -e s/s390x/s390/ -e s/parisc64/parisc/ \
      -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
      -e s/sh[234].*/sh/ )

# Cross compiling and selecting different set of gcc/bin-utils
# ---------------------------------------------------------------------------
#
# 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 have ARCH set in the environment.
# The default ARCH is the host where make is executed.

# 交叉编译,选择不同的gcc/bin-utils设置。
# ---------------------------------------------------------------------------
#
# 当执行别的架构下交叉编译,ARCH被设置成目标架构.(看arch/*可以知道支持哪些架构)。
# ARCH在make调用的过程中可以设置:
# make ARCH=ia64
# 另外一种方法是在环境变量中设置ARCH。
# 默认的ARCH是make执行的主机端架构。

# CROSS_COMPILE specify the prefix used for 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_COMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile

# CROSS_COMPILE指定编译过程中使用的所有可执行文件的前缀。只有gcc和bin-utils可执行文件才会有
# $(CROSS_COMPILE)前缀。
# CROSS_COMPILE可以在命令行中设置。
# make CROSS_COMPILE=ia64-linux-
# CROSS_COMPILE也可以在环境变量中设置。
# CROSS_COMPILE默认值是没有前缀的。
# 注意:一些架构在它们arch/*/Makefile文件中指定CROSS_COMPILE变量。
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH  ?= arm
CROSS_COMPILE ?= arm-linux-

# Architecture as present in compile.h
UTS_MACHINE  := $(ARCH)
SRCARCH  := $(ARCH)

# Additional ARCH settings for x86
# 对x86架构有额外设置
ifeq ($(ARCH),i386)
        SRCARCH := x86
endif
ifeq ($(ARCH),x86_64)
        SRCARCH := x86
endif

# Additional ARCH settings for sparc
ifeq ($(ARCH),sparc64)
       SRCARCH := sparc
endif

# Additional ARCH settings for sh
ifeq ($(ARCH),sh64)
       SRCARCH := sh
endif

# Where to locate arch specific headers
# 放置架构特定头文件的目录
hdr-arch  := $(SRCARCH)

ifeq ($(ARCH),m68knommu)
       hdr-arch  := m68k
endif

KCONFIG_CONFIG ?= .config

# SHELL used by kbuild
# kbuild使用的SHELL
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \  //如果$BASH存在且是可执行的则为真
   else if [ -x /bin/bash ]; then echo /bin/bash; \
   else echo sh; fi ; fi)

HOSTCC       = gcc
HOSTCXX      = g++
HOSTCFLAGS   = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2
//-Wall     基本打开了所有需要注意的警告信息。
//-Wmissing-prototypes 
//-Wstrict-prototypes 使用了非原型的函数声明时给出警告
//-O2     编译优化级别
//-fomit-frame-pointer 

# Decide whether to build built-in, modular, or both.
# Normally, just do built-in.
# 决定构建built-in还是modular,或者两者同时构建。
# 通常之构建built-in。

KBUILD_MODULES :=
KBUILD_BUILTIN := 1

# If we have only "make modules", don't compile built-in objects.
# When we're building modules with modversions, we need 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.

#   如果我们执行"make modules",就不编译built-in目标。
# 当我们使用modversions构建模块,我们需要在进入下层目录是考虑built-in目标,这是为了确保在我们记录
# 他们之间,校验码是最新的。PS:这点不理解,翻译的也有问题。

ifeq ($(MAKECMDGOALS),modules)
  KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
endif

# If we have "make <whatever> modules", compile modules
# in addition to whatever we do anyway.
# Just "make" or "make all" shall build modules as well

# 如果我们执行了"make <whatever> modules",就会编译我们指定的模块。
# 只执行"make"或"make all"将会编译所有模块。

ifneq ($(filter all _all modules,$(MAKECMDGOALS)),)
  KBUILD_MODULES := 1
endif

ifeq ($(MAKECMDGOALS),)
  KBUILD_MODULES := 1
endif

export KBUILD_MODULES KBUILD_BUILTIN
export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD

# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
# 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 printed.
# 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 hidden 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.

# 美化输出
# ---------------------------------------------------------------------------
#
# 通常我们在执行命令前会输出整个命令。通过echo $($(quiet)$(cmd)),我们现在可以设置$(quiet)去选择别的
# 输出格式,例如:
#
#         quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
#         cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
#
# 如果$(quiet)为空,整个命令都会被打印。
# 如果$(quiet)被设置成"quiet_",只有会打印简短的版本。
# 如果$(quiet)被设置成"silent_",什么都不会打印,因为$(silent_cmd_cc_o_c)值不存在。
#
# 一个简单的变量$(Q)被用于命令行的前缀——这对于在非冗余模式下隐藏命令非常有用。
#
# $(Q)ln $@ :<
#
# 如果KBUILD_VERBOSE等于0,上面的命令就会被隐藏。
# 如果KBUILD_VERBOSE等于1,上面的命令就会被打印。

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

# If the user is running make -s (silent mode), suppress echoing of
# commands
# 如果用户运行make -s(静默模式),限制所有命令的输出。

ifneq ($(findstring s,$(MAKEFLAGS)),) //在$(MAKEFLAGS)中找到字符串s
  quiet=silent_
endif

export quiet Q KBUILD_VERBOSE


# Look for make include files relative to root of kernel src
# 设置包含文件的路径,该路径相对于内核源码的根目录。
MAKEFLAGS += --include-dir=$(srctree)  //用于make递归调用时传递命令行选项

# We need some generic definitions (do not try to remake the file).
# 我们需要一些一般的定义(不要尝试remake这个文件)。
$(srctree)/scripts/Kbuild.include: ;
include $(srctree)/scripts/Kbuild.include

# Make variables (CC, etc...)
# Make变量(CC,等...)

AS  = $(CROSS_COMPILE)as
LD  = $(CROSS_COMPILE)ld
CC  = $(CROSS_COMPILE)gcc
CPP  = $(CC) -E
AR  = $(CROSS_COMPILE)ar
NM  = $(CROSS_COMPILE)nm
STRIP  = $(CROSS_COMPILE)strip
OBJCOPY  = $(CROSS_COMPILE)objcopy
OBJDUMP  = $(CROSS_COMPILE)objdump
AWK  = awk
GENKSYMS = scripts/genksyms/genksyms
INSTALLKERNEL  := installkernel
DEPMOD  = /sbin/depmod
KALLSYMS = scripts/kallsyms
PERL  = perl
CHECK  = sparse

CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
    -Wbitwise -Wno-return-void $(CF)
MODFLAGS = -DMODULE
CFLAGS_MODULE   = $(MODFLAGS)
AFLAGS_MODULE   = $(MODFLAGS)
LDFLAGS_MODULE  = -T $(srctree)/scripts/module-common.lds
CFLAGS_KERNEL =
AFLAGS_KERNEL =
CFLAGS_GCOV = -fprofile-arcs -ftest-coverage

0 0
原创粉丝点击