Linux Kbuild文档(转)
转载链接:http://blog.chinaunix.net/uid-10221131-id-2943265.html
Linux Kbuild文档
Linux Kbuild文档 V 0.1 2008-10-30 目录 Linux内核配置方式1.1 概述 Linux内核源代码组织了一个配置系统,该配置系统可以生成内核配置菜单,方便内核配置。配置系统主要包含Makefile、Kconfig和配置工具,可以生成配置界面。其中,配置界面是通过配置工具来生成的,配置工具通过Makefile编译执行,配置界面中的选项则是通过各级的Kconfig(老版本也称Config.in)和Makefile(老版本也称Kbuild)文件定义。 Linux内核配置系统也被移植到其它软件(如Busybox、glibc、uclibc等)中,来提供同样的配置界面以方便有选择性的配置。 1.2 内核配置工具 Linux内核配置命令主要有:make config、make menuconfig、make xconfig和make gconfig,分别是字符界面、ncurses光标菜单、QT图形窗口和GTK图形窗口的配置界面。字符界面配置方式需要回答每一个选项提示,逐个回答进行配置并不方便,而光标和图形配置界面界面友好,方便实用。 make config是完全命令行的配置方式,make menuconfig依赖于ncurses库,make xconfig依赖于QT图形库,make gconfig依赖于GTK图形库。 不同的内核配置方式,分别通过不同的配置工具来完成。scripts目录下提供了各种内核配置工具,表1是这些工具的说明。 表1 内核配置工具说明
其中zconf.tab.c程序实现了解析Kconfig文件和内核配置主要函数。Zconf.tab.c程序还直接包括了下列一些C程序,这样各种配置功能都包含在zconf.tab.o目标文件中了。 其中,lex.zconf.c实现lex语法解析器, util.c实现配置工具, confdata.c实现.config等相关数据文件保存, expr.c实现表达式函数, symbol.c实现变量处理函数, menu.c实现菜单控制函数。 1.3 内核配置方式 在顶层的Makefile中,可以查找到如下几行定义的规则: 这就是生成内核配置界面的命令规则,它也定义了执行的目标和依赖的前提条件,还有要执行的命令。这条规则定义的目标为config %config,通配符%意味着可以包括config、menuconfig、xconfig、gconfig等。依赖的前提条件是scripts_basic outputmakefile,这些在Makefile中也是规则定义,主要用来编译生成配置工具。这条规则执行的命令就是执行scripts/kconfig/Makefile制定的规则。 根据配置工具的不同,内核有不同的配置方式。有命令行方式,还有图形界面方式。表2是各种内核配置方法的说明。 表2 内核配置方法的说明
这些内核配置方式是在scripts/kconfig/Makefile中通过规则定义的。从这个Makefile中,可以找到下面一些规则定义。如果把变量或者通配符带进去,就可以明白要执行的操作。 这里的ARCH以arm为例来说明。 执行命令:scripts/kconfig/qconf arch/arm/Kconfig,使用QT图形库生成配置界面,arch/arm/Kconfig是菜单的主配置文件,每种配置方式都需要。 执行命令:scripts/kconfig/qconf arch/arm/Kconfig,使用GTK图形库生成配置界面。 执行命令:scripts/kconfig/mconf arch/arm/Kconfig,使用lxdialog工具,生成光标配置菜单。 执行命令:scripts/kconfig/conf (-o/s) arch/arm/Kconfig,完全命令行的内核配置方式。使用“-o”选项,直接读取已经存在的.config文件,要求确定内核新的配置项。使用“-s”选项,直接读取已经存在的.config文件,提示但不要求确认内核新的配置项。 通过上述各种方式都可以完成配置内核的工作,在顶层目录下生成.config文件。这个.config文件保存大量的内核配置项,.config会自动转换成include/linux/autoconf.h头文件。在include/linux/config.h文件中,将包含使用include/linux/autoconf.h头文件。 2. Kconfig linux在2.6版本以后将配置文件由原来的config.in改为Kconfig,对于Kconfig的语法在内核源代码/Documentation/kbuild/kconfig-language.txt中做了详细的说明。 2.1 Kconfig的树状关系 Kconfig的配置选项是以树的形式组织的,如下所示所示: 每个选项都有其自己的依赖关系。这些依赖关系决定了选项是否是可见的。父选项可见,子选项才能可见。 arch/$(ARCH)/Kconfig文件是主Kconfig文件,跟体系结构有关系。主Kconfig文件调用其他目录的Kconfig文件,其他的Kconfig文件又调用各级子目录的配置文件,成树状关系。 2.2菜单选项 多数选项定义了一个配置选项,其它选项起辅助组织作用。一个配置选项定义可以是下面的形式: 每行都是以关键字开始,并可以接多个参数。"config" 为定义了一新的配置选项。下面的几行定义了该配置选项的属性。属性可以是该配置选项的类型,输入提示(input prompt),依赖关系,帮助信息和默认值。一个配置选项可以用相同的名字定义多次,但每个定义只能有一个输入提示并且类型还不能冲突。 2.3菜单属性 一个菜单选项可以有多个属性,这些属性受到语法的限制。每个配置选项都必须指定类型。类型定义包括:"bool"、"tristate"、"string"、"hex"、"int"共五种。其中有两个基本类型:tristate 和 string,其他类型都是基于这两个基本类型。内核菜单属性说明表3所示。 表3 内核菜单属性说明
2.4菜单依赖关系 依赖关系决定了菜单选项是否可见,也可以减少tristate的输入范围。tristate逻辑比boolean逻辑在表达式中用更多的状态(state)来表示模块的状态。依赖关系表达式的语法如表4所示,表达式是以优先级的降序列出的。 表4 菜单依赖关系语法说明
一个表达式的值可以是'n','m'或'y'(或者是计算的结果 0,1,2)。当表达式的值为'm'或'y'的时候,菜单项才是可见的。 symbol有两种类型:不可变的和可变的。不可变的symbol是最普通的,由'config'语句定义,完全由数字、字母和下划线组成(alphanumeric characters or underscores)。 不可变的symbol只是表达式的一部分。经常用单引号或双引号括起来。在引号中,可以使用任何字符,使用引号要用转义字符'\'。 2.5菜单结构 菜单在树中的位置可由两种方法决定。 第一种可以是这样: 所有的在"menu" ... "endmenu" 之间都是"Network device support"的子菜单。所有的子菜单选项都继承了父菜单的依赖关系,比如,"NET"的依赖关系就被加到了配置选项NETDEVICES的依赖列表中。 第二种是通过分析依赖关系生成菜单的结构。如果菜单选项在一定程度上依赖于前面的选项,它就能成为该选项的子菜单。首先,前面的(父)选项必须是依赖列表中的一部分并且它们中必须有满足下面两个条件的选项:如果父选项为'n',子选项必须不可见;如果父选项可见,子选项才能可见。 MODVERSIONS 直接依赖 MODULES,这就意味着如果MODULES不为'n',该选项才可见。换句话说,当MODULES可见时,选项才可见(MODULES的(空)依赖关系也是选项依赖关系的一部分)。 2.6 Kconfig语法 配置文件描述了菜单选项,每行都是以一关键字开头(除了帮助信息)。菜单的关键字如表5所示。其中菜单开头的关键字有:config、menuconfig、choice/endchoice、comment、menu/endmenu。它们也可以结束一个菜单选项,另外还有if/endif、source也可以结束菜单选项。 表5 Kconfig菜单关键字说明
3. Kbuild Makefile Linux内核源代码是通过Makefile组织编译的,Linux2.6内核Makefile的许多特性和2.4内核差别很大,在内核目录的documention/kbuild/makefiles.txt中有详细的说明。 3.1 Makefile的组织结构 Linux内核的Makefile分为5个部分,如表6所示: 表6 Makefile的5个部分
顶层Makefile阅读的.config文件,而该文件是由内核配置程序生成的。 顶层Makefile负责制作:vmlinux(内核文件)与模块(任何模块文件)。制作的过程主要是 通过递归向下访问子目录的形式完成。并根据内核配置文件确定访问哪些子目录。顶层Makefile要原封不动的包含一具体架构的Makefile,其名字类似于arch/$(ARCH)/Makefile。该架构Makefile向顶层Makefile提供其架构的特别信息。 每一个子目录都有一个Kbuild Makefile文件,用来执行从其上层目录传递下来的命令。 Kbuild Makefile从.config文件中提取信息,生成Kbuild完成内核编译所需的文件列表。 scripts/Makefile.*包含了所有的定义、规则等信息。这些文件被用来编译基于kbuild Makefile的内核。 3.2 Makefile语言 内核的Makefile使用的是GNU Make。该Makefile只使用GNU Make已注明的功能,并使用了许多GNU 的扩展功能。 GNU Make支持基本的显示处理过程的函数。内核Makefile 使用了一种类似小说的方式,显示"if"语句的构造、处理过程。 GNU Make 有2个赋值操作符,":="和"="。":=",将对右边的表达式求值,并将所求的值赋给左边。"="更像是一个公式定义,只是将右边的值简单的赋值给左边,当左边的表达式被使用时,才求值。 有时使用"="是正确的。但是,一般情况下,推荐使用":="。 3.3 Kbuild 变量 顶层Makefile输出以下变量: (1)VERSION、PATCHLEVEL、SUBLEVEL和EXTRAVERSION 这些变量定义了当前内核的版本号。只有很少一部分Makefile会直接用到这些变量;可使用 $(KERNELRELEASE)代替。$(VERSION),$(PATCHLEVEL),和$(SUBLEVEL)定义了最初使用的三个数字的版本号,比如"2""4"和"0"。这三个值一般是数字。$(EXTRAVERSION) 为了补丁定义了更小的版本号。一般是非数字的字符串,比如"-pre4" ,或就空着。 (2)KERNELRELEASE $(KERNELRELEASE) 是一个字符串,类似"2.4.0-pre4",用于安装目录的命名或显示当前的版本号。一部分架构Makefile使用该变量。 (3)ARCH 该变量定义了目标架构,比如"i386","arm" 或"sparc"。有些Kbuild Makefile根据 $(ARCH) 决定编译哪些文件。 默认情况下,顶层Makefile将其设置为本机架构。如果是跨平台编译,用户可以用下面的命令覆盖该值: make ARCH=m68k ... (4)INSTALL_PATH 该变量为架构Makefile定义了安装内核镜像与 System.map 文件的目录。主要用来指明架构特殊的安装路径。 (5)INSTALL_MOD_PATH和MODLIB $(INSTALL_MOD_PATH) 为了安装模块,给 $(MODLIB) 声明了前缀。该变量不能在Makefile中定义,但可以由用户传给Makefile。 $(MODLIB) 具体的模块安装的路径。顶层Makefile将$(MODLIB)定义为 $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。用户可以通过命令行参数的形式将其覆盖。 (6)INSTALL_MOD_STRIP 如果该变量有定义,模块在安装之前,会被剥出符号表。如果INSTALL_MOD_STRIP 为 "1",就使用默认选项 --strip-debug。否则,INSTALL_MOD_STRIP 将作为命令 strip的选项使用。 3.4 Kbuild Makefile的定义 大部分内核中的Makefile都是使用Kbuild组织结构的Kbuild Makefile。这章介绍了 Kbuild Makefile的语法。 Kbuild文件倾向于"Makefile"这个名字,"Kbuild"也是可以用的。但如果"Makefile" "Kbuild"同时出现的话,使用的将会是"Kbuild"文件。 3.4.1 目标定义 目标定义是Kbuild Makefile的主要部分,也是核心部分。主要是定义了要编 译的文件,所有的选项,以及到哪些子目录去执行递归操作。 最简单的Kbuild makefile 只包含一行,如: 该例子告诉Kbuild在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c或foo.S文件编译得到。 如果foo.o要编译成一模块,那就要用obj-m了。所采用的形式如下: $(CONFIG_FOO)可以为y(编译进内核) 或m(编译成模块)。如果CONFIG_FOO不是y和m,那么该文件就不会被编译联接了。 3.4.2 编译进内核 - obj-y Kbuild Makefile 规定所有编译进内核的目标文件都存在$(obj-y)列表中。而这些列表依赖内核的配置。 Kbuild编译所有的$(obj-y)文件。然后,调用"$(LD) -r"将它们合并到一个build-in.o文件中。稍后,该build-in.o会被其父Makefile联接进vmlinux中。 $(obj-y)中的文件是有顺序的。列表中有重复项是可以的:当第一个文件被联接到built-in.o中后,其余文件就被忽略了。联接也是有顺序的,那是因为有些函数(module_init()/__initcall)将会在启动时按照他们出现的顺序进行调用。所以,记住改变联接的顺序可能改变你SCSI控制器的检测顺序,从而导致你的硬盘数据损害。 举例说明obj-y: 3.4.3 编译可装载模块 - obj-m $(obj-m) 列举出了哪些文件要编译成可装载模块。 一个模块可以由一个文件或多个文件编译而成。如果是一个源文件,Kbuild Makefile只需简单的将其加到$(obj-m)中去就可以了。例如: 注意:此例中 $(CONFIG_ISDN_PPP_BSDCOMP) 的值为'm' 如果内核模块是由多个源文件编译而成,那你就要采用上面那个例子一样的方法去声明你所要编译的模块。Kbuild需要知道你所编译的模块是基于哪些文件,所以你需要通过变量$(<module_name>-objs)来告诉它。例如: 在这个例子中,模块名将是isdn.o,Kbuild将编译在$(isdn-objs)中列出的所有文件,然后使用"$(LD) -r"生成isdn.o。 Kbuild能够识别用于组成目标文件的后缀-objs和后缀-y。这就让Kbuild Makefile可以通过使用 CONFIG_ 符号来判断该对象是否是用来组合对象的。例如: 在这个例子中,如果 $(CONFIG_EXT2_FS_XATTR) 是 'y',xattr.o将是复合对象ext2.o的一部分。 注意:当然,当你要将其编译进内核时,上面的语法同样适用。所以,如果你的CONFIG_EXT2_FS=y,那Kbuild会按你所期望的那样,生成ext2.o文件,然后将其联接到built-in.o中。 3.4.4目标库文件 - lib-y 在obj-*中所列文件是用来编译模块或者是联接到特定目录中的built-in.o。同样,也可以列出一些将被包含在lib.a库中的文件。在 lib-y 中所列出的文件用来组成该目录下的一个库文件。在obj-y与lib-y中同时列出的文件,因为都是可以访问的,所以该文件是不会被包含在库文件中的。同样的情况,lib-m中的文件就要包含在lib.a库文件中。 注意,一个Kbuild makefile可以同时列出要编译进内核的文件与要编译成库的文件。所以,在一个目录里可以同时存在built-in.o与lib.a两个文件。例如: 这将由 checksum.o 和delay.o 两个文件创建一个库文件 lib.a。为了让Kbuild真正认识到这里要有一个库文件lib.a要创建,其所在的目录要加到libs-y列表中。 3.4.5递归向下访问目录 一个Makefile只对编译所在目录的对象负责。在子目录中的文件的编译要由其所在的子目录的Makefile来管理。只要你让Kbuild知道它应该递归操作,那么该系统就会在其子目录中自动的调用 make 递归操作。 这就是obj-y和obj-m的作用。比如ext2被放的一个单独的目录下,在fs目录下的Makefile会告诉Kbuild使用下面的赋值进行向下递归操作。 如果 CONFIG_EXT2_FS 被设置为 'y'(编译进内核)或是'm'(编译成模块),相应的 obj- 变量就会被设置,并且Kbuild就会递归向下访问 ext2 目录。Kbuild只是用这些信息来决定它是否需要访问该目录,而具体怎么编译由该目录中的Makefile来决定。将 CONFIG_ 变量设置成目录名是一个好的编程习惯。这让Kbuild在完全忽略那些相应的CONFIG_ 值不是'y'和'm'的目录。 3.4.6编辑标志 编辑标记包括:EXTRA_CFLAGS,、EXTRA_AFLAGS、EXTRA_LDFLAGS、EXTRA_ARFLAG。所有的EXTRA_变量只在所定义的Kbuild Makefile中起作用。EXTRA_变量可以在Kbuild Makefile中所有命令中使用。 $(EXTRA_CFLAGS) 是用 $(CC) 编译C源文件时的选项。例如: 该变量是必须的,因为顶层Makefile拥有变量 $(CFLAGS) 并用来作为整个源代码树的编译选项。 $(EXTRA_AFLAGS) 也是一个针对每个目录的选项,只不过它是用来编译汇编源代码的。例如: $(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)分别与$(LD)和$(AR)类似,只不过它们是针对每个目录的。例如: CFLAGS_$@, AFLSGA_$@ CFLAGS_$@ 和 AFLAGS_$@ 只能在当前Kbuild Makefile中的命令中使用。 $(CFLAGS_$@) 是 $(CC) 针对每个文件的选项。$@ 表明了具体操作的文件。例如: 以上三行分别设置了aha152x.o,gdth.o 和 seagate.o的编辑选项。 $(AFLAGS_$@) 也类似,只不是是针对汇编语言的。例如: 3.4.7依赖跟踪 Kbuild 跟踪在以下方面依赖: 1) 所有要参与编译的文件(所有的.c 和.h文件) 2) 在参与编译文件中所要使用的 CONFIG_ 选项 3) 用于编译目标的命令行 因此,如果你改变了 $(CC) 的选项,所有受影响的文件都要重新编译。 3.4.8特殊规则 特殊规则就是那Kbuild架构不能提供所要求的支持时,所使用的规则。一个典型的例子就是在构建过程中生成的头文件。另一个例子就是那些需要采用特殊规则来准备启动镜像。 特殊规则的写法与普通Make规则一样。Kbuild并不在Makefile所在的目录执行,所以所有的特殊规则都要提供参与编译的文件和目标文件的相对路径。 在定义特殊规则时,要使用以下两个变量:$(src)和$(obj)。$(src) 表明Makefile所在目录的相对路径。经常在定位源代码树中的文件时,使用该变量。$(obj) 表明目标文件所要存储目录的相对路径。经常在定位所生成的文件时,使用该变量。例如: 这就是一个特殊规则,遵守着make所要求的普通语法。 4. 一个使用linux kbuild实现可配置编译的例子 我编写了一个使用Linux kbuild机制实现可配置编译的小例子,工程名为print-example。包括如下如下几个目录: 其中scripts、Makefile、Makefile.flags是从busybox-1.9.0复制过来的。 4.1 运行print 运行make menuconfig命令弹出配置菜单如下: 进入Print Configure选项选择配置项: 这里选择代印信息1和2,保存退出配置界面。 运行make命令编译程序,生成print可执行文件,运行print结果如下: 运行make clean编译产生文件。 4.2 实现print 4.2.1 主目录Makefile 主目录Makefile修改部分代码如下: 使用core-y时是使用的静态链接目标文件obj-y,使用libs-y时是使用库目标文件lib-y,各个子目录的Makefile应该相应的使用obj-y或lib-y。 4.2.2主目录Kconfig 主目录Kconfig代码如下: 它给出了主菜单的配置选项,并有source关键字加入子目录的Kconfig文件。 4.2.3 main文件夹 main文件夹下共两个文件: 其中,main.c代码如下: 头文件autoconf.h是在编译过程中生成的。 Makefile代码如下: 4.2.4 printfun文件夹 printfun文件夹下有六个文件: 其中,printx.c(print1.c, print2.c, print3.c, print4.c)代码如下: Makefile代码如下: Kconfig代码如下: 4.2.5 include目录 include目录下只有一个文件print.h,代码如下: 参考文献 【1】孙纪坤 配置编译内核 【2】linux kernel /Documentation/kbuild/kconfig-language.txt 【3】2.6Kconfig语法 【4】linux kernel /Documentation/kbuild/makefile.txt 【5】linux2.6内核Makefile详解 |
Linux Kbuild文档(转)的更多相关文章
- LINUX 内核文档地址
Linux的man很强大,该手册分成很多section,使用man时可以指定不同的section来浏览,各个section意义如下: 1 - commands2 - system calls3 - l ...
- Linux之文档与目录结构 目录的相关操作 Linux的文件系统
Linux之文档与目录结构 Linux文件系统结构 Linux目录结构的组织形式和Windows有很大的不同.首先Linux没有“盘(C盘.D盘.E盘)”的概念.已经建立文件系统的硬盘分区被挂载到 ...
- Linux之文档与目录结构 (/ 用法, 相对路径,绝对路径)
Linux之文档与目录结构 Linux文件系统结构 Linux目录结构的组织形式和Windows有很大的不同.首先Linux没有“盘(C盘.D盘.E盘)”的概念.已经建立文件系统的硬盘分区被挂载到 ...
- Linux 在文档中查找满足条件的行并输出到文件:
Linux 在文档中查找满足条件的行并输出到文件: 文件名称: dlog.log 输出文件: out.log 1.满足一个条件(包含 “TJ” )的语句: grep “TJ” dlog. ...
- 500 多个 Linux 命令文档搜索
500 多个 Linux 命令文档搜索 搜索界面:https://wangchujiang.com/linux-command/ 源码:https://github.com/jaywcjlove/li ...
- Linux内核官方文档atomic_ops.txt【摘自Linux 内核文档】
摘自Linux内核文档 Documentation/atomic_ops.txt,不是本人原创 Semantics and Behavior of Atomic and Bitmask Operati ...
- Linux--2 Linux之文档与目录结构、shell基本命令
一.Linux之文档与目录结构 1.Linux之文档与目录结构 Linux目录结构的组织形式和Windows有很大的不同.Linux没有“盘(如C盘.D盘.E盘)”的概念,而是建立一个根"/ ...
- Linux进阶文档丨阿里架构师十年Linux心得,全在这份文档里面
Linux是什么 Linux就是个操作系统: 它和Windows XP.Windows 7.Windows 10什么的一样就是一个操作系统而已! Linux能干什么: 它能当服务器,服务器上安装者各种 ...
- Where is the kernel documentation?; Ubuntu 上如何安装 linux 内核文档;fedora 上如何安装linux内核文档?
有时候,linux内核文档对我们很重要,我们可以在linux系统中安装,并及时查看: 参考链接:https://askubuntu.com/questions/841043/where-is-the- ...
随机推荐
- 如何使用离线存储(localStorage)?
1.存储数据:localStorage.setItem("属性","属性值") 2.获取本地存储的值:localStorage.getItem("属性 ...
- iptables 自定义链
当默认链中的规则非常多时,不方便我们管理. 想象一下,如果INPUT链中存放了200条规则,这200条规则有针对httpd服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,假如,我们突 ...
- 【技术博客】Django中文件下载的实现
开发组在开发过程中,都不可避免地遇到了一些困难或问题,但都最终想出办法克服了.我们认为这样的经验是有必要记录下来的,因此就有了[技术博客]. Django中文件下载的实现 1.背景 在VisualPy ...
- shell脚本监控阿里云专线网络状态,若不通通过触发阿里云的进程监控报警
#!/bin/bash while [ 1 ] do rtt=`ping -c 3 15.0.160.18 |grep rtt |awk '{print $4}' |awk -F'/' '{print ...
- CentOS忘记密码修改方案以及centos卡在开机登录界面,命令失效的解决方法
CentOS忘记密码修改方案 应用场景 linux管理员忘记root密码,需要进行找回操作. 注意事项:本文基于CentOS7.2环境进行操作的,由于CentOS的版本之间是有差异的,继续之前请先确定 ...
- Java核心技术 卷一(序言+0-5)
l 常见简写: JDK(Java Development Kit):Java开发工具包 API:应用程序编程接口 OOP(Object-Oriented Programming):面向对象程序设计 l ...
- JavaSE 面试题: 类初始化和实例初始化等
JavaSE 面试题 类初始化和实例初始化等 class Father { private int i = test(); private static int j = method(); stati ...
- Java 在 Word 文档中使用新文本替换指定文本
创作一份文案,经常会高频率地使用某些词汇,如地名.人名.人物职位等,若表述有误,就需要整体撤换.文本将介绍如何使用Spire.Doc for Java,在Java程序中对Word文档中的指定文本进行替 ...
- requests获取响应时间(elapsed)与超时(timeout)、小数四舍五入
前言 requests发请求时,接口的响应时间,也是我们需要关注的一个点,如果响应时间太长,也是不合理的.如果服务端没及时响应,也不能一直等着,可以设置一个timeout超时的时间 elapsed官方 ...
- LOJ2336 JOI2017 绳 贪心、构造
传送门 首先显然的是可以一开始先染好再做.每个点只会被染一次.最后只剩下两种颜色. 接下来是结论时间:序列可以反转的充要条件是除了首尾的极大颜色连通块以外其他极大颜色连通块长度为偶数. 证明充分性:考 ...