Linux Makefile学习(一)

  • Post author:
  • Post category:linux



本文是最近学习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



版权声明:本文为yebincedu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。