1. 程式人生 > >linux kernel 4.18.16 Makefile註釋

linux kernel 4.18.16 Makefile註釋

前言:

本人的作業系統作業,要求註釋最新版本的GNU Linux kernel 的Makefile檔案,我還沒用過Linux,一開啟這個Makefile真的是下了一跳……好多東西要註釋啊,忙活了一個下午,成果就寫個部落格吧。

參考:

Makefile:

# SPDX-License-Identifier: GPL-2.0
# SPDX-許可證-識別符:GPL-2.0
# 版本 = 4
# 修補版本號 = 18
# 次級版本號 = 15
# 附加資訊,一般預設為空,可以自行設定
# 此版本的名字
VERSION = 4
PATCHLEVEL = 18
SUBLEVEL = 15
EXTRAVERSION
= NAME = Merciless Moray # *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. # That's our default target when none is given on the command line
PHONY := _all _all: # o Do not use make's built-in rules and variable # (this increases performance and avoids hard-to-debug behaviour); # o Look for make include files relative to root of kernel src # o 禁止使用內建的規則和變數 # (這提高了效能並避免了難以除錯的行為); # o 查詢與核心src有關的生成包含檔案 MAKEFLAGS += -rR --include-dir=$(
CURDIR) # 非傳遞環境變數,不會傳遞到下一級Makefile # Avoid funny character set dependencies unexport LC_ALL LC_COLLATE=C LC_NUMERIC=C export LC_COLLATE LC_NUMERIC # 傳遞環境變數,環境變數會傳遞到下一級Makefile # Avoid interference with shell env settings unexport GREP_OPTIONS # 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.a 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. # 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)/[email protected] //這個是簡化版的輸出 # cmd_cc_o_c = $(CC) $(c_flags) -c -o [email protected] $< //這個是原版的輸出 # # If $(quiet) is empty, the whole command will be printed. //表示如果為空則完全回顯 # If it is set to "quiet_", only the short version will be printed. //$(quiet)=quiet_表示只有版本顯示 # If it is set to "silent_", nothing will be printed at all, since //表示完全不回顯 # the variable $(silent_cmd_cc_o_c) doesn't exist. # # 下面是$(Q)用作字首,如果$(Q)[email protected]表示不回顯,為空表示回顯 # A simple variant is to prefix commands with $(Q) - that's useful # for commands that shall be hidden in non-verbose mode. # # $(Q)ln [email protected] :< # # If KBUILD_VERBOSE equals 0 then the above command will be hidden. # If KBUILD_VERBOSE equals 1 then the above command is displayed. # # 如果$(quiet)為空,則輸出原版編譯命令 # 如果$(quiet)為quiet_,則輸出簡化版本的 # 如果$(quiet)為silent_,則任何都不輸出,因為slient_cmd_cc_o_cc根本不存在 # 不過有個全域性的控制,如果KBUILD_VERBOSE為0,則輸出簡化版本,如果為1,則輸出簡化版本 # # To put more focus on warnings, be less verbose as default # Use 'make V=1' to see the full commands # 設定列印訊息級別,通過呼叫 make 時新增的引數 V 來修改 ifeq ("$(origin V)", "command line") KBUILD_VERBOSE = $(V) endif # 預設的KBUILD_VERBOSE的值被設定為0,也就意味著在編譯過程中,只輸出 # 預設我們是不回顯的,回顯即在命令執行前顯示要執行的命令 ifndef KBUILD_VERBOSE KBUILD_VERBOSE = 0 endif ifeq ($(KBUILD_VERBOSE),1) #這裡就是定義是否要回顯 quiet = Q = #不以@開頭表示回顯 else quiet=quiet_ Q = @ #這裡以@開頭表示不回顯 endif # If the user is running make -s (silent mode), suppress echoing of # commands ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),) # 如果MAKEFLAGS中帶了-s表示完全不要回顯 quiet=silent_ tools_silent=s endif # 輸出quiet給子make export quiet Q KBUILD_VERBOSE # 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過程中的輸出檔案目的地址,有兩種方式: # 第一種是在 make 引數中設定(make -O dir") # 第二種方式是設定環境變數(export KBUILD_OUTPU=dir) # KBUILD_SRC is not intended to be used by the regular user (for now), # it is set on invocation of make with KBUILD_OUTPUT or O= specified. ifeq ($(KBUILD_SRC),) # 如果KBUILD_SRC值為空,就執行下面的操作 # 上面說的這個功能當前對一般使用者沒有用 # OK, Make called in directory where kernel src resides # Do we want to locate output files in a separate directory? # 如果命令列中定義了O變數來修改輸出目錄,就用使用者定義的這個目錄 ifeq ("$(origin O)", "command line") KBUILD_OUTPUT := $(O) # 用於指定我們的輸出檔案的輸出目錄 endif # Cancel implicit rules on top Makefile # 取消隱式推導規則 $(CURDIR)/Makefile Makefile: ; # CURDIR值為當前的核心原始碼目錄current.dir # 上面操作是檢視當前目錄的Makefile是否為最新 ifneq ($(words $(subst :, ,$(CURDIR))), 1) $(error main directory cannot contain spaces nor colons) endif # 如果輸出目錄值不為空,正常情況下進入 ifneq ($(KBUILD_OUTPUT),) # check that the output directory actually exists # 上面說在輸出目錄中執行第二個make命令,傳入相關變數,並且檢查輸出目錄是否存在 saved-output := $(KBUILD_OUTPUT) KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \ && pwd) $(if $(KBUILD_OUTPUT),, \ $(error failed to create output directory "$(saved-output)")) # MAKECMDGOALS 是make的一個環境變數,儲存所有目標列表 # 下面這個命令將所有指明的目標列表和sub-make加入到PHONY中 PHONY += $(MAKECMDGOALS) sub-make # 下面這個命令很是不明白,大概是用來過濾,太複雜了 # 簡單分析下,過濾掉MAKECMDGOALS中的_all sub-make和$(CURDIR)/Makefile,並將它們都賦值為sub-make $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make @: # Invoke a second make in the output directory, passing relevant variables # 這個就是sub-make的值,大致就是將頂層Makefile定義的規則傳給下層資料夾中的Makefile中 sub-make: $(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \ -f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS)) # Leave processing to above invocation of make # 表示執行完了子makefile,返回頂層make skip-makefile := 1 endif # ifneq ($(KBUILD_OUTPUT),) #結束ifneq endif # ifeq ($(KBUILD_SRC),) #結束ifeq # We process the rest of the Makefile if this is the final invocation of make # 表示如果skip-makefile為空,這按照分類執行,也就是不是整體進行make ifeq ($(skip-makefile),) # Do not print "Entering directory ...", # but we want to display it when entering to the output directory # so that IDEs/editors are able to understand relative filenames. MAKEFLAGS += --no-print-directory # Call a source code checker (by default, "sparse") as part of the # C compilation. //呼叫一個靜態分析工具作為c編譯器的部分 # # 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/dev-tools/sparse.rst" for more details, # including where to get the "sparse" utility. # 設定語法檢查級別,預設級別為0 ifeq ("$(origin C)", "command line") KBUILD_CHECKSRC = $(C) endif ifndef KBUILD_CHECKSRC KBUILD_CHECKSRC = 0 endif # 用M來指定外部模組的目錄 # 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 # 下面是為了支援舊語法格式的Makefile的設定 ifdef SUBDIRS KBUILD_EXTMOD ?= $(SUBDIRS) endif ifeq ("$(origin M)", "command line") KBUILD_EXTMOD := $(M) endif ifeq ($(KBUILD_SRC),) # building in the source tree srctree := . else ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR))) # building in a subdirectory of the source tree srctree := .. else srctree := $(KBUILD_SRC) endif endif export KBUILD_CHECKSRC KBUILD_EXTMOD KBUILD_SRC objtree := . src := $(srctree) # 將src設定為原始碼根目錄 obj := $(objtree) #將obj設定位當前目錄 VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) # 這裡是說當前目錄找不到原始檔時的搜尋目錄 export srctree objtree VPATH # export用於要將指定變數輸出給子make # To make sure we do not include .config for any of the *config targets # catch them early, and hand them over to scripts/kconfig/Makefile # It is allowed to specify more targets when calling make, including # mixing *config targets and build targets. # For example 'make oldconfig all'. # Detect when mixed targets is specified, and make a second invocation # of make so .config is not included in this case either (for *config). # 下面這裡是保證呼叫make的時候輸入了*config目標,這是就不能包含.config檔案 version_h := include/generated/uapi/linux/version.h old_version_h := include/linux/version.h clean-targets := %clean mrproper cleandocs no-dot-config-targets := $(clean-targets) \ cscope gtags TAGS tags help% %docs check% coccicheck \ $(version_h) headers_% archheaders archscripts \ kernelversion %src-pkg no-sync-config-targets := $(no-dot-config-targets) install %install config-targets := 0 mixed-targets := 0 dot-config := 1 may-sync-config := 1 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) dot-config := 0 endif endif ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),) ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) may-sync-config := 0 endif endif ifneq ($(KBUILD_EXTMOD),) may-sync-config := 0 endif ifeq ($(KBUILD_EXTMOD),) ifneq ($(filter config %config,$(MAKECMDGOALS)),) config-targets := 1 ifneq ($(words $(MAKECMDGOALS)),1) mixed-targets := 1 endif endif endif # For "make -j clean all", "make -j mrproper defconfig all", etc. ifneq ($(filter $(clean-targets),$(MAKECMDGOALS)),) ifneq ($(filter-out $(clean-targets),$(MAKECMDGOALS)),) mixed-targets := 1 endif endif # install and modules_install need also be processed one by one ifneq ($(filter install,$(MAKECMDGOALS)),) ifneq ($(filter modules_install,$(MAKECMDGOALS)),) mixed-targets := 1 endif endif ifeq ($(mixed-targets),1) # =========================================================================== # We're called with mixed targets (*config and build targets). # Handle them one by one. PHONY += $(MAKECMDGOALS) __build_one_by_one $(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one @: __build_one_by_one: $(Q)set -e; \ for i in $(MAKECMDGOALS); do \ $(MAKE) -f $(srctree)/Makefile $$i; \ done else # We need some generic definitions (do not try to remake the file). # 這裡是定義了一些通用的srctree變數定義,這裡執行remake操作 scripts/Kbuild.include: ; # 這裡的檔案包含了大量通用的函式和變數,已經為這個檔案建立了筆記,抽個時間進行分析, # 還是先對那個進行分析吧,因為下面會用到它定義的很多變數 include scripts/Kbuild.include # Read KERNELRELEASE from include/config/kernel.release (if it exists) KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) # 設定版本號 KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION) export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION include scripts/subarch.include # 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. # 當執行交叉編譯的時候,要將ARCH的值設定為目標的架構,支援的交媾可以在arch目錄下看到 # ARCH可以在執行make命令時設定,如make ARCH=arm # 預設的ARCH是和Host相同 # 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 # 下面是處理交叉編譯這塊的,交叉編譯需要知道Host的架構和Target的架構吧 # CROSS_COMPILE是編譯時所有命令的字首,可以在執行make的時候指定如make CROSS_COMPILE=ia64-linux- # CROSS_COMPILE也可以通過環境變數來設定 # 預設情況下是不需要CROSS_COMPILE來執行的,也就是不交叉編譯 ARCH ?= $(SUBARCH) # 預設Host的架構與Target架構相同 # Architecture as present in compile.h UTS_MACHINE := $(ARCH) SRCARCH := $(ARCH) # 下面是對x86結構的特殊照顧,不明白原因 # Additional ARCH settings for x86 ifeq ($(ARCH),i386) SRCARCH := x86 endif ifeq ($(ARCH),x86_64) SRCARCH := x86 endif # Additional ARCH settings for sparc ifeq ($(ARCH),sparc32) SRCARCH := sparc endif ifeq ($(ARCH),sparc64) SRCARCH := sparc endif # Additional ARCH settings for sh ifeq ($(ARCH),sh64) SRCARCH := sh endif # 聲稱的配置檔名 KCONFIG_CONFIG ?= .config export KCONFIG_CONFIG # 設定kbuild使用的Shell # 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) HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS 2>/dev/null) HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS 2>/dev/null) HOST_LFS_LIBS := $(shell getconf LFS_LIBS 2>/dev/null) # 設定編譯器,和全域性編譯FLAGS HOSTCC = gcc HOSTCXX = g++ HOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \ -fomit-frame-pointer -std=gnu89 $(HOST_LFS_CFLAGS) HOSTCXXFLAGS := -O2 $(HOST_LFS_CFLAGS) HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) HOST_LOADLIBES := $(HOST_LFS_LIBS) # Make variables (CC, etc...) # 定義一系列Make變數,大部分都是編譯階段使用的一些工具,如as,cc,ar,nm,objcopy等 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 LEX = flex YACC = bison AWK = awk GENKSYMS = scripts/genksyms/genksyms INSTALLKERNEL := installkernel DEPMOD = /sbin/depmod PERL = perl PYTHON = python PYTHON2 = python2 PYTHON3 = python3 CHECK = sparse # 預設的字串檢查 CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) NOSTDINC_FLAGS = CFLAGS_MODULE = AFLAGS_MODULE = LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = LDFLAGS_vmlinux = # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ -I$(srctree)/arch/$(SRCARCH)/include/uapi \ -I$(objtree)/arch/$(SRCARCH)/include/generated/uapi \ -I$(srctree)/include/uapi \ -I$(objtree)/include/generated/uapi \ -include $(srctree)/include/linux/kconfig.h # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option LINUXINCLUDE := \ -I$(srctree