Linux 26内核Makefile分析

  相关的文章凤毛麟角,笔者抽时间完成了这篇分析文章,让读者迅速熟悉Linux最新体系,从而加深对内核的理解,同时也希望能对Linux在公司的推广起到一定的推动作用,算是抛砖引玉吧!

  顶层Makefile通过读取配置文件,递归编译内核代码树的相关目录,从而产生两个重要的目标文件:vmlinux和模块。

  位于arch/$(ARCH) 目录下,为顶层Makefile提供与具体硬件体协结构相关的信息。

  通过调用make menuconfig或者make xconfig命令,用户可以选择需要的配置来生成期望的目标文件。

  主要为整个Makefile体系提供各自模块的目标文件定义,上层Makefile根据它所定义的目标来完成各自模块的编译。

  在编译内核之前,用户必须首先完成必要的配置。Linux内核提供了数不胜数的功能,支持众多的硬件体系结构,这就需要用户对将要生成的内核进行裁减。内核提供了多种不同的工具来简化内核的配置,最简单的一种是字符界面下命令行工具:

  这个工具会依次遍历内核所有的配置项,要求用户进行逐项的选择配置。这个工具会耗费用户太多时间,除非万不得以(你的编译主机不支持其他配置工具)一般不建议使用。

  相信以前对2.4内核比较熟悉的用户一定不会陌生。当然在2.6内核中提供了更漂亮和方便的基于X11的图形配置工具:

  当用户使用这个工具对Linux内核进行配置时,界面下方会出现这个配置项相关的帮助信息和简单描述,当你对内核配置选项不太熟悉时,建议你使用这个工具来进行内核配置。

  当用户完成配置后,配置工具会自动生成.config文件,它被保存在内核代码树的根目录下。用户可以很容易找到它,当然用户也可以直接对这个文件进行简单的修改。但是当你修改过配置文件之后,你必须通过下面的命令来验证和更新配置:

  跟2.4版本的不同之处在于,用户不需要显示的调用make dep命令来生成依赖文件,内核会自动维护代码间的依赖关系。

  当一切工作完成以后,用户只需要简单键入make,剩下所有的工作makefile就会自动替你完成了。

  当用户使用Linux的Makefile编译内核版本时,Makefile的编译流程如下:

   使用命令行或者图形界面配置工具,对内核进行裁减,生成.config配置文件

   链接上述过程产生的目标文件生成vmlinux,vmlinux存放在内核代码树的根目录下

  目标定义是Makefile文件的核心部分,目标定义通知Makefile需要生成哪些目标文件、如何根据特殊的编译选项链接目标文件,同时控制哪些子目录要递归进入进行编译。

  这表示与ext2相关的目标文件由 ext2-y定义的文件列表组成,其中ext2-$(*)是由内核配置文件.config中的配置项决定,最终Makefile会在这个目录下统一生成一个目标文件ext2.o(由obj-$(CONFIG_EXT2_FS)决定)。其中obj-y表示为生成vmlinux文件所需要的目标文件集合,海湾8305模块具体的文件依赖于内核配置。

  Makefile会编译所有的$(obj-y)中定义的文件,然后调用链接器将这些文件链接到built-in.o文件中。最终built-in.o文件通过顶层Makefile链接到vmlinux中。海湾8305模块值得注意的是$(obj-y)的文件顺序很重要。列表文件可以重复,文件第一次出现时将会链接到built-in.o中,后来出现的同名文件将会被忽略。文件顺序直接决定了他们被调用的顺序,这一点读者需要特别注意。

  读者可能会在某些Makefile中发现lib-y定义,所有包含在lib-y定义中的目标文件都将会被编译到该目录下一个统一的库文件中。值得注意的是lib-y定义一般被限制在 lib 和arch/$(ARCH)/lib 目录中。

  体系makefile文件和顶层makefile文件共同定义了如何建立vmlinux文件的规则。

  Makefile文件只负责当前目录下的目标文件,子目录中的文件由子目录中的makefile负责编译,编译系统使用obj-y 和 obj-m来自动递归编译各个子目录中的文件。

  如果在内核配置文件.config中,CONFIG_EXT2_FS被设置为y或者m,则内核makefile会自动进入ext2目录来进行编译。内核Makefile只使用这些信息来决定是否需要编译这个目录,子目录中的makefile规定哪些文件编译为模块,哪些文件编译进内核。

  Linux Makefile通过在编译过程中生成的 .文件名.o.cmd(比如对于main.c文件,它对应的依赖文件名为.main.o.cmd)来定义相关的依赖关系。

   所有的前期依赖文件(包括所有相关的*.c 和 *.h)

  位于init目录下的main.c文件的依赖文件.main.o.cmd内容如下,读者可以结合起来理解上述文件依赖关系的三个组成部分:

  特殊规则使用在内核编译需要规则定义而没有相应定义的时候。典型的例子如编译时头文件的产生规则。其他例子有体系makefile编译引导映像的特殊规则。特殊规则写法同普通的makefile规则。

  编译程序在makefile所在的目录不能被执行,因此所有的特殊规则需要提供前期文件和目标文件的相对路径。

  $(src): $(src)是对于makefile文件目录的相对路径,当使用代码树中的文件时

  $(obj): $(obj)是目标文件目录的相对路径。生成文件使用$(obj)变量。

  目标文件依赖于两个前提文件。目标文件的前缀是$(obj), 前提文件的前缀是

  体系makefile文件定义了编译vmlinux文件的目标对象,将它们压缩和封装成引导代码,并复制到合适的位置。这包括各种安装命令。在Linux中Makefile无法为所有的体系结构提供标准化的方法,因此常需要具体硬件体系结构下makefile提供附加处理规则。

  当执行不带参数的make命令时,将首先编译第一个目标对象。在顶层makefile中第一个目标对象是all:。

  增加新的前提文件给all目标可以设置不同于vmlinux的默认目标对象。海湾8305模块

  当这条规则被使用时它将检查哪些文件需要更新,或命令行被改变。后面这种情况将迫使

  重新编译编译选项被改变的执行文件。使用if_changed的目标对象必须列举在$( builtin-target)中,否则命令行检查将失败,目标一直会编译。

  当这条规则被使用时它将检查哪些文件需要更新,或命令行被改变。同时它会重新检测依赖关系的改变并将生成新的依赖文件。这是与if_changed命令的区别。

  当正常执行带编译命令时命令的简短信息会被显示(要想显示详细的命令,请在命令行中加入V=1)。要让定制命令具有这种功能需要设置两个变量:

  相同目录下的vmlinux.lds.S文件是这个脚本的预处理的变体。内核编译系统知晓.lds

  内核编译系统支持在编译阶段编译主机可执行程序。为了使用主机程序需要两个步骤:第一个步骤使用hostprogs-y变量告诉内核编译系统有主机程序可用。第二步给主机程序添加潜在的依赖关系。有两种方法,在规则中增加依赖关系或使用$(always)变量。这一部分的内容相对于其他内核文件的编译要简单的多,感兴趣的读者可以参考scripts/Makefile.build中的相关内容。

  当执行make clean命令时, devlist.h classlist.h两个文件将被删除。内核编译系统默认这些文件与makefile具有相同的相对路径,否则需要设置以/开头的绝对路径。

  这样就将删除包括子目录在内的整个debian目录。如果不使用以/开头的绝对路径内核编译系统见默认使用相对路径。

  通常内核编译系统根据obj-* := dir/进入子目录,但是在体系makefile中需要显式使用如下方式:

  上面赋值语句指示编译系统执行make clean命令时进入compressed/目录。

  在编译最终的引导映像文件的makefile中有一个可选的目标对象名称是archclean。

  随着Linux的飞速发展,越来越多的开发人员将关注的焦点集中到Linux的研究和开发上。如果想对Linux内核进行研究和开发,就必须首先熟悉Linux 内核Makefile的组织和编译过程。目前Linux最新的稳定内核版本为2.6.17,但是当今绝大部分对于Linux Makefile的介绍都是基于2.4内核的,可以说关于2.6内核Makefile相关的文章凤毛麟角,我特意抽时间完成了这篇分析文章,让读者迅速熟悉Linux最新Makefile体系,从而加深对内核的理解,同时也希望能对Linux在公司的推广起到一定的推动作用。

本文由泰州市功放模块有限公司发布于技术中心,转载请注明出处:Linux 26内核Makefile分析

相关阅读