构建顺序
代码分析
版本号等的定义,并将默认目标定义好,即_all,最后通过_all的依赖项决定到编译哪个目标。
VERSION = 5
PATCHLEVEL = 3
SUBLEVEL = 12
EXTRAVERSION =
NAME = Bobtail Squid
PHONY := _all
_all:
linux的编译可以指定输出路径的,如果自行指定输出路径,则会在对应路径再次运行make。所以会分为两步进行。同样的,即使不指定输出路径,也会进行两步。分别为make和sub-make。make是用户自行调用的,sub-make是由make调用的在输出路径下的make。
路径确定
# sub_make_done表示当前是否正在进行sub-make
# need-sub-make表示当前make是否需要进行sub-make
ifneq ($(sub_make_done),1)
# 不让make使用隐式规则,这样避免一些难以确定的问题。
MAKEFLAGS += -rR
# 字符集定义
unexport LC_ALL
LC_COLLATE=C
LC_NUMERIC=C
export LC_COLLATE LC_NUMERIC
# 避免环境变量的影响
unexport GREP_OPTIONS
# 通过一些小手段来控制输出的详细程度
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),)
quiet=silent_
endif
export quiet Q KBUILD_VERBOSE
# 指定的输出目录,通过make O=...传入
ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif
ifneq ($(KBUILD_OUTPUT),)
# 保证输出目录存在
abs_objtree := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) && pwd)
$(if $(abs_objtree),, \
$(error failed to create output directory "$(KBUILD_OUTPUT)"))
abs_objtree := $(realpath $(abs_objtree))
else
abs_objtree := $(CURDIR)
endif # ifneq ($(KBUILD_OUTPUT),)
ifeq ($(abs_objtree),$(CURDIR))
MAKEFLAGS += --no-print-directory
else
need-sub-make := 1
endif
# 通过Makefile的路径来确定源码目录,并保证目录没有":"和空格
abs_srctree := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
ifneq ($(words $(subst :, ,$(abs_srctree))), 1)
$(error source directory cannot contain spaces or colons)
endif
# 如果源码目录跟输出目录不同,则需要sub-make
ifneq ($(abs_srctree),$(abs_objtree))
MAKEFLAGS += --include-dir=$(abs_srctree)
need-sub-make := 1
endif
# make 3.x的'MAKEFLAGS += -rR'并不是立马生效 ,所以需要sub-make来屏蔽隐式规则,同时屏蔽当前makefile的隐式规则
ifneq ($(filter 3.%,$(MAKE_VERSION)),)
need-sub-make := 1
$(lastword $(MAKEFILE_LIST)): ;
endif
取消回显没有别的export abs_srctree abs_objtree
export sub_make_done := 1
ifeq ($(need-sub-make),1)
PHONY += $(MAKECMDGOALS) sub-make
$(filter-out _all sub-make $(lastword $(MAKEFILE_LIST)), $(MAKECMDGOALS)) _all: sub-make
@:
# 在输出目录下调用make
sub-make:
$(Q)$(MAKE) -C $(abs_objtree) -f $(abs_srctree)/Makefile $(MAKECMDGOALS)
endif # need-sub-make
endif # sub_make_done
正式编译
如果不需要sub-make,则当前的make调用需要进行真正的编译操作。
ifeq ($(need-sub-make),)
...
endif # need-sub-make
MAKEFLAGS += --no-print-directory
# C=1只检查需要重新编译的文件
# C=2 检查所有的文件
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
确定M的值,确定需要编译的外部模块
ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
export KBUILD_CHECKSRC KBUILD_EXTMOD
确定源码路径
ifeq ($(abs_srctree),$(abs_objtree))
# building in the source tree
srctree := .
building_out_of_srctree :=
else
ifeq ($(abs_srctree)/,$(dir $(abs_objtree)))
# building in a subdirectory of the source tree
srctree := ..
else
srctree := $(abs_srctree)
endif
building_out_of_srctree := 1
endif
ifneq ($(KBUILD_ABS_SRCTREE),)
srctree := $(abs_srctree)
endif
objtree := .
VPATH := $(srctree)
export building_out_of_srctree srctree objtree VPATH
version_h := include/generated/uapi/linux/version.h
old_version_h := include/linux/version.h
# 清理用的target
clean-targets := %clean mrproper cleandocs
# 不需要依赖.config的target
no-dot-config-targets := $(clean-targets) \
cscope gtags TAGS tags help% %docs check% coccicheck \
$(version_h) headers headers_% archheaders archscripts \
%asm-generic kernelversion %src-pkg
# 不需要同步config的target
no-sync-config-targets := $(no-dot-config-targets) install %install \
kernelrelease
config-targets := 0
mixed-targets := 0
dot-config := 1
may-sync-config := 1
# 确定是否需要依赖.config
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endif
# 确定是否需要同步config
ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
may-sync-config := 0
endif
endif
# 如果是构建外部模块,则不需要同步config
ifneq ($(KBUILD_EXTMOD),)
may-sync-config := 0
endif
# 确定是不是config 与build的混合目标
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(words $(MAKECMDGOALS)),1)
mixed-targets := 1
endif
endif
endif
# 如 "make -j clean all", "make -j mrproper defconfig all"等,清理target与非清理target也是混合目标
ifneq ($(filter $(clean-targets),$(MAKECMDGOALS)),)
ifneq