linux内核Makefile中的变量build--- 过渡篇(五)
一. kbuild系统主要涉及的几个文件
| 文件名 | 作用 |
|---|---|
| Makefile | 内核源代码顶层目录的Makefile文件 |
| scripts/Makefile.build | 通常在进行递归make时会用到的Makefile文件 |
| scripts/Makefile.host | 如果需要生成可执行文件时会用到的文件。例如:在编译内核之前需要配置内核,此时会编译生成配置程序,在这个过程中会用到这个文件 |
| scripts/Kbuild.include | 可以看作是kbuild系统的头文件。定义了一些常用的变量。其中有一个变量很重要:build。 |
| scripts/Makefile.lib | 负责归类分析obj-y、obj-m和其中的目录subdir-ym所使用的规则 |
| scripts/Makefile.modinst | 在安装模块时会用到的文件 |
| Makefile.headerinst | 内核头文件安装时使用的规则 |
| Makefile.modpost | 模块编译的第二阶段,由.o和.mod生成.ko时使用的规则 |
| Makefile.clean | 内核源码目录清理规则 |
二. 常用目标分类
| 目标 | 常用目标举例 | 作用 |
|---|---|---|
| 配置 | ||
| config | 启动Kconfig,以不同界面来配置内核。 | |
| xconfig | ||
| menuconfig | ||
| 编译 | ||
| all | 编译vmlinux内核映像和内核模块 | |
| vmlinux | 编译vmlinux内核映像 | |
| modules | 编译内核模块 | |
| 安装 | ||
| headers_install | 安装内核头文件/模块。 | |
| modules_install | ||
| 源码浏览 | ||
| tags | 生成代码浏览工具所需要的文件。 | |
| TAGS | ||
| cscope | ||
| 静态分析 | ||
| checkstack | 检查并分析内核代码。 | |
| namespacecheck | ||
| headers_check | ||
| 文档转换 | %doc | 把kernel文档转成不同格式 |
| 内核打包 | %pkg | 以不同的安装格式编译内核 |
| 构架相关(以arm为例) | ||
| zImage | 生成压缩的内核映像/td> | |
| uImage | 生成压缩的u-boot可引导的内核映像 | |
| install | 安装内核映像 |
其中的构架相关目标在顶层Makefile上并未出现,而是被包含在平台相关的Makefile(arch/$(ARCH)/Makefile)中。
三. build变量的定义
build变量定义在scripts/Kbuild.include中:
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
其中$(KBUILD_SRC)正常情况下为空,所以变量的定义可简化为:
build := -f scripts/Makefile.build obj
四. 展开(MAKE)$(build)= 后的形式
build的常用形式:
$(MAKE) $(build)=$(build-dir) [para]
其中[para] 可选。使用scripts/Kbuild.include中的$(build)变量定义,进行变量替换,上述命令被展开为:
$(MAKE) -f scripts/Makefile.build obj=$(build-dir) [para]
Make进入由参数-f指定的Make文件scripts/Makefile.build,并传入参数 obj=$(build-dir)和para。
在scripts/Makefile.build的处理过程中,$(obj)代表此次Make命令要处理(编译、链接、和生成)文件所在的目录,该目录下的Makefile文件通常情况下都会被Makefile.build所引用。引用方法如下:
# 在递归时包含子目录的Kbuild(如果存在的话)或者Makefile文件
src := $(obj)
...
# 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)
$ (obj)目录下的Makefile暂记为$(obj)/Makefile。针对Make命令,有两种情况:不指定Make目标和指定目标。
1. 不指定目标
比如:
$(MAKE) $(build)=init
由于未指定目标,这时会使用Makefile.build中的默认目标__build。然后更进一步,会使用$(obj)/Makefile(init/Makefile)中定义的变量来进行目标匹配。
__build在Makefile.build中的构建规则为:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
首先会构建该默认目标__build的依赖。Make会寻找重建这些依赖的规则。而这些规则要么在当前的Makefile文件Makefile.build中,要么在Makefile.build include的$ (obj)/Makefile中。在不指定Make目标的情况下,会使用Makefile.build中的构建规则来重建依赖。相应地,只重构那些在$(obj)/Makefile定义的依赖。其他的依赖要么不满足条件,要么找不到重构规则而被忽略。
---------------------------举例 -----------------------
例如命令 $ (MAKE) $ (build)=init:
没有指明Make目标,那么将使用Makefile.build中的默认目标__build,且会包含init目标的Makefile文件,即init/Makefile。
在__build规则中,因$ (KBUILD_BUILTIN)被主目录设置为1,且export,所以将首先重建依赖$ (builtin-target)所以将首先重建依赖$ (builtin-target)、$ (lib-target) 、$ (extra-y))、$ (subdir-ym) $ (always) (删除线的依赖一般为空,不为空的场景这里就不再讲解)。
# scripts/Makefile.build
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
该规则同样要首先重建依赖$ (obj-y)。而$ (obj-y)在init/Makefile中定义且被赋值。这时Make又会查找$ (obj-y)包含文件的构建规则。同样地,该规则要么在Makefile.build中,要么在$ (obj)/Makefile中。此处$(obj-y)为.o文件的合集(main.o version.o mounts.o initramfs.o calibrate.o),.o文件的构建规则在Makefile.build中被定义:
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
如果不懂if_changed_rule函数的使用,请移步到内核源代码单个.o文件的编译过程(六)中,里面有一小节有讲到这个函数)。
$(call if_changed,link_o_target)即调用cmd_link_o_target 生成init/built-in.o。定义如下
# scripts/Makefile.build
#
# Rule to compile a set of .o files into one .o file
#
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), $^) \
$(cmd_secanalysis),\
rm -f $@; $(AR) rcs $@)
实际执行时的打印如下:
arm-linux-ld -EL -r -o init/built-in.o init/main.o init/version.o init/mounts.o init/initramfs.o init/calibrate.o
-----------------举例结束 --------------------
一直在重复这样一个递归“规则----> 规则目标–>依赖—>重建依赖—>依赖的规则---->…”的过程,直至最后的目标文件被构建,然后逆推,由依赖层层重建其规则目标。如果构建的最终目标是主机程序。
小结:
由于没有指定Make目标,那么将使用Makefile.build的默认目标__build,建构的入口点就在此。Make在Makefile.build 和$(obj)/Makefile中寻找 __build依赖的重建规则。依次变量展开,依赖层层递归重建。
2. 指定目标
一般情况下,在(MAKE) $ (build)=build_dir [para] 中,通过参数[para] 指定Make目标时,使用的是$ (obj)/Makefile文件中构建规则。这时,在$ (obj)/Makefile文件中不仅要给一些变量赋值,且还包含本目录下目标的重建规则。
比如在顶层Makefile中,我们常见的%config目标:
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
在此指定Make目标为自动化变量$@,当我们输入类似如下的命令:
make menuconfig
那么,上述Make命令会被替换为:
make -f scripts/Makefile.build obj=scripts/kconfig menuconfig
即指定Make的目标为 menuconfig。那么在$(obj)目录(scripts/kconfig)下的Makefile中包含menuconfig模式匹配规则。其他的流程和上节的"不指定目标"处理类似。在此不再赘述。
五. scripts/Makefile.build文件总框架
#定义src变量
src:=$(obj)
#包含几个关键的文件
-include include/config/auto.conf #if xxx_CONFIG配置选项
include scripts/Kbuild.include #if_changed、echo-cmd等变量
#包含obj目录下的Kbuild或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)
#包含Makefile.lib
include scripts/Makefile.lib
#编译主机程序时,要包含Makefile.host
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host
endif
#定义builtin-target
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target:=$(obj)/built-in.o
endif
#__build构建规则
__build:$(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y))\
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target))\
$(subdir-ym)$(always)
@:
#$(obj)/built-in.o的生成规则,注意先要构建依赖$(obj-y)
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
# 普通模式匹配规则
define rule_cc_o_c
$(call echo-cmd,checksrc) $(cmd_checksrc) \
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
$(cmd_modversions) \
$(call echo-cmd,record_mcount) \
$(cmd_record_mcount) \
scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
$(dot-target).tmp; \
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd
endef
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
linux内核Makefile中的变量build--- 过渡篇(五)的更多相关文章
- linux内核Makefile整体分析
转自:http://www.cnblogs.com/amanlikethis/p/3675486.html <请阅读原文> 一.概述 1.本文的意义 众多的资料(<嵌入式Linux应 ...
- linux内核makefile概览
linux内核makefile概览 本博客参照内核官方英文文档 linux的内核makefile主要用于编译整个内核源码,按照用户的需求生成各种目标文件,对于用户来说,编译内核时非常简单的,只需要几个 ...
- 嵌入式C语言自我修养 02:Linux 内核驱动中的指定初始化
2.1 什么是指定初始化 在标准 C 中,当我们定义并初始化一个数组时,常用方法如下: ] = {,,,,,,,,}; 按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值.因为没有对 a ...
- makefile中使用变量
makefile里的变量就像一个变量,变量的作用主要如下: (1)保存文件名列表. (2)保存编译器的参数. makefile中的变量是用一个字符串在makefile中定义的,这个文本串就是变量的值. ...
- TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现
题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...
- Makefile中的变量和shell变量
我们在写makefile时 多多少少会用到shell脚本, 对于变量的在shell中的使用有一些要注意的细节.让我们从一个简单的makefile来看看. 注意makefile中一定要有一个目标,且一定 ...
- makefile中打印变量名字,方便调试
$(warning $(DVD_SERVICE)) // DVD_SerVICE是Makefile中的变量 $(warning ST40_IMPORTS is $(ST40_IMPORTS)) 变 ...
- 《Linux内核设计与实现》读书笔记——第五章
<Linux内核设计与实现>读书笔记--第五章 标签(空格分隔): 20135321余佳源 第五章 系统调用 操作系统中,内核提供了用户进程与内核进行交互的一组接口.这些接口让应用程序受限 ...
- Linux内核Makefile文件(翻译自内核手册)
--译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...
- 《Linux内核Makefile分析》之 auto.conf, auto.conf.cmd, autoconf.h【转】
转自:http://blog.sina.com.cn/s/blog_87c063060101l25y.html 转载:http://blog.csdn.net/lcw_202/article/deta ...
随机推荐
- 从源码角度深入解析Callable接口
摘要:从源码角度深入解析Callable接口,希望大家踏下心来,打开你的IDE,跟着文章看源码,相信你一定收获不小. 本文分享自华为云社区<一个Callable接口能有多少知识点?>,作者 ...
- 使用RAMMap+PoolMon分析Windows内存异常使用问题
由于技术能力有限,文章仅能进行简要分析和说明,如有不对的地方,请指正,谢谢. 1 RAMMap和PoolMon工具简介 RAMMap和PoolMon都是微软Sysinternals的工具,前者可以从使 ...
- Typora用法:
Typora用法: 一:标题 模板: #+空格+标题名+回车 一级标题 二级标题 三级标题 四级标题 五级标题 二:字体 加粗 斜体 斜体加粗 删除线(esc键下面的那个键) 上标:我是上标 下表:我 ...
- NC51101 Lost Cows
题目链接 题目 题目描述 \(N (2 \leq N \leq 8,000)\) cows have unique brands in the range 1..N. In a spectacular ...
- 优雅的操作文件:java.nio.file 库介绍
概述 在早期的 Java 版本中,文件 IO 操作功能一直相对较弱,主要存在以下问题: 缺乏对现代文件系统的支持:只提供的基础的文件操作,不支持很多现代的文件系统 API 不够直观:文件操作的 API ...
- java英文字符串首字母大写
java英文字符串首字母大写 /** * 首字母大写 * @param string * @return */ public static String toUpperCase4Index(Strin ...
- 2023-04-14:n对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手, 人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的ID, 情侣们按顺序编号,第一对
2023-04-14:n对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手, 人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的ID, 情侣们按顺序编号,第一对 ...
- vue全家桶进阶之路12:监听器 watch
在Vue2中,监听器(watch)用于监测数据的变化,并在数据变化时执行一些操作.监听器可以用来响应用户输入.观察数据变化.执行异步操作等. 监听器的使用方法如下: 在组件的watch选项中定义一个或 ...
- < Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓
欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法.无论你是编程新手,还是有一 ...
- 记一次 .NET 某汽贸店 CPU 爆高分析
一:背景 1. 讲故事 上周有位朋友在 github 上向我求助,说线程都被卡住了,让我帮忙看下,截图如下: 时隔两年 终于有人在上面提 Issue 了,看样子这块以后可以作为求助专区来使用,既然来求 ...