linux 模块Makefile 分析2

来源:互联网 发布:v2ex python版 编辑:程序博客网 时间:2024/05/22 03:52

本次再深入解析一下内核的Makfile

hjj@hjj-Inspiron:~/MyTest/gpio$ cat Makefile

ifneq ($(KERNELRELEASE),)
$(warning "----file was source")
obj-m := m_gpio.o
m_gpio-objs:= gpioadaptor.o gpio.o

else
    PWD=$(shell pwd)
    KVER=$(shell uname -r)
#   KDIR=/lib/modules/$(KVER)/build
    KDIR=/home/hjj/cxt/ADSP-EDU-BF533-uClinux-V2.1/uClinux源码/ADSP-EDU-BF533uC_V2.1/linux-2.6.x
    $(warning "-----KDIR=$(KDIR)")
all:
    make -C $(KDIR) M=$(PWD)
clean:
    -rm *~ *.o *.ko modules.* Module.symvers *.mod.c
endif


hjj@hjj-Inspiron:~/MyTest/gpio$ make
Makefile:11: "-----KDIR=/home/hjj/cxt/ADSP-EDU-BF533-uClinux-V2.1/uClinux\u6e90\u7801/ADSP-EDU-BF533uC_V2.1/linux-2.6.x"
make -C /home/hjj/cxt/ADSP-EDU-BF533-uClinux-V2.1/uClinux\u6e90\u7801/ADSP-EDU-BF533uC_V2.1/linux-2.6.x M=/home/hjj/MyTest/gpio
make[1]: Entering directory `/home/hjj/cxt/ADSP-EDU-BF533-uClinux-V2.1/uClinux源码/ADSP-EDU-BF533uC_V2.1/linux-2.6.x'
/home/hjj/MyTest/gpio/Makefile:2: "----file was source"
  LD      /home/hjj/MyTest/gpio/built-in.o
  CC [M]  /home/hjj/MyTest/gpio/gpioadaptor.o
  CC [M]  /home/hjj/MyTest/gpio/gpio.o
  LD [M]  /home/hjj/MyTest/gpio/m_gpio.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/hjj/MyTest/gpio/m_gpio.mod.o
  LD [M]  /home/hjj/MyTest/gpio/m_gpio.ko
make[1]: Leaving directory `/home/hjj/cxt/ADSP-EDU-BF533-uClinux-V2.1/uClinux源码/ADSP-EDU-BF533uC_V2.1/linux-2.6.x'


这里需要搞清几个问题:
1. 进入内核顶层Makefile, 具体怎样又第2次source 到了本Makefile, 即 "----file was source" 是怎样被执行的。
2. 如何知道模块名称为m_gpio.ko
3. m_gpio.mod.c 是如何生成的。

问题1: makefile 只说明了进入linux-2.6.x 目录, 显然会读那里的Makefile

********************************************************************************
顶层Makefile 流程
********************************************************************************

 -include include/config/auto.conf
 include $(srctree)/arch/$(ARCH)/Makefile


_all: modules
PHONY += $(module-dirs) modules
modules: $(module-dirs)
    @echo '  Building modules, stage 2.';
    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
    上半部和下半部的分界。

$(module-dirs): crmodverdir $(objtree)/Module.symvers
    $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)


module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
#module-dirs := _module_/home/hjj/MyTest/gpio
ifeq ("$(origin M)", "command line")
    KBUILD_EXTMOD := $(M)
endif
$(M) 命令行传来的目录, 付给了KBUILD_EXTMOD 变量

build
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
# KBUILD_SRC 为空,所以
# build := -f scripts/Makefile.build obj
展开为:
--------------------------------------------------------------------------------
    make -f scripts/Makefile.build obj=/home/hjj/MyTest/gpio
    由此将进入Makefile.build 继续执行
--------------------------------------------------------------------------------

