/*-------------------------------------------------------------------------------*/
VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 20 EXTRAVERSION = .7 NAME = Homicidal Dwarf Hamster
# 以上表明了内核版本。组合起来就是:2.6.20.7 ,yeah,这就是我分析的内核版本
# 注意写makefile时不要使用makefile的内建的规则和变量
#要想不打印"Entering directory ..."字样,请使用no-print-directory选项 MAKEFLAGS += -rR --no-print-directory
# 因为需要递归执行build, 所以必须注意要保证按照正确顺序执行make.
# 使用 'make V=1' 可以看到完整命令
ifdef V ifeq ("$(origin V)", "command line") KBUILD_VERBOSE = $(V) endif endif ifndef KBUILD_VERBOSE KBUILD_VERBOSE = 0 endif
# 使用 'make C=1' 仅检查需要重新使用c编译器编译的文件 # 使用 'make C=2' 检查所有c编译器编译的文件
ifdef C ifeq ("$(origin C)", "command line") KBUILD_CHECKSRC = $(C) endif endif ifndef KBUILD_CHECKSRC KBUILD_CHECKSRC = 0 endif
# 使用 make M=dir 表明需要编译的模块目录 # 旧的语法make ... SUBDIRS=$PWD 依然支持 # 这里通过环境变量 KBUILD_EXTMOD来表示 ifdef SUBDIRS KBUILD_EXTMOD ?= $(SUBDIRS) endif ifdef M ifeq ("$(origin M)", "command line") KBUILD_EXTMOD := $(M) endif endif
# 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 会再obj目录的make调用 # KBUILD_SRC 到目前还不是为了给一般用户使用的 ifeq ($(KBUILD_SRC),)
ifdef O ifeq ("$(origin O)", "command line") KBUILD_OUTPUT := $(O) endif endif
# 缺剩目标 PHONY := _all _all:
ifneq ($(KBUILD_OUTPUT),) # 调用输出目录的第二个make, 传递相关变量检查输出目录确实存在
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)
$(filter-out _all,$(MAKECMDGOALS)) _all: $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \ KBUILD_SRC=$(CURDIR) \ KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
# Leave processing to above invocation of make skip-makefile := 1 endif # ifneq ($(KBUILD_OUTPUT),) endif # ifeq ($(KBUILD_SRC),)
ifeq ($(skip-makefile),)
PHONY += all ifeq ($(KBUILD_EXTMOD),) _all: all else _all: modules endif
srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR)) TOPDIR := $(srctree) # FIXME - TOPDIR is obsolete, use srctree/objtree objtree := $(CURDIR) src := $(srctree) obj := $(objtree)
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH TOPDIR
# SUBARCH 告诉 usermode build 当前的机器是什么体系. 它是第一个设置的,并且如果 # 是usermode build ,命令行中的 "ARCH=um" 优先下面的 ARCH 设置. 如果是 native build , # 设置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/ )
# 交叉编译和选择不同的gcc/bin-utils # --------------------------------------------------------------------------- # # 当交叉编译其他体系的内核时,ARCH 应该设置为目标体系. # ARCH 可以再make执行间设置: # make ARCH=ia64 # 另外一种方法是设置 ARCH 环境变量. # 默认 ARCH 是当前执行的宿主机.
# CROSS_COMPILE 作为编译时所有执行需要使用的前缀 # 只有gcc 和 相关的 bin-utils 使用 $(CROSS_COMPILE)设置的前缀. # CROSS_COMPILE 可以再命令行设置: # make CROSS_COMPILE=ia64-linux- # 另外 CROSS_COMPILE 也可以再环境变量中设置. # CROSS_COMPILE 的默认值是空的 # Note: 一些体系的 CROSS_COMPILE 是再其 arch/*/Makefile中设置的
ARCH ?= $(SUBARCH) CROSS_COMPILE ?=
# Architecture as present in compile.h UTS_MACHINE := $(ARCH)
KCONFIG_CONFIG ?= .config
# SHELL used by kbuild CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi)
HOSTCC = gcc HOSTCXX = g++ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2
# Decide whether to build built-in, modular, or both. # Normally, just do built-in.
KBUILD_MODULES := KBUILD_BUILTIN := 1
# 如果仅编译模块 "make modules", 就不会编译内建的 objects. # 当使用modversions编译 modules 时 , 就需要考虑build-in objects, # 目的是再记录前确认 checksums 已经更新.
ifeq ($(MAKECMDGOALS),modules) KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) endif
# If we have "make modules", compile modules # in addition to whatever we do anyway. # Just "make" or "make all" shall build modules as well
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 # --------------------------------------------------------------------------- # # 一般,make再执行命令前会打印整个命令信息. 现在通过$($(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)放到命令前面,以便再 non-verbose 模式下可以隐藏命令: # # $(Q)ln $@ :< # # 如果 KBUILD_VERBOSE 等于 0 ,那么上面的命令将隐藏. # 如果 KBUILD_VERBOSE 等于 1 ,那么上面的命令将显示.
ifeq ($(KBUILD_VERBOSE),1) quiet = Q = else quiet=quiet_ Q = @ endif
# 如果make -s (silent mode), 不会显示命令
ifneq ($(findstring s,$(MAKEFLAGS)),) quiet=silent_ endif
export quiet Q KBUILD_VERBOSE
# Look for make include files relative to root of kernel src MAKEFLAGS += --include-dir=$(srctree)
# We need some generic definitions. include $(srctree)/scripts/Kbuild.include
# Make variables (CC, etc...)
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 DEPMOD = /sbin/depmod KALLSYMS = scripts/kallsyms PERL = perl CHECK = sparse
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) MODFLAGS = -DMODULE CFLAGS_MODULE = $(MODFLAGS) AFLAGS_MODULE = $(MODFLAGS) LDFLAGS_MODULE = -r CFLAGS_KERNEL = AFLAGS_KERNEL =
# Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option LINUXINCLUDE := -Iinclude \ $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \ -include include/linux/autoconf.h
CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__
# Read KERNELRELEASE from include/config/kernel.release (if it exists) KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION export ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
# When compiling out-of-tree modules, put MODVERDIR in the module # tree rather than in the kernel tree. The kernel tree might # even be read-only. export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
# Files to ignore in find ... statements
RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git
# =========================================================================== # 下面是设置config和build 内核时共同使用的规则
# scripts里面是最基本的帮助builds,在scripts/basic目录下的makefile是所有build时都会用到的工具:fixdep/ PHONY += scripts_basic scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic
# 把对scripts/basic/makefile转化到scripts_basic处理 scripts/basic/%: scripts_basic ;
#这里先说说script目录里面的makefile文件作用 #makefile:配置目标,包括编译岛内核和模块方式的target #makefile_clean:当然是删除了 #kbuild_include:一般的配置选项,会在makefile_build中调用 #makefile_build:build配置 #makefile_lib:module,vmlinux的配置 #makefile_host:配置binary #makefile_modinst:安装module #makefile_modpost:
PHONY += outputmakefile # outputmakefile规则目的是在输出目录产生一个makefile文件。这会为make提供方便。这里是调用scripts/mkmakefile创建makfile文件 outputmakefile: ifneq ($(KBUILD_SRC),) $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) endif
# 设置是.config,还是module,还是build命令
no-dot-config-targets := clean mrproper distclean \ cscope TAGS tags help %docs check% \ include/linux/version.h headers_% \ kernelrelease kernelversion
config-targets := 0 mixed-targets := 0 dot-config := 1
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) dot-config := 0 endif endif
ifeq ($(KBUILD_EXTMOD),) ifneq ($(filter config %config,$(MAKECMDGOALS)),) config-targets := 1 ifneq ($(filter-out config %config,$(MAKECMDGOALS)),) mixed-targets := 1 endif endif endif
ifeq ($(mixed-targets),1) # =========================================================================== # We're called with mixed targets (*config and build targets). # Handle them one by one.
%:: FORCE $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
else ifeq ($(config-targets),1) # =========================================================================== #仅配置linux
# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed. # KBUILD_DEFCONFIG may point out an alternative default configuration # used for 'make defconfig' include $(srctree)/arch/$(ARCH)/Makefile export KBUILD_DEFCONFIG
config %config: scripts_basic outputmakefile FORCE $(Q)mkdir -p include/linux include/config $(Q)$(MAKE) $(build)=scripts/kconfig $@
else # =========================================================================== # 仅编译内核
ifeq ($(KBUILD_EXTMOD),) # Additional helpers built in scripts/ # Carefully list dependencies so we do not try to build scripts twice # in parallel PHONY += scripts scripts: scripts_basic include/config/auto.conf $(Q)$(MAKE) $(build)=$(@)
#下面就不用说了吧 # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ drivers-y := drivers/ sound/ net-y := net/ libs-y := lib/ core-y := usr/ endif # KBUILD_EXTMOD
ifeq ($(dot-config),1) # Read in config -include include/config/auto.conf
ifeq ($(KBUILD_EXTMOD),) # Read in dependencies to all Kconfig* files, make sure to run # oldconfig if changes are detected. -include include/config/auto.conf.cmd
# To avoid any implicit rule to kick in, define an empty command $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# If .config is newer than include/config/auto.conf, someone tinkered # with it and forgot to run make oldconfig. # if auto.conf.cmd is missing then we are probably in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig else # external modules needs include/linux/autoconf.h and include/config/auto.conf # but do not care if they are up-to-date. Use auto.conf to trigger the test PHONY += include/config/auto.conf
include/config/auto.conf: $(Q)test -e include/linux/autoconf.h -a -e $@ || ( \ echo; \ echo " ERROR: Kernel configuration is invalid."; \ echo " include/linux/autoconf.h or $@ are missing."; \ echo " Run 'make oldconfig && make prepare' on kernel src to fix it."; \ echo; \ /bin/false)
endif # KBUILD_EXTMOD
else # Dummy target needed, because used as prerequisite include/config/auto.conf: ; endif # $(dot-config)
# =========================================================================== # 仅编译内核
ifeq ($(KBUILD_EXTMOD),) # Additional helpers built in scripts/ # Carefully list dependencies so we do not try to build scripts twice # in parallel PHONY += scripts scripts: scripts_basic include/config/auto.conf $(Q)$(MAKE) $(build)=$(@)
#下面就不用说了吧 # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ drivers-y := drivers/ sound/ net-y := net/ libs-y := lib/ core-y := usr/ endif # KBUILD_EXTMOD
.....
all: vmlinux
#配置gcc选项 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE CFLAGS += -Os else CFLAGS += -O2 endif ....
# 缺剩的编译的内核镜像 export KBUILD_IMAGE ?= vmlinux
# # vmlinux与map安装路径,默认时boot目录 export INSTALL_PATH ?= /boot
# #module安装目录 #
MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) export MODLIB
# # 如果定义了INSTALL_MOD_STRIP,在安装module后会strip这些安装的modules
ifdef INSTALL_MOD_STRIP ifeq ($(INSTALL_MOD_STRIP),1) mod_strip_cmd = $(STRIP) --strip-debug else mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP) endif # INSTALL_MOD_STRIP=1 else mod_strip_cmd = true endif # INSTALL_MOD_STRIP export mod_strip_cmd
#如果不是安装module ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
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-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \ $(init-n) $(init-) \ $(core-n) $(core-) $(drivers-n) $(drivers-) \ $(net-n) $(net-) $(libs-n) $(libs-))))
init-y := $(patsubst %/, %/built-in.o, $(init-y)) core-y := $(patsubst %/, %/built-in.o, $(core-y)) drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) net-y := $(patsubst %/, %/built-in.o, $(net-y)) libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) libs-y := $(libs-y1) $(libs-y2)
# Build vmlinux ...
#配置syms ...
#以下是内核link时的配置 .... | | |