3. 软件构造
3.1 软件第一级构造
init-y := init/
drivers-y := drivers/ sound/
net-y := net/
libs-y := lib/
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
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)
以下的构造在 arch/ppc/Makefile
head-y := arch/ppc/kernel/head.o
...
core-y += arch/ppc/kernel/ arch/powerpc/kernel/ /
...
_all: all
all: uImage zImage
zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm : vmlinux
uImage: vmlinux
bzImage: zImage
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
all: vmlinux
3.2 以下为若干动态生成的文件/目录:
include/linux/version.h: $(srctree)/Makefile FORCE
$(call filechk,version.h)
include/linux/utsrelease.h: include/config/kernel.release FORCE
$(call filechk,utsrelease.h)
include/linux/compile.h: FORCE
@echo ' CHK $@'
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ /
"$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(CFLAGS)"
include/asm:
@echo ' SYMLINK $@ -> include/asm-$(ARCH)'
$(Q)if [ ! -d include ]; then mkdir -p include; fi;
@ln -fsn asm-$(ARCH) $@
include/config/kernel.release: include/config/auto.conf FORCE
$(Q)rm -f $@
$(Q)echo $(kernelrelease) > $@
.version
cmd_vmlinux_version = set -e; /
if [ ! -r .version ]; then /
rm -f .version; /
echo 1 >.version; /
else /
mv .version .old_version; /
expr 0$$(cat .old_version) + 1 >.version; /
fi;
3.3 具体构造方法
3.3.1 obj-y
LINUX软件采用层次构造的方法.每个层次的软件模块文件名统一为built-in.o 。每个软件模块对应不同的目录。一个软件模块可以有本目录的.o和子目录的built-in.o所构造。
obj-y = a.o
obj-y += cpu/
编译系统做如下变换:
1. 获取子软件模块的目录和名称
子软件模块的目录
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
(subdir-ym := $(sort $(subdir-y) $(subdir-m)))
软件模块的直接构建模块列表
obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
obj-y := $(addprefix $(obj)/,$(obj-y))
子软件模块的名称
subdir-obj-y := $(foreach o,$(obj-y),$(if $(filter-out $(o),$(notdir $(o))),$(o)))
subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y))
2. 建立子软件模块的构建依赖
$(sort $(subdir-obj-y)): $(subdir-ym) ;
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
(注:本目录下的.o 和 .c文件之间的依赖由implicit rule确定)
3. 建立软件模块的构建依赖
builtin-target := $(obj)/built-in.o
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
4. 加入到编译目标
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) /
$(if $(KBUILD_MODULES),$(obj-m)) /
$(subdir-ym) $(always)
3.3.2 obj-m
obj-m不同于obj-y在于
1.同一目录中可以有多个不同的可加载软件模块
2. 一个可加载软件模块可以有多个.s/.c组成
obj-m = a.o b.o
obj-m += c/d.o
a-objs = aa.o bb.o
b-y = dd.o ee.o
LINUX编译系统做如下的变换
1.获取可加载软件模块的列表和子目录的列表
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
subdir-m += $(__subdir-m)
obj-m := $(filter-out %/, $(obj-m))
2. 获取不同类型的可加载模块列表(多.o文件构造和单.o文件构造列表)
multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
single-used-m := $(addprefix $(obj)/,$(single-used-m))
multi-used-m := $(addprefix $(obj)/,$(multi-used-m))
3. 多.o文件构造的.o列表
multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m))
4. 单.o文件的生成依赖
$(single-used-m): %.o: %.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
5. 多.o文件的生成依赖
link_multi_deps = /
$(filter $(addprefix $(obj)/, /
$($(subst $(obj)/,,$(@:.o=-objs))) /
$($(subst $(obj)/,,$(@:.o=-y)))), $^)
$(multi-used-m) : %.o: $(multi-objs-m) FORCE
$(call if_changed,link_multi-m)
@{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
6. 子目录依赖
适用于多.o文件中有源文件位于子目录中。
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
7. 加入到编译目标中
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) /
$(if $(KBUILD_MODULES),$(obj-m)) /
$(subdir-ym) $(always)
其中:
multi-objs-m 和real-objs-m
real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
用于设置针对模块编译的编译标志
$(multi-objs-m) : modname = $(modname-multi)
$(multi-objs-m:.o=.i) : modname = $(modname-multi)
$(multi-objs-m:.o=.s) : modname = $(modname-multi)
$(multi-objs-m:.o=.lst) : modname = $(modname-multi)
$(real-objs-m) : modkern_cflags := $(CFLAGS_MODULE)
$(real-objs-m:.o=.i) : modkern_cflags := $(CFLAGS_MODULE)
$(real-objs-m:.o=.s) : modkern_cflags := $(CFLAGS_MODULE)
$(real-objs-m:.o=.lst): modkern_cflags := $(CFLAGS_MODULE)
$(real-objs-m) : quiet_modtag := [M]
$(real-objs-m:.o=.i) : quiet_modtag := [M]
$(real-objs-m:.o=.s) : quiet_modtag := [M]
$(real-objs-m:.o=.lst): quiet_modtag := [M]
$(real-objs-m) : modkern_aflags := $(AFLAGS_MODULE)
$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
3.3.3 lib-y
lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
lib-target := $(obj)/lib.a
endif
$(lib-target): $(lib-y) FORCE
$(call if_changed,link_l_target)
3.3.4 Implicit Rule
%.o: %.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)