热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

linux内核企鹅,Linux内核Makefile体系简单分析

众所周知,Linux内核是使用make命令来配置并编译的,那必然少不了Makefile。在内核目录树中我们可以看到内核编译系统的顶层Makefile文件

众所周知,Linux内核是使用make命令来配置并编译的,那必然少不了Makefile。在内核目录树中我们可以看到内核编译系统的顶层Makefile文件。但是如此复杂、庞大的内核源码绝不可能使用一个或几个Makefile文件来完成配置编译,而是需要一套同样复杂、庞大,且为Linux内核定制的Makefile系统。她可以说是内核的一个子系统,是内核中比较特殊的一部分,几乎都是应用层的程序和脚本,但又和生成的内核二进制文件息息相关。编译不仅涉及本地编译,还涉及各个平台之间的交叉编译以及二进制文件格式处理等等。她是对Makefile在功能上的扩充,使其在配置编译Linux内核的时候更加灵活、高效和简洁。

尽管她是一个复杂的系统,但对绝大部分内核开发者来说只需要知道如何使用,而无需了解其中的细节。她对绝大部分内核开发者基本上是透明的,隐藏了大部分实现细节,有效地降低了开发者的负担,能使其能专注于内核开发,而不至于花费时间和精力在编译过程上。

以下我们就来简要的了解一下内核Makefile体系。

一、内核Makefile体系概述

其实内核Makefile体系的包含了Kconfig和Kbuild两个系统。她曾经的维护人是Sam

Ravnborg <>&#xff0c;现在的暂时没有查到。参考资料&#xff1a;

Kconfig对应的是内核配置阶段&#xff0c;如你使用命令&#xff1a;make menuconfig&#xff0c;就是在使用Kconfig系统。Kconfig由以下三部分组成&#xff1a;

