一. 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--- 过渡篇(五)的更多相关文章

  1. linux内核Makefile整体分析

    转自:http://www.cnblogs.com/amanlikethis/p/3675486.html <请阅读原文> 一.概述 1.本文的意义 众多的资料(<嵌入式Linux应 ...

  2. linux内核makefile概览

    linux内核makefile概览 本博客参照内核官方英文文档 linux的内核makefile主要用于编译整个内核源码,按照用户的需求生成各种目标文件,对于用户来说,编译内核时非常简单的,只需要几个 ...

  3. 嵌入式C语言自我修养 02:Linux 内核驱动中的指定初始化

    2.1 什么是指定初始化 在标准 C 中,当我们定义并初始化一个数组时,常用方法如下: ] = {,,,,,,,,}; 按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值.因为没有对 a ...

  4. makefile中使用变量

    makefile里的变量就像一个变量,变量的作用主要如下: (1)保存文件名列表. (2)保存编译器的参数. makefile中的变量是用一个字符串在makefile中定义的,这个文本串就是变量的值. ...

  5. TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现

    题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...

  6. Makefile中的变量和shell变量

    我们在写makefile时 多多少少会用到shell脚本, 对于变量的在shell中的使用有一些要注意的细节.让我们从一个简单的makefile来看看. 注意makefile中一定要有一个目标,且一定 ...

  7. makefile中打印变量名字,方便调试

    $(warning $(DVD_SERVICE)) // DVD_SerVICE是Makefile中的变量 $(warning   ST40_IMPORTS is $(ST40_IMPORTS)) 变 ...

  8. 《Linux内核设计与实现》读书笔记——第五章

    <Linux内核设计与实现>读书笔记--第五章 标签(空格分隔): 20135321余佳源 第五章 系统调用 操作系统中,内核提供了用户进程与内核进行交互的一组接口.这些接口让应用程序受限 ...

  9. Linux内核Makefile文件(翻译自内核手册)

    --译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...

  10. 《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 ...

随机推荐

  1. 【能力提升】SQL Server常见问题介绍及快速解决建议

    前言 本文旨在帮助SQL Server数据库的使用人员了解常见的问题,及快速解决这些问题.这些问题是数据库的常规管理问题,对于很多对数据库没有深入了解的朋友提供一个大概的常见问题框架. 下面一些问题是 ...

  2. cocos2d-x场景间参数传递

    1>使用全局变量     这个就不详细说明了.   2>切换时传递     2.1>在secondScene.h 中加入成员变量,如 int sceneNum;         并在 ...

  3. vs 解决方案定位当前打开的cs文件

    可以通过工具-选项-项目和解决方案-勾选[在解决方案资源管理器中跟踪活动项]

  4. MySQL-带你上官网看索引

    在我之前的一篇文章中,有引用一个讨论用Hash还是Tree的问题,DB中关于查找类数据结构,除了树,还有Hash(HashMap,HashSet). 存储数据结构之争 B+树主要是照顾磁盘IO这种特殊 ...

  5. vue上传文件(原生方法)

    前言: 组件库的文件上传不适合项目,这里我们利用input标签实现文件上传 首先input type=file  标签是这个亚子的,而且样式不能改,我们利用css的方法,将一个定位到这个下面来,然后i ...

  6. 【必知必会的MySQL知识】⑤DQL语言

    目录 一.前言 二.基础查询 2.1 语法 2.2 实践操作 三.条件查询 3.1 语法 3.2 where 语句操作符 3.3 实践操作 四.排序查询 4.1 语法格式 4.2 实践操作 五.分组查 ...

  7. jdk环境配置已经版本切换

    下载安装jdk到电脑盘,两个版本要下载到一个盘里面下安装好后右击我的电脑 找到高级系统设置,点开环境变量 新建环境变量 总计环境变量一共添加四个其中 java8和java11是是选择文件路径 JAVA ...

  8. 基于go语言的声明式流式ETL,高性能和弹性流处理器

    简要介绍Benthos,并给出若干示例,指导如何安装和运行. Benthos Benthos 是一个开源的.高性能和弹性的数据流处理器,能够以各种代理模式连接各种源和汇,可以帮助用户在不同的消息流之间 ...

  9. Selenium - 元素操作(4) - alert弹窗处理

    Selenium - 元素操作 alert弹窗 Alert弹出框由于不是html的页面元素,而是JavaScript的控件:所以不能右键检查,用传统的方法去操作. 例如这种弹窗: # 获取告警弹框的文 ...

  10. 这款全自动自适应工具你用过了吗?autofit.js请求加入你的战场!

    前段时间做了一个自适应的小工具(autofit.js) 经过一段时间的试用,同学们发现了工具存在的一些问题,我自己也发现了一些,这篇文章是针对这些问题撰写的. autofit.js autofit.j ...