MAKEFLAGS += -rR --include-dir=$(CURDIR)
MAKEFLAGS和CURDIR为makefile中的默认变量
使用make -.p可以查看makefile预先定义过的东西
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
这段代码实现了在make的时候使用参数V=1或者V=0实现长短命令log输出切换
原理是通过命令行传进来的V参数构造KBUILD_VERBOSE quiet Q三个变量
在写命令的时候加上$(Q)或者$(quiet)前缀,使得命令文本变成短命令打印的版本
V=0:$(Q)make------->@make @(quiet)sym------->quiet_sym
V=1:$(Q)make------->make @(quiet)sym------->sym
uboot编译时可加上-s变成静默编译,原理是凑出silent_前缀
export quiet Q KBUILD_VERBOSE
之后通过export把这三个变量传给下层makefile
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
objtree := .
src := $(srctree)
obj := $(objtree)
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH
生成源代码路径,和生成文件路径以及VPATH
HOSTARCH := $(shell uname -m | \
sed -e s/i.86/x86/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ \
-e s/sa110/arm/ \
-e s/ppc64/powerpc/ \
-e s/ppc/powerpc/ \
-e s/macppc/powerpc/\
-e s/sh.*/sh/)
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
export HOSTARCH HOSTOS
这里是检测host主机,也就是编译用主机的系统和架构
KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG
将.config文件名作为变量KCONFIG_CONFIG导入,这个是正式编译前进行编译配置自动生成的,为关键文件之一
HOSTCC = cc
HOSTCXX = c++
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2
HOSTCC = $(call os_x_before, 10, 5, "cc", "gcc")
HOSTCFLAGS += $(call os_x_before, 10, 4, "-traditional-cpp")
HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress")
生成host的gcc命令
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
LDR = $(CROSS_COMPILE)ldr
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
生成交叉编译的gcc命令
export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
将生成的命令变量export到下层makefile,同时export的还有目标平台的ARCH、CPU、BOARD等信息(第一行),这些信息在1.7小节介绍的代码中生成
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
@# If the following part fails, include/config/auto.conf should be
@# deleted so "make silentoldconfig" will be re-run on the next build.
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
{ rm -f include/config/auto.conf; false; }
@# include/config.h has been updated after "make silentoldconfig".
@# We need to touch include/config/auto.conf so it gets newer
@# than include/config.h.
@# Otherwise, 'make silentoldconfig' would be invoked twice.
$(Q)touch include/config/auto.conf
第5行将script/Makefile.autoconf使用-f作为makefile,这个文件中导入了config.mk
ifneq ($(wildcard $(KCONFIG_CONFIG)),)
ifneq ($(wildcard include/config/auto.conf),)
autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \
include/config/auto.conf)
ifeq ($(autoconf_is_old),)
include config.mk
include arch/$(ARCH)/Makefile
endif
endif
endif
1.6小节中,目标平台的ARCH、CPU、BOARD等信息会在config.mk文件中生成,以上代码导入了config.mk文件
以下为config.mk中生成这几个变量的代码
ARCH := $(CONFIG_SYS_ARCH:"%"=%)
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_TEGRA
CPU := arm720t
endif
endif
BOARD := $(CONFIG_SYS_BOARD:"%"=%)
ifneq ($(CONFIG_SYS_VENDOR),)
VENDOR := $(CONFIG_SYS_VENDOR:"%"=%)
endif
ifneq ($(CONFIG_SYS_SOC),)
SOC := $(CONFIG_SYS_SOC:"%"=%)
endif
config.mk中使用的变量由.config文件生成
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="mx6"
CONFIG_SYS_VENDOR="freescale"
CONFIG_SYS_BOARD="mx6ull_alientek_emmc"
CONFIG_SYS_CONFIG_NAME="mx6ull_alientek_emmc"
make xxx_defconfig命令时生成.config,主要执行了如下规则
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
其中依赖以下三条规则
PHONY += FORCE
FORCE:
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
PHONY += outputmakefile
# outputmakefile generates a Makefile in the output directory, if using a
# separate output directory. This allows convenient use of make in the
# output directory.
outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)ln -fsn $(srctree) source
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif
第一规则(FORCE)和第三规则(outputmakefile)实际执行了空命令,对结果没有影响,因此主要生成了第二个规则(scripts_basic)对应的文件
$(build)变量定义在script/Kbuild.include文件中
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
该文件在顶层makefile中已经被导入
# We need some generic definitions (do not try to remake the file).
scripts/Kbuild.include: ;
include scripts/Kbuild.include
因此
在规则scripts_basic中,最终执行的命令如下
make -f ./scripts/Makefile.build obj=scripts/basic
在规则%config中,最终执行的命令如下
make -f ./scripts/Makefile.build obj=scripts/kconfig %_defconfig
可见执行的都是./scripts/Makefile.build这个文件,同时传入了不同的obj作为参赛
./scripts/Makefile.build文件中,一开始的代码如下
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
以上代码用于去掉obj中的tpl和spl前缀
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
对于第2.1节中的两个make过程,kbuid-file分别为scripts/basic/Makefile和scripts/kconfig/Makefile
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
scripts/basic/Makefile
hostprogs-y := fixdep
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
scripts/kconfig/Makefile
%_defconfig: $(obj)/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
# Added for U-Boot (backward compatibility)
%_config: %_defconfig
@: