您的位置:首页 > 运维架构 > Linux

Linux Makefile学习(一)

2015-07-13 21:39 381 查看
本文是最近学习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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: