经常需要移植代码,我觉得LINUX的编译系统是一个很好的组织源代码和实施软件编译的模板,BUSYBOX就采用了这个模板。因此我将通读LINUX makefile。对其进行改造,方便以后编写代码。
每个段落都采用接口/实现来描述。
1. Makefile 的使用
1.1 MAKE执行过程显示控制
1.1.1 使用
make V=0/1/2
0: 简单显示,不显示具体命令,只显示过程
1: 详细显示,显示具体执行命令
2: 显示原因
1.1.1 实现
KBUILD_VERBOSE = $(V)
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
ifeq ($(KBUILD_VERBOSE),2)
why = 。。。
echo-why = $(call escsq, $(strip $(why)))
endif
每个命令有相应的简化显示版本,如
quiet_cmd_sysmap = SYSMAP
cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
在执行命令前使用:
echo-cmd = $(if $($(quiet)cmd_$(1)), /
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
若KBUILD_VERBOSE = 1, 所显示的为命令所对应字符串而非简化版本。
1.2 代码检查开关
1.2.1 接口
make C=1
1.2.2 实现
KBUILD_CHECKSRC = $(C)
ifneq ($(KBUILD_CHECKSRC),0)
ifeq ($(KBUILD_CHECKSRC),2)
quiet_cmd_force_checksrc = CHECK $<
cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
else
quiet_cmd_checksrc = CHECK $<
cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
endif
endif
1.3 用户提供软件模块支持
1.3.1 接口
make M=dir
1.3.2 实现
module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
PHONY += $(module-dirs) modules
$(module-dirs): crmodverdir $(objtree)/Module.symvers
$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
modules: $(module-dirs)
@echo ' Building modules, stage 2.';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
。。。。
1.4 指定存放编译结果的目录(目标目录)
1.4.1 接口
make O=dir/to/store/output/files/
1.4.2 实现
KBUILD_OUTPUT := $(O)
$(filter-out _all,$(MAKECMDGOALS)) _all:
$(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) /
KBUILD_SRC=$(CURDIR) /
KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
2. HOST工具和软件配置设置
为了对LINUX系统进行配置,系统使用KCONFIG系统,具体参见Documentation目录下kconfig-language.txt。 由于无法提供KCONFIG的执行文件,KCONFIG解释软件提供源代码。在使用KCONFIG系统前须编译出KCONFIG解释软件。
所有LINUX的配置以MACRO 存储在include/linux/autoconf.h 中,所有的文件都依赖此文件并包含此文件。如此,autoconf.h某一个改变都导致整个系统重新编译,这显然依赖的粒度太大。
LINUX采用的方法是每个文件虽然都包含autoconf.h但并不依赖它。但是make系统只能认识文件日期之间的依赖关系,这样就需要为每个MACRO创建对应的文件。这样依赖某些宏的文件可以变为依赖相应的宏对应的文件。
script/kconfig/conf 根据autoconf.h生成伪header。所有的伪header位于include/config目录下。
但是GCC -M不能生成对此伪文件的依赖。fixdep改变GCC -M的结果使得其增加对伪文件的依赖。
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
# To avoid any implicit rule to kick in, define an empty command.
scripts/basic/%: scripts_basic ;
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)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile /
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif
config %config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
注:LINUX采用以下方法包含autoconf.h
LINUXINCLUDE := -Iinclude /
$(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) /
-include include/linux/autoconf.h
注: fixdep中的相关注释
* If the user re-runs make *config, linux/autoconf.h will be
* regenerated. make notices that and will rebuild every file which
* includes autoconf.h, i.e. basically all files. This is extremely
* annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
*
* So we play the same trick that "mkdep" played before. We replace
* the dependency on linux/autoconf.h by a dependency on every config
* option which is mentioned in any of the listed prequisites.
*
* To be exact, split-include populates a tree in include/config/,
* e.g. include/config/his/driver.h, which contains the #define/#undef
* for the CONFIG_HIS_DRIVER option.
*
* So if the user changes his CONFIG_HIS_DRIVER option, only the objects
* which depend on "include/linux/config/his/driver.h" will be rebuilt,
* so most likely only his driver ;-)