linux内核makefile——寻找第一个target

内核版本为linux-2.6.31.14


VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 31
EXTRAVERSION = .14
NAME = Man-Eating Seals of Antiquity

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

# Do not:
# o  use make's built-in rules and variables
#    (this increases performance and avoids hard-to-debug behaviour);
# o  print "Entering directory ...";
MAKEFLAGS += -rR --no-print-directory
#####################################################################
#控制编译器参数,不用管它
#####################################################################

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

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

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif
########################################################################################
#函数origin并不操作变量的值,只是告诉你你的这个变量是哪里来的,
#其语法是: $(origin <variable>;)。
#注意,<variable>是变量的名字,不应该是引用。所以你最好不要在<variable>中使用“$”字符。
#origin 函数会以其返回值来告诉你这个变量的“出生情况”,
#origin函数的返回值有:
#“undefined”从来没有定义过、
#“default”是一个默认的定义、
#“environment”是一个环境变量、
#“file”这个变量被定义在Makefile中、
#“command line”这个变量是来自命令行的、
#“override”是被override指示符重新定义的、
#“automatic”是一个命令运行中的自动化变量
#
#这些信息对于我们编写 Makefile 是非常有用的,例如,在这里我们make命令后跟了一个参数“V”,
#而我们的环境中也有一个环境变量“V”,此时,我们想判断一下,如果变量来源于参数,
#那么我们就把之重定义了,如果来源于非命令行或环境变量,那么我们就不重新定义它。
#
#KBUILD_VERBOSE的值根据在命令行中是否定义了变量V,
#当没有定义时,默认为V=0,输出为short version;
#可以用make V=1 来输出全部的命令。
######################################################################


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

ifeq ("$(origin C)", "command line")
  KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif
########################################################################################
# make C=1 仅检查被编辑过的文件
# make C=2 强制检查所有文件
########################################################################################


# 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
ifdef SUBDIRS
  KBUILD_EXTMOD ?= $(SUBDIRS)
endif

ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif
########################################################################################
#编译驱动的时候经常用到的makefile为
#all:
#	make -C $(KERN_DIR) M=`pwd` modules 
#	
# -C $(KERN_DIR) 到内核源码目录下读取那里的Makefile;
# M=$(PWD) 然后返回到当前目录继续读入、执行当前的Makefile。
#这里就是判断make后面是否定义了M
########################################################################################


# 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
########################################################################################
#可以把Makefele的输出指定到特定的文件夹中
#例如:make O=dir/to/store/output/files/
########################################################################################


# That's our default target when none is given on the command line
PHONY := _all
_all:
########################################################################################
#PHONY里的都是伪目标
#Makefile中同名的目标会被后面的覆盖,这不是最后一个_all,所以这个_all没用
########################################################################################


# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;
########################################################################################
#取消makefile的隐含规则
#神马是隐含规则呢?不去管了,晕头了
########################################################################################


ifneq ($(KBUILD_OUTPUT),)
########################################################################################
#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 cd $(KBUILD_OUTPUT) && /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
     $(error output directory "$(saved-output)" does not exist))

PHONY += $(MAKECMDGOALS) sub-make

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

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

# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
########################################################################################
#KBUILD_OUTPUT为空,所以以上这段代码不执行
########################################################################################

endif # ifeq ($(KBUILD_SRC),)

# We process the rest of the Makefile if this is the final invocation of make
ifeq ($(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
########################################################################################
#KBUILD_EXTMOD叫做Kbuild扩展模式,如果我们make M=dir,那么会将变量KBUILD_EXTMOD的值设置为dir,
#随后去执行依赖于modules的代码,就相当于执行make modules。
#这个make方法也是用来提高我们的驱动开发效率的,如果你只想编译某个具体的驱动,
#只要指定对应的子目录,就可以只编译这个驱动而不去碰其他的内核代码了。
#
#这里直接跳去执行all的代码了
########################################################################################

我们直接来看看all的代码,在top makefile中搜索all有两个结果

all: vmlinux

ifdef CONFIG_MODULES
all: modules

CONFIG_MODULES为空,第二个被忽略

这下只省一个all了,但是,不要忘了makefile也能包含文件

在第一个all下面include了一个$(srctree)/arch/$(SRCARCH)/Makefile文件,把这个all给覆盖了,所以我们执行的是include文件中的all代码

进去看看

# Default kernel to build
all: bzImage

# KBUILD_IMAGE specify target image being built
KBUILD_IMAGE := $(boot)/bzImage

bzImage: vmlinux
	$(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
	$(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
	$(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@

all依赖于bzImage,bzImage又依赖于vmlinux,我们还是回到top makefile中看看vmlinux吧

vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
	$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
	$(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
	$(Q)$(MAKE) $(build)=Documentation
endif
	$(call vmlinux-modpost)
	$(call if_changed_rule,vmlinux__)
	$(Q)rm -f .old_version

依赖好多......我们先来看看最简单的FORCE
PHONY += FORCE
FORCE:
定义于makefile的最后,是个命令和依赖都为空的伪目标,作用是尽管vmlinux存在,其他依赖没有更新,命令也会被执行


再来看看vmlinux的其他依赖

vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-all  := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds  := arch/$(SRCARCH)/kernel/vmlinux.lds
export KBUILD_VMLINUX_OBJS := $(vmlinux-all)


modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
	$(call if_changed_rule,vmlinux-modpost)

ifdef CONFIG_KALLSYMS_EXTRA_PASS
last_kallsyms := 3
else
last_kallsyms := 2
endif

kallsyms.o := .tmp_kallsyms$(last_kallsyms).o

所有的依赖文件都找出来了,这样就结束了么?想的太简单了,在makefile中还有这么一行

$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;

他们三个都依赖于vmlinux-dirs

vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
		     $(net-y) $(net-m) $(libs-y) $(libs-m)))

还没完,vmlinux-dirs还有依赖

$(vmlinux-dirs): prepare scripts
	$(Q)$(MAKE) $(build)=$@


先看scripts吧
scripts: scripts_basic include/config/auto.conf
	$(Q)$(MAKE) $(build)=$(@)

PHONY += scripts_basic
scripts_basic:
	$(Q)$(MAKE) $(build)=scripts/basic

其中auto.conf是配置时生成的文件


再来看prepare

prepare: prepare0

prepare0: archprepare FORCE
	$(Q)$(MAKE) $(build)=.
	$(Q)$(MAKE) $(build)=. missing-syscalls

archprepare: prepare1 scripts_basic

prepare1: prepare2 include/linux/version.h include/linux/utsrelease.h \
                   include/asm include/config/auto.conf
	$(cmd_crmodverdir)

prepare2: prepare3 outputmakefile

outputmakefile:
ifneq ($(KBUILD_SRC),)
	$(Q)ln -fsn $(srctree) source
	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
	    $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

prepare3: include/config/kernel.release
ifneq ($(KBUILD_SRC),)
	@$(kecho) '  Using $(srctree) as source for kernel'
	$(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
		echo "  $(srctree) is not clean, please run 'make mrproper'";\
		echo "  in the '$(srctree)' directory.";\
		/bin/false; \
	fi;
	$(Q)if [ ! -d include2 ]; then                                  \
	    mkdir -p include2;                                          \
	    ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm;     \
	fi
endif

include/config/kernel.release: include/config/auto.conf FORCE
	$(Q)rm -f $@
	$(Q)echo $(kernelrelease) > $@


include/config/auto.conf: ;

千辛万苦,最终我们终于找到了第一个target。


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值