徐州做网站建设的公司,做开锁推广什么网站好,企业网站模板官网,制作网络网站众所周知#xff0c;Linux内核是使用make命令来配置并编译的#xff0c;那必然少不了Makefile。在内核目录树中我们可以看到内核编译系统的顶层Makefile文件。但是如此复杂、庞大的内核源码绝不可能使用一个或几个Makefile文件来完成配置编译#xff0c;而是需要一套同样复杂…众所周知Linux内核是使用make命令来配置并编译的那必然少不了Makefile。在内核目录树中我们可以看到内核编译系统的顶层Makefile文件。但是如此复杂、庞大的内核源码绝不可能使用一个或几个Makefile文件来完成配置编译而是需要一套同样复杂、庞大且为Linux内核定制的Makefile系统。她可以说是内核的一个子系统是内核中比较特殊的一部分几乎都是应用层的程序和脚本但又和生成的内核二进制文件息息相关。编译不仅涉及本地编译还涉及各个平台之间的交叉编译以及二进制文件格式处理等等。她是对Makefile在功能上的扩充使其在配置编译Linux内核的时候更加灵活、高效和简洁。尽管她是一个复杂的系统但对绝大部分内核开发者来说只需要知道如何使用而无需了解其中的细节。她对绝大部分内核开发者基本上是透明的隐藏了大部分实现细节有效地降低了开发者的负担能使其能专注于内核开发而不至于花费时间和精力在编译过程上。以下我们就来简要的了解一下内核Makefile体系。一、内核Makefile体系概述其实内核Makefile体系的包含了Kconfig和Kbuild两个系统。她曾经的维护人是SamRavnborg 现在的暂时没有查到。参考资料Kconfig对应的是内核配置阶段如你使用命令make menuconfig就是在使用Kconfig系统。Kconfig由以下三部分组成scripts/kconfig/*Kconfig文件解析程序kconfig各个内核源代码目录中的kconfig文件arch/$(ARCH)/configs/*_defconfig各个平台的缺省配置文件当Kconfig系统生成.config后Kbuild会依据.config编译指定的目标。后面我会简单地对make %config的流程进行情景分析这里不必赘述。Kbuild是内核Makefile体系重点对应内核编译阶段由5个部分组成顶层Makefile根据不同的平台对各类target分类并调用相应的规则Makefile生成目标.config内核配置文件arch/$(ARCH)/Makefile具体平台相关的Makefilescripts/Makefile.*通用规则文件面向所有的Kbuild Makefiles所起的作用可以从后缀名中得知。各子目录下的Makefile文件由其上层目录的Makefile调用执行其上层传递下来的命令而其中scripts目录下的编译规则文件和其目录下的C程序在整个编译过程起着重要的作用。列举如下文件名作用Kbuild.include共用的定义文件被许多独立的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文件并根据.config文件确定访问哪些子目录并通过递归向下访问子目录的形式完成。顶层Makefile同时根据.config文件原封不动的包含一个具体架构的Makefile其名字类似于arch/$(ARCH)/Makefile。该架构Makefile向顶层Makefile提供其架构的特别信息。每一个子目录都有一个Makefile文件用来执行从其上层目录传递下来的命令。子目录的Makefile也从.config文件中提取信息生成内核编译所需的文件列表。二、内核Makefile导读与情景分析1、概述上面简要介绍了内核Makefile的总体结构但当我们打开顶层Makefile文件时还是因为她的复杂而觉得无从下手。但是内核Makefile就是Makefile和最简单的Makefile遵循着同样的规则。所以只要我们静下心来分析,还是可以理解的。当然在阅读内核的Makefile前你必须对Makefile和shell脚本有一定的基础。推荐参考资料《》 翻译整理徐海兵 PDF文档《》翻译杨春敏 黄毅根据Makefile的执行规则在分析Makefile时首先必须确定一个目标然后才能确定所有的依赖关系最后根据更新情况决定是否执行相应的命令。所以要看懂内核Makefile的大致框架我们首先要了解她里面所定义的目标。而内核Makefile所定义的目标基本上可以通过make help打印出来(因为help本身就是顶层Makefile的一个目标里面是打印帮助信息的“echo”命令)。这些目标可以分为以下几个大类目标常用目标举例作用配置%configconfig启动Kconfig以不同界面来配置内核。menuconfigxconfig编译all编译vmlinux内核映像和内核模块vmlinux编译vmlinux内核映像modules编译内核模块安装headers_install安装内核头文件/模块modules_install源码浏览tags生成代码浏览工具所需要的文件TAGScscope静态分析checkstack检查并分析内核代码namespacecheckheaders_check内核打包%pkg以不同的安装格式编译内核文档转换%doc把kernel文档转成不同格式构架相关(以arm为例)zImage生成压缩的内核映像uImage生成压缩的u-boot可引导的内核映像install安装内核映像其中的构架相关目标在顶层Makefile上并未出现而是被包含在平台相关的Makefile(arch/$(ARCH)/Makefile)中。2、情景分析以下我们就来分析一个简单的目标(menuconfig)作为情景分析范例来演示一下内核Makefile的分析方法。首先当我们在内核源码的根目录下执行make menuconfig命令时根据规则make程序读取顶层Makefile文件及其包含的Makefile文件内建所有的变量、明确规则和隐含规则并建立所有目标和依赖之间的依赖关系结构链表。make程序最终会调用规则config %config: scripts_basicoutputmakefile FORCE$(Q)mkdir-p include/linux include/config$(Q)$(MAKE)$(build)scripts/kconfig $调用的原因是我们指定的目标“menuconfig”匹配了“%config”。她的依赖目标是scripts_basic和outputmakefile以及FORCE。也就是说在完成了这3个依赖目标后下面的两个命令才会执行以完成我们指定的目标“menuconfig”。所以我们来看看这三个依赖目标实现的简要过程(1)scripts_basicmake程序会调用规则scripts_basic:$(Q)$(MAKE)$(build)scripts/basic他没有依赖目标所以直接执行了以下的指令只要将指令展开我们就知道make做了什么操作。其中比较不好展开的是$(build)她的定义在scripts/Kbuild.include中build : -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.buildobj所以展开后是make -f scripts/Makefile.build obj scripts/basic也就是make解析执行scripts/Makefile.build文件且参数objscripts/basic。而在解析执行scripts/Makefile.build文件的时候scripts/Makefile.build又会通过解析传入参数来包含对应文件夹下的Makefile文件(scripts/basic/Makefile)从中获得需要编译的目标。在确定这个目标以后通过目标的类别来继续包含一些scripts/Makefile.*文件。例如scripts/basic/Makefile中内容如下hostprogs-y : fixdep docproc hashalways : $(hostprogs-y)# fixdep is needed tocompile other host programs$(addprefix$(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep所以scripts/Makefile.build会包含scripts/Makefile.host。相应的语句如下# Do not include hostrules unless neededifneq($(hostprogs-y)$(hostprogs-m),)includescripts/Makefile.hostendif此外scripts/Makefile.build会包含includescripts/Makefile.lib等必须的规则定义文件在这些文件的共同作用下完成对scripts/basic/Makefile中指定的程序编译。由于Makefile.build的解析执行牵涉了多个Makefile.*文件过程较为复杂碍于篇幅无法一条一条指令的分析兴趣的读者可以自行分析。推荐两篇经典的分析文档《Kbuild系统原理分析》 作者未知网上有PDF文档(2)outputmakefilemake程序会调用规则PHONY outputmakefile# outputmakefilegenerates a Makefile in the output directory, if using a# separate outputdirectory. 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从这里我们可以看出outputmakefile是当KBUILD_SRC不为空(指定Odir编译输出目录和源代码目录分开)时在输出目录建立Makefile时才执行命令的如果我们在源码根目录下执行make menuconfig命令时这个目标是空的什么都不做。如果我们指定了Odir时就会执行源码目录下的scripts/mkmakefile用于在指定的目录下产生一个Makefile并可以在指定的目录下开始编译。(3)FORCE这是一个在内核Makefile中随处可见的伪目标她的定义在顶层Makefile的最后PHONY FORCEFORCE:是个完全的空目标但是为什么要定义一个这样的空目标并让许多目标将其作为依赖目标呢原因如下正因为FORCE是一个没有命令或者依赖目标不可能生成相应文件的伪目标。当make执行此规则时总会认为FORCE不存在必须完成这个目标所以她是一个强制目标。也就是说规则一旦被执行make就认为它的目标已经被执行并更新过了。当她作为一个规则的依赖时由于依赖总被认为被更新过的因此作为依赖所在的规则中定义的命令总会被执行。所以可以这么说只要执行依赖包含FORCE的目标其目标下的命令必被执行。在make完成了以上3个目标之后就开始执行下面的命令的首先是$(Q)mkdir -pinclude/linux include/config这个很好理解就是建立两个必须的文件夹。然后$(Q)$(MAKE)$(build)scripts/kconfig $这和我们上面分析的$(Q)$(MAKE)$(build)结构相同将其展开得到make -fscripts/Makefile.build objscripts/kconfigmenuconfig所以这个指令的效果是使make解析执行scripts/Makefile.build文件且参数objscripts/kconfigmenuconfig。这样Makefile.build会包含对应文件夹下的Makefile文件(scripts/kconfig /Makefile)并完成scripts/kconfig /Makefile下的目标menuconfig:$(obj)/mconf$ $(Kconfig)这个目标的依赖条件是$(obj)/mconf通过分析可知她其实是对应以下规则mconf-objs : mconf.o zconf.tab.o $(lxdialog)……ifeq($(MAKECMDGOALS),menuconfig)hostprogs-y mconfendif也就是编译生成本机使用的mconf程序。完成依赖目标后通过scripts/kconfig/Makefile中对Kconfig的定义可知最后执行mconfarch/$(SRCARCH)/Kconfig而对于conf和xconf等都有类似的过程所以总结起来当make %config时内核根目录的顶层Makefile会临时编译出scripts/kconfig中的工具程序conf/mconf/qconf等负责对arch/$(SRCARCH)/Kconfig文件进行解析。这个Kconfig又通过source标记调用各个目录下的Kconfig文件构建出一个Kconfig树使得工具程序构建出整个内核的配置界面。在配置结束后工具程序就会生成我们常见的.config文件。三、在内核中添加自己的模块虽然内核Makefile体系很是复杂但是这种复杂带来的确是开发时的便利。其实内核Makefile体系之所以复杂其中的一个原因就是为了方便扩展。对于一个开发者来要在内核中添加自己的一个驱动代码是非常简单的事情。一般来说对于一个新驱动代码的添加驱动工程师只需要在内核源码的drivers目录的相应子目录下添加新设备驱动源码并增加或修改该目录下的Kconfig和Makefile文件即可。比如你已经写好了一个针对TI 的AM33XX芯片的LED的驱动程序名为am33xx_led.c。(1)将驱动源码am33xx_led.c等文件复制到linux-X.Y.Z/drivers/char目录。(2)在该目录下的Kconfig文件中添加LED驱动的配置选项config AM33XX_LEDbool Support for am33xx leddriversdepends on SOC_OMAPAM33XXdefault n---help---Say Y here if you want to support for AM33XX LED drivers.(3)在该目录下的Makefile文件中添加对LED驱动的编译obj-$(CONFIG_AM33XX_LED) am33xx_led.o这样你就可以在make menuconfig的时候看到这个配置选项并进行配置了。当然上面的例子只是一个意思对于Kconfig文件和Makefile的详细语法请参考内核文档Documentation/kbuild/makefile.txt四 、在内核Makefile上对读者的建议这个复杂的Makefile体系体现了很多优秀程序共有的设计思想对于我们今后的程序设计上有很多值得借鉴的地方。比如模块化设计、简化编程接口使得自行添加模块更加的简洁。阅读分析这样复杂的Makefile对于学习和编写Makefile和shell脚本有很好的参考价值。如果你正在学习Makefile的编写和阅读那你可以耐心的分析一下内核的Makefile体系只要你认真分析了一两个目标的实现你会发现当你在阅读一些小软件的Makefile时已经是轻车熟路了。特别是现在很多芯片的开发包都是以SDK包的形式发布的而这些软件包都是通过Makefile体系来实现自动编译和配置的所以熟悉Makefile是每个Linux开发者都需要做到的。