本次再深入解析一下内核的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

在scripts/Makefile.build中
# 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 命令调用。
********************************************************************************

linux 模块Makefile 分析2相关推荐

  1. Linux内核移植之一:内核源码结构与Makefile分析

    内容来自 韦东山<嵌入式Linux应用开发完全手册> 一.内核介绍 1.版本及其特点 Linux内核的版本号可以从源代码的顶层目录下的Makefile中看到,比如下面几行它们构成了Linu ...

  2. Linux内核学习(五):linux kernel源码结构以及makefile分析

    Linux内核学习(五):linux kernel源码结构以及makefile分析 前面我们知道了linux内核镜像的生成.加载以及加载工具uboot. 这里我们来看看linux内核的源码的宏观东西, ...

  3. 在linux c 以结构体形式写文件 结构体参数如何在函数中传递,Linux安全审计机制模块实现分析(16)-核心文件之三auditsc.c文件描述及具体变量、函数定义...

    原标题:Linux安全审计机制模块实现分析(16)-核心文件之三auditsc.c文件描述及具体变量.函数定义 2.4.3文件三auditsc.c2.4.3.1 文件描述 kernel/auditsc ...

  4. linux注册函数机制,Linux可信计算机制模块详细分析之函数实现机制(1)字符设备驱动...

    原标题:Linux可信计算机制模块详细分析之函数实现机制(1)字符设备驱动 2.3 函数实现机制 2.3.1 Linux 字符设备驱动 在linux 3.5.4中,用结构体cdev描述字符设备,cde ...

  5. linux 对象管理器,Linux多安全策略和动态安全策略框架模块详细分析之函数实现机制中文件对象管理器分析(3)...

    3.决策的实施 当主体对客体进行访问时,客体管理器会收集主体和客体的SID,并根据此SID对在AVC中进行查找:如果找到,则根据相应的安全决策进行处理:反之客体管理器会将主体的SID.客体的SID以及 ...

  6. Linux保护文件实现,Linux完整性保护机制模块实现分析(1)

    原标题:Linux完整性保护机制模块实现分析(1) 2 详细分析2.1 模块功能描述 文件系统完整性模块包含四种机制:监控磁盘机制.同步机制.检查修复文件系统机制.监视文件系统机制. 1.监控磁盘机制 ...

  7. linux源码acl,Linux自主访问控制机制模块详细分析之posix_acl.c核心代码注释与acl.c文件介绍...

    原标题:Linux自主访问控制机制模块详细分析之posix_acl.c核心代码注释与acl.c文件介绍 2.4.4.6 核心代码注释 1 posix_acl_permission() int(stru ...

  8. Linux模块机制浅析

    Linux模块机制浅析   Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...

  9. 操作系统课设--NACHOS试验环境准备、安装与MAKEFILE分析

    山东大学操作系统课设lab1 实验一 NACHOS试验环境准备.安装与MAKEFILE分析(lab1) 实验环境: 分析记录: 1. 准备虚拟机下LINUX宿主操作系统环境 2. NACHOS实验代码 ...

最新文章

  1. react 打包后,项目部署完毕,刷新页面报错(404)
  2. Redis数据库的应用场景介绍
  3. 5938. 找出数组排序后的目标下标
  4. c语言 void fun(float *p1),C语言程序设计试题1
  5. wps二次开发无法创建对象wps.application的解决方案
  6. 存储总结——DASNASSAN
  7. Linux下查看和设置环境变量
  8. 加粉软件直接把你的银行卡信息给泄露了
  9. MPU6050读取实验
  10. 百度2023校招 内推码IVV4AS
  11. Java中统计耗时的方法
  12. tableau过期解决办法
  13. 【JavaSE】String类总结,StringBuilder、StringBuffer、String的区别讲解
  14. 使用react进行项目开发
  15. linux批量修改文件名多目录,Linux下批量修改文件名
  16. LangChain vs Semantic Kernel
  17. Web数据挖掘技术综述
  18. 轮式机器人算法仿真的一些杂七杂八02
  19. max9286 四合一_硅天下吉比特多媒体串行链路(GMSL)解串器MAX9286详细信息_产品参数_价格_联系方式_DAV数字音视工程网...
  20. Linux也可以这样美——Ubuntu18.04安装、配置、美化-踩坑记

热门文章

  1. SpringBoot profile及其配置文件加载顺序
  2. java例子 计算奇数 偶数的个数
  3. 人脸识别有漏洞!测试的19款国产手机全部被破解
  4. 【论文阅读】A high-performance neural prosthesis enabled by control algorithm design
  5. JAVAweb实现web网页登录
  6. 如何求方程式各未知数
  7. 行测-判断推理-图形推理-样式规律-空间重构-四面体和八面体
  8. [Android]手机通过USB绑定共享电脑网络
  9. java applet启动调试,java applet 运行环境调试记要
  10. python二次开发ug_二次开发 | 手把手教你用python进行后处理