补充完整另两个依赖。
crmodverdir:
    $(Q)mkdir -p $(MODVERDIR)
    $(Q)rm -f $(MODVERDIR)/*

PHONY += $(objtree)/Module.symvers
$(objtree)/Module.symvers:
    @test -e $(objtree)/Module.symvers || ( \
    echo; \
    echo "  WARNING: Symbol version dump $(objtree)/Module.symvers"; \
    echo "           is missing; modules will have no dependencies and modversions."; \
    echo )


********************************************************************************
Makefile.build 流程
********************************************************************************
------------------------------------------------------------------
第一个问题, 重新source 编译目录的Makefile
------------------------------------------------------------------
-include include/config/auto.conf
include scripts/Kbuild.include
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
这句重新source 了编译目录的Makefile, 下面分析变量:
src := $(obj)
其中 obj 就是命令行里的 /home/hjj/MyTest/gpio
kbuild-dir := /home/hjj/MyTest/gpio
编译目录因不包含Kbuild, 所以包含Makefile,
编译目录被第二次包含(include), 但此时已经设置了KERNELRELEASE 变量

KERNELRELEASE 在顶层Makefile 中设置
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)


------------------------------------------------------------------
2. 维护目标
------------------------------------------------------------------
其默认目标:__build

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m)) \
     $(subdir-ym) $(always)
    @:

__build: /home/hjj/MyTest/gpio/built-in.o /home/hjj/MyTest/gpio/m_gpio.o
    补充:
KBUILD_BUILTIN 由顶层Makefile 设置,总为1
builtin-target 由scripts/Makefile.build 设置
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
lib-target 不存在, extra-y 为空

KBUILD_MODULES 由顶层Makefile 设置,总为1
obj-m 由Makefile 设置,
scripts/Makefile.lib 添加前缀
obj-m        := $(addprefix $(obj)/,$(obj-m))

----------------------------------------
built-in.o 的生成
----------------------------------------

builtin-target := $(obj)/built-in.o

ifdef builtin-target
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
              $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\
              rm -f $@; $(AR) rcs $@)

$(builtin-target): $(obj-y) FORCE
    $(call if_changed,link_o_target)     // 这个函数来维护

if_changed 函数在KBuild.include 中定义
# Execute command if command has changed or prerequisite(s) are updated.
#
if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
    @set -e;                                                             \
    $(echo-cmd) $(cmd_$(1));                                             \
    echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)


# Find any prerequisites that is newer than target or that does not exist.
# PHONY targets skipped in both cases.
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
targets += $(builtin-target)
endif # builtin-target

ifneq ($(KBUILD_NOCMDDEP),1)
# Check if both arguments has same arguments. Result is empty string if equal.
# User may override this check using make KBUILD_NOCMDDEP=1
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                    $(filter-out $(cmd_$@),   $(cmd_$(1))) )
endif

总之,条件满足后,执行命令
    $(echo-cmd) $(cmd_$(1));                                             \
    echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

echo command 是一个变量, 它判断函数参数命令是否存在,为真,将显示这个参数命令
# echo command.
# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
echo-cmd = $(if $($(quiet)cmd_$(1)),\
    echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)

后面还哟一个echo 命令,用于生成dot 命令文件
# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
dot-target = $(dir $@).$(notdir $@)
make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
评论:
make-cmd 会被展开,这是肯定的,但make-cmd 展开会被执行吗? 何时被执行? 怎样被执行?


----------------------------------------
m_gpio.o 的生成
----------------------------------------

再看Makefile.build
targets += $(real-objs-y) $(real-objs-m) $(lib-y)
targets += $(extra-y) $(MAKECMDGOALS) $(always)

一定条件下添加如下target
targets += $(real-objs-y) $(real-objs-m) $(lib-y)
targets += $(lib-target)
targets += $(extra-y) $(MAKECMDGOALS) $(always)


targets := $(wildcard $(sort $(targets)))
cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
为cmd_files 赋值
在编译目录列一下ls .* -d, 吓一跳,发现每个.o 都对应一个.cmd 隐含文件, 一看就是由
这些命令生成对应.o的
那么这些cmd 内容是怎样生成,何时调用这些cmd 呢? 这也是一个难点,下次分解。

///////////////////////////////////////

    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost

Makefile 不仅可以定义变量,还可以定义函数。函数就是可以接受输入参数,完成一定功能
并可以有返回值的代码。
它的调用用call 命令调用。
********************************************************************************
0 0
原创粉丝点击