scripts/kconfig/*

Kconfig文件解析程序

kconfig

各个内核源代码目录中的kconfig文件

arch/$(ARCH)/configs/*_defconfig

各个平台的缺省配置文件

当Kconfig系统生成.config后&#xff0c;Kbuild会依据.config编译指定的目标。后面我会简单地对make %config的流程进行情景分析&#xff0c;这里不必赘述。

Kbuild是内核Makefile体系重点&#xff0c;对应内核编译阶段&#xff0c;由5个部分组成&#xff1a;

顶层Makefile

根据不同的平台&#xff0c;对各类target分类并调用相应的规则Makefile生成目标

.config

内核配置文件

arch/$(ARCH)/Makefile

具体平台相关的Makefile

scripts/Makefile.*

通用规则文件&#xff0c;面向所有的Kbuild Makefiles&#xff0c;所起的作用可以从后缀名中得知。

各子目录下的Makefile文件

由其上层目录的Makefile调用&#xff0c;执行其上层传递下来的命令

而其中scripts目录下的编译规则文件和其目录下的C程序在整个编译过程起着重要的作用。列举如下&#xff1a;

文件名

作用

Kbuild.include

共用的定义文件&#xff0c;被许多独立的Makefile.*规则文件和顶层Makefile包含

Makefile.build

提供编译built-in.o, lib.a等的规则

Makefile.lib

负责归类分析obj-y、obj-m和其中的目录subdir-ym所使用的规则

Makefile.host

本机编译工具(hostprog-y)的编译规则

Makefile.clean

内核源码目录清理规则

Makefile.headerinst

内核头文件安装时使用的规则

Makefile.modinst

内核模块安装规则

Makefile.modpost

模块编译的第二阶段,由.o和.mod生成.ko时使用的规则

顶层Makefile主要是负责完成vmlinux(内核文件)与*.ko(内核模块文件)的编译。顶层Makefile读取.config文件&#xff0c;并根据.config文件确定访问哪些子目录&#xff0c;并通过递归向下访问子目录的形式完成。顶层Makefile同时根据.config文件原封不动的包含一个具体架构的Makefile&#xff0c;其名字类似于arch/$(ARCH)/Makefile。该架构Makefile向顶层Makefile提供其架构的特别信息。

每一个子目录都有一个Makefile文件&#xff0c;用来执行从其上层目录传递下来的命令。子目录的Makefile也从.config文件中提取信息&#xff0c;生成内核编译所需的文件列表。

二、内核Makefile导读与情景分析

1、概述

上面简要介绍了内核Makefile的总体结构&#xff0c;但当我们打开顶层Makefile文件时还是因为她的复杂而觉得无从下手。但是内核Makefile就是Makefile&#xff0c;和最简单的Makefile遵循着同样的规则。所以只要我们静下心来分析,还是可以理解的。当然&#xff0c;在阅读内核的Makefile前&#xff0c;你必须对Makefile和shell脚本有一定的基础。

推荐参考资料&#xff1a;

《》 翻译整理&#xff1a;徐海兵  PDF文档

《》翻译&#xff1a;杨春敏 黄毅

根据Makefile的执行规则&#xff0c;在分析Makefile时&#xff0c;首先必须确定一个目标&#xff0c;然后才能确定所有的依赖关系&#xff0c;最后根据更新情况决定是否执行相应的命令。所以要看懂内核Makefile的大致框架&#xff0c;我们首先要了解她里面所定义的目标。而内核Makefile所定义的目标基本上可以通过make help打印出来(因为help本身就是顶层Makefile的一个目标&#xff0c;里面是打印帮助信息的“echo”命令)。

这些目标可以分为以下几个大类&#xff1a;

目标

常用目标举例

作用

配置

%config

config

启动Kconfig&#xff0c;以不同界面来配置内核。

menuconfig

xconfig

编译

all

编译vmlinux内核映像和内核模块

vmlinux

编译vmlinux内核映像

modules

编译内核模块

安装

headers_install

安装内核头文件/模块

modules_install

源码浏览

tags

生成代码浏览工具所需要的文件

TAGS

cscope

静态分析

checkstack

检查并分析内核代码

namespacecheck

headers_check

内核打包

%pkg

以不同的安装格式编译内核

文档转换

%doc

把kernel文档转成不同格式

构架相关

(以arm为例)

zImage

生成压缩的内核映像

uImage

生成压缩的u-boot可引导的内核映像

install

安装内核映像

其中的构架相关目标在顶层Makefile上并未出现&#xff0c;而是被包含在平台相关的Makefile(arch/$(ARCH)/Makefile)中。

2、情景分析

以下我们就来分析一个简单的目标(menuconfig)&#xff0c;作为情景分析范例来演示一下内核Makefile的分析方法。

首先当我们在内核源码的根目录下执行make menuconfig命令时&#xff0c;根据规则&#xff0c;make程序读取顶层Makefile文件及其包含的Makefile文件&#xff0c;内建所有的变量、明确规则和隐含规则&#xff0c;并建立所有目标和依赖之间的依赖关系结构链表。make程序最终会调用规则&#xff1a;

config %config: scripts_basic

outputmakefile FORCE

$(Q)mkdir

-p include/linux include/config

$(Q)$(MAKE)

$(build)&#61;scripts/kconfig $&#64;

调用的原因是我们指定的目标“menuconfig”匹配了“%config”。

她的依赖目标是scripts_basic和outputmakefile&#xff0c;以及FORCE。也就是说在完成了这3个依赖目标后&#xff0c;下面的两个命令才会执行以完成我们指定的目标“menuconfig”。

所以我们来看看这三个依赖目标实现的简要过程&#xff1a;

(1)scripts_basic

make程序会调用规则&#xff1a;

scripts_basic:

$(Q)$(MAKE)

$(build)&#61;scripts/basic

他没有依赖目标&#xff0c;所以直接执行了以下的指令&#xff0c;只要将指令展开&#xff0c;我们就知道make做了什么操作。其中比较不好展开的是$(build)&#xff0c;她的定义在scripts/Kbuild.include中&#xff1a;

build :&#61; -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build

obj

所以展开后是&#xff1a;

make -f scripts/Makefile.build obj&#61; scripts/basic

也就是make解析执行scripts/Makefile.build文件&#xff0c;且参数obj&#61;

scripts/basic。而在解析执行scripts/Makefile.build文件的时候&#xff0c;scripts/Makefile.build又会通过解析传入参数来包含对应文件夹下的Makefile文件(scripts/basic/Makefile)&#xff0c;从中获得需要编译的目标。

在确定这个目标以后&#xff0c;通过目标的类别来继续包含一些scripts/Makefile.*文件。例如scripts/basic/Makefile中内容如下&#xff1a;

hostprogs-y :&#61; fixdep docproc hash

always      :&#61; $(hostprogs-y)

# fixdep is needed to

compile other host programs

$(addprefix

$(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep

所以scripts/Makefile.build会包含scripts/Makefile.host。相应的语句如下&#xff1a;

# Do not include host

rules unless needed

ifneq

($(hostprogs-y)$(hostprogs-m),)

include

scripts/Makefile.host

endif

此外scripts/Makefile.build会包含include

scripts/Makefile.lib等必须的规则定义文件&#xff0c;在这些文件的共同作用下完成对scripts/basic/Makefile中指定的程序编译。

由于Makefile.build的解析执行牵涉了多个Makefile.*文件&#xff0c;过程较为复杂&#xff0c;碍于篇幅无法一条一条指令的分析&#xff0c;兴趣的读者可以自行分析。

推荐两篇经典的分析文档&#xff1a;

《Kbuild系统原理分析》  作者未知&#xff0c;网上有PDF文档

(2)outputmakefile

make程序会调用规则&#xff1a;

PHONY &#43;&#61; outputmakefile

# outputmakefile

generates a Makefile in the output directory, if using a

# separate output

directory. This allows convenient use of make in the

# output directory.

outputmakefile:

ifneq ($(KBUILD_SRC),)

$(Q)ln -fsn $(srctree) source

$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \

$(srctree) $(objtree)

$(VERSION) $(PATCHLEVEL)

endif

从这里我们可以看出&#xff1a;outputmakefile是当KBUILD_SRC不为空(指定O&#61;dir&#xff0c;编译输出目录和源代码目录分开)时&#xff0c;在输出目录建立Makefile时才执行命令的&#xff0c;

如果我们在源码根目录下执行make menuconfig命令时&#xff0c;这个目标是空的&#xff0c;什么都不做。

如果我们指定了O&#61;dir时&#xff0c;就会执行源码目录下的scripts/mkmakefile&#xff0c;用于在指定的目录下产生一个Makefile&#xff0c;并可以在指定的目录下开始编译。

(3)FORCE

这是一个在内核Makefile中随处可见的伪目标&#xff0c;她的定义在顶层Makefile的最后&#xff1a;

PHONY

&#43;&#61; FORCE

FORCE:

是个完全的空目标&#xff0c;但是为什么要定义一个这样的空目标&#xff0c;并让许多目标将其作为依赖目标呢&#xff1f;原因如下&#xff1a;

正因为FORCE是一个没有命令或者依赖目标&#xff0c;不可能生成相应文件的伪目标。当make执行此规则时&#xff0c;总会认为FORCE不存在&#xff0c;必须完成这个目标&#xff0c;所以她是一个强制目标。也就是说&#xff1a;规则一旦被执行&#xff0c;make就认为它的目标已经被执行并更新过了。当她作为一个规则的依赖时&#xff0c;由于依赖总被认为被更新过的&#xff0c;因此作为依赖所在的规则中定义的命令总会被执行。所以可以这么说&#xff1a;只要执行依赖包含FORCE的目标&#xff0c;其目标下的命令必被执行。

在make完成了以上3个目标之后&#xff0c;就开始执行下面的命令的&#xff0c;首先是

$(Q)mkdir -p

include/linux include/config

这个很好理解&#xff0c;就是建立两个必须的文件夹。然后

$(Q)$(MAKE)

$(build)&#61;scripts/kconfig $&#64;

这和我们上面分析的$(Q)$(MAKE)

$(build)&#61;结构相同&#xff0c;将其展开得到&#xff1a;

make -f

scripts/Makefile.build obj&#61;scripts/kconfigmenuconfig

所以这个指令的效果是使make解析执行scripts/Makefile.build文件&#xff0c;且参数obj&#61;scripts/kconfig

menuconfig。这样Makefile.build会包含对应文件夹下的Makefile文件(scripts/kconfig /Makefile)&#xff0c;并完成scripts/kconfig /Makefile下的目标&#xff1a;

menuconfig:

$(obj)/mconf

$<$(Kconfig)

这个目标的依赖条件是$(obj)/mconf&#xff0c;通过分析可知她其实是对应以下规则&#xff1a;

mconf-objs  :&#61; mconf.o zconf.tab.o $(lxdialog)

……

ifeq

($(MAKECMDGOALS),menuconfig)

hostprogs-y &#43;&#61; mconf

endif

也就是编译生成本机使用的mconf程序。完成依赖目标后&#xff0c;通过scripts/kconfig/Makefile中对Kconfig的定义可知&#xff0c;最后执行&#xff1a;

mconfarch/$(SRCARCH)/Kconfig

而对于conf和xconf等都有类似的过程&#xff0c;所以总结起来&#xff1a;当make %config时&#xff0c;内核根目录的顶层Makefile会临时编译出scripts/kconfig中的工具程序conf/mconf/qconf等负责对arch/$(SRCARCH)/Kconfig文件进行解析。这个Kconfig又通过source标记调用各个目录下的Kconfig文件构建出一个Kconfig树&#xff0c;使得工具程序构建出整个内核的配置界面。在配置结束后&#xff0c;工具程序就会生成我们常见的.config文件。

三、在内核中添加自己的模块

虽然内核Makefile体系很是复杂&#xff0c;但是这种复杂带来的确是开发时的便利。其实内核Makefile体系之所以复杂&#xff0c;其中的一个原因就是为了方便扩展。对于一个开发者来要在内核中添加自己的一个驱动代码是非常简单的事情。

一般来说&#xff0c;对于一个新驱动代码的添加&#xff0c;驱动工程师只需要在内核源码的drivers目录的相应子目录下添加新设备驱动源码&#xff0c;并增加或修改该目录下的Kconfig和Makefile文件即可。

比如你已经写好了一个针对TI 的AM33XX芯片的LED的驱动程序&#xff0c;名为am33xx_led.c。

(1)将驱动源码am33xx_led.c等文件复制到linux-X.Y.Z/drivers/char目录。

(2)在该目录下的Kconfig文件中添加LED驱动的配置选项&#xff1a;

config AM33XX_LED

bool "Support for am33xx led

drivers"

depends on  SOC_OMAPAM33XX

default n

---help---

Say Y here if you want to support for AM33XX LED drivers.

(3)在该目录下的Makefile文件中添加对LED驱动的编译&#xff1a;

obj-$(CONFIG_AM33XX_LED)   &#43;&#61;  am33xx_led.o

这样你就可以在make menuconfig的时候看到这个配置选项&#xff0c;并进行配置了。

当然&#xff0c;上面的例子只是一个意思&#xff0c;对于Kconfig文件和Makefile的详细语法&#xff0c;请参考内核文档&#xff1a;Documentation/kbuild/makefile.txt

四 、在内核Makefile上对读者的建议

这个复杂的Makefile体系体现了很多优秀程序共有的设计思想&#xff0c;对于我们今后的程序设计上有很多值得借鉴的地方。比如&#xff1a;模块化设计、简化编程接口&#xff0c;使得自行添加模块更加的简洁。阅读分析这样复杂的Makefile对于学习和编写Makefile和shell脚本有很好的参考价值。如果你正在学习Makefile的编写和阅读&#xff0c;那你可以耐心的分析一下内核的Makefile体系&#xff0c;只要你认真分析了一两个目标的实现&#xff0c;你会发现当你在阅读一些小软件的Makefile时已经是轻车熟路了。特别是现在很多芯片的开发包都是以SDK包的形式发布的&#xff0c;而这些软件包都是通过Makefile体系来实现自动编译和配置的&#xff0c;所以熟悉Makefile是每个Linux开发者都需要做到的。



推荐阅读
  • 对于以压缩包形式发布的软件,其目录中通常包含一个配置脚本 `configure`。该脚本的主要功能是确定编译所需的各项参数,如头文件的位置和链接库的路径,并生成相应的 `Makefile` 以供编译使用。通过运行此脚本,开发者可以确保软件在不同环境下的正确编译与安装。此外,该脚本还能够检测系统依赖项,进一步提高编译过程的可靠性和兼容性。 ... [详细]
  • 掌握DSP必备的56个核心问题,我已经将其收藏以备不时之需! ... [详细]
  • PJSIP 编译与开发指南:深入解析 PJSIP 库的应用与优化
    PJSIP 编译与开发指南:深入解析 PJSIP 库的应用与优化 ... [详细]
  • 求助高手:下载的压缩包中包含CMake文件,如何在Windows环境下使用已安装的CMake GUI进行运行?
    从GitHub仓库 `https://github.com/vonmax007/RobotSimulation` 下载的代码包含多种算法,其中算法1的文件目录中包含了CMake文件。为了在Windows环境下使用已安装的CMake GUI运行这些文件,需要先确保CMake已正确安装,并按照以下步骤操作:打开CMake GUI,设置源代码路径和构建路径,点击“Configure”配置项目,然后点击“Generate”生成构建文件。最后,在生成的构建目录中使用命令行或IDE进行编译和运行。 ... [详细]
  • 《软件测试精要》深度解析与实战经验分享
    《软件测试精要》深度解析与实战经验分享,系统梳理了软件测试的核心概念与关键原则,结合实际项目中的测试经验和教训,详细探讨了测试分类、测试权衡要素、测试效率、测试覆盖率以及测试框架的引入和用例设计等内容,为读者提供了全面而实用的指导。 ... [详细]
  • 在进行网络编程时,准确获取本地主机的IP地址是一项基本但重要的任务。Winsock作为20世纪90年代初由Microsoft与多家公司共同制定的Windows平台网络编程接口,为开发者提供了一套高效且易用的工具。通过Winsock,开发者可以轻松实现网络通信功能,并准确获取本地主机的IP地址,从而确保应用程序在网络环境中的稳定运行。此外,了解Winsock的工作原理及其API函数的使用方法,有助于提高开发效率和代码质量。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • NOI题库(noi.openjudge.cn):1.7 编程基础之字符串 T31 至 T35 详解与解析
    T31至T35题目详细解析了字符串处理的基础编程技巧。其中,T31涉及P型编码,要求将一个仅包含数字字符的字符串转换为特定格式的编码串。例如,输入字符串“111223”应输出相应的P型编码结果。其他题目则涵盖了字符串的多种操作和变换方法,包括但不限于子串提取、字符替换和模式匹配等,旨在提升编程者对字符串处理的综合能力。 ... [详细]
  • 在前一篇文章中,我们介绍了如何使用Requests库发送GET请求。本文将深入探讨如何通过Requests库发送POST请求,包括参数格式、请求封装等关键技巧,并通过“历史上的今天”API实例进行详细说明。 ... [详细]
  • 本文分享了将物理服务器上的操作系统、应用软件及数据迁移到阿里云ECS服务器的实际经验。P2V迁移通过利用多种工具软件,将物理服务器的系统状态和数据完整地复制到虚拟磁盘中,确保在阿里云平台上顺利运行。该过程不仅涉及技术细节,还涵盖了迁移前的准备、迁移中的监控以及迁移后的验证等多个环节,为用户提供了一套全面的迁移方案。 ... [详细]
  • 如何将PHP文件上传至服务器及正确配置服务器地址 ... [详细]
  • HBase在金融大数据迁移中的应用与挑战
    随着最后一台设备的下线,标志着超过10PB的HBase数据迁移项目顺利完成。目前,新的集群已在新机房稳定运行超过两个月,监控数据显示,新集群的查询响应时间显著降低,系统稳定性大幅提升。此外,数据消费的波动也变得更加平滑,整体性能得到了显著优化。 ... [详细]
  • 首期 Cosmos SDK 中文开发者培训课程顺利落幕 ... [详细]
  • 在上篇文章的基础上,本文将继续探讨 Linux 设备驱动中的设备模型与 `devicedriverbus` 机制。在将设备注册到总线之前,需要先创建 `device` 对象。可以通过静态定义 `device` 结构体变量,并调用 `device_register` 函数来完成这一过程。此外,文章还将详细解析设备模型的内部工作机制,以及 `devicedriverbus` 机制如何实现设备与驱动的自动匹配和管理。 ... [详细]
  • NanoPi2 使用体验深入解析(续篇)
    随着Raspberry Pi的问世,开源硬件领域迎来了前所未有的发展,激发了全球范围内的创新热潮。在中国,这一趋势同样催生了一系列类似的开发板,例如NanoPi 2。本文作为前篇的延续,将深入探讨NanoPi 2的实际使用体验,从性能、兼容性到应用场景,进行全面分析。 ... [详细]
author-avatar
mobiledu2502878013
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有