zoukankan      html  css  js  c++  java
  • Linux kernel config and makefile system

    转载自:http://blog.csdn.net/dreamxu/article/details/6125545

    http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-kerconf/
    上面这篇文章针对的系统相对较老点. 后来又找到了一篇新的文章:

    http://blog.csdn.net/estate66/archive/2010/09/15/5886816.aspx

     

    因为在2.6.36的内核中,已经没有config.in文件。取而代之的是Kconfig文件。所以说前面的文章较老,但对于整个内核的编译系统的把握非常有帮助。

     

    这里我先贴了第一篇文章。后面一篇在后面。
    2003 年 2 月

    随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展。越来越多的人開始投身到 Linux 内核级的开发中。面对日益庞大的 Linux 内核源码,开发人员在完毕自己的内核代码后,都将面临着相同的问题,即怎样将源码融入到 Linux 内核中,增加相应的 Linux 配置选项。并终于被编译进 Linux 内核。

    这就须要了解 Linux 的内核配置系统。

    众所周知。Linux 内核是由分布在全球的 Linux 爱好者共同开发的,Linux 内核每天都面临着很多新的变化。

    可是。Linux 内核的组织并没有出现混乱的现象,反而显得非常的简洁,并且具有非常好的扩展性,开发人员能够非常方便的向 Linux 内核中增加新的内容。原因之中的一个就是 Linux 採用了模块化的内核配置系统。从而保证了内核的扩展性。

    本文首先分析了 Linux 内核中的配置系统结构,然后,解释了 Makefile 和配置文件的格式以及配置语句的含义。最后。通过一个简单的样例--TEST Driver。详细说明怎样将自行开发的代码增加到 Linux 内核中。在下面的文章中,不可能解释全部的功能和命令,仅仅对那些经常使用的进行解释。至于那些没有讨论到的。请读者參考后面的參考文献。

    1. 配置系统的基本结构

    Linux内核的配置系统由三个部分组成,各自是:

    Makefile:分布在 Linux 内核源码中的 Makefile,定义 Linux 内核的编译规则。 
    配置文件(config.in):给用户提供配置选择的功能; 
    配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面。各自相应于 Make config、Make menuconfig 和 make xconfig)。
    这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包括一些用 C 编写的代码)。本文并非对配置系统本身进行分析。而是介绍怎样使用配置系统。

    所以,除非是配置系统的维护者,一般的内核开发人员无须了解它们的原理,仅仅须要知道怎样编写 Makefile 和配置文件就能够。所以,在本文中,我们仅仅对 Makefile 和配置文件进行讨论。另外,凡是涉及到与详细 CPU 体系结构相关的内容,我们都以 ARM 为例,这样不仅能够将讨论的问题明白化,并且对内容本身不产生影响。

    2. Makefile

    2.1 Makefile 概述

    Makefile 的作用是依据配置的情况,构造出须要编译的源文件列表。然后分别编译,并把目标代码链接到一起。终于形成 Linux 内核二进制文件。



    因为 Linux 内核源码是依照树形结构组织的,所以 Makefile 也被分布在文件夹树中。

    Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:

    Makefile:顶层 Makefile。是整个内核配置、编译的整体控制文件。 
    .config:内核配置文件,包括由用户选择的配置选项。用来存放内核配置后的结果(如 make config)。 
    arch/*/Makefile:位于各种 CPU 体系文件夹下的 Makefile,如 arch/arm/Makefile,是针对特定平台的 Makefile。 
    各个子文件夹下的 Makefile:比方 drivers/Makefile,负责所在子文件夹下源码的管理。 
    Rules.make:规则文件,被全部的 Makefile 使用。 
    用户通过 make config 配置后,产生了 .config。顶层 Makefile 读入 .config 中的配置选择。顶层 Makefile 有两个基本的任务:产生 vmlinux 文件和内核模块(module)。为了达到此目的,顶层 Makefile 递归的进入到内核的各个子文件夹中,分别调用位于这些子文件夹中的 Makefile。至于究竟进入哪些子文件夹,取决于内核的配置。在顶层 Makefile 中。有一句:include arch/$(ARCH)/Makefile,包括了特定 CPU 体系结构下的 Makefile,这个 Makefile 中包括了平台相关的信息。



    位于各个子文件夹下的 Makefile 相同也依据 .config 给出的配置信息,构造出当前配置下须要的源文件列表。并在文件的最后有 include $(TOPDIR)/Rules.make。

    Rules.make 文件起着非常关键的数据,它定义了全部 Makefile 共用的编译规则。比方。假设须要将本文件夹下全部的 c 程序编译成汇编代码,须要在 Makefile 中有下面的编译规则:

            %.s: %.c
            $(CC) $(CFLAGS) -S $< -o $@
            
    有非常多子文件夹下都有相同的要求,就须要在各自的 Makefile 中包括此编译规则。这会比較麻烦。而 Linux 内核中则把此类的编译规则统一放置到 Rules.make 中。并在各自的 Makefile 中包括进了 Rules.make(include Rules.make),这样就避免了在多个 Makefile 中反复相同的规则。

    对于上面的样例,在 Rules.make 中相应的规则为:

            %.s: %.c
            $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F)) $(CFLAGS_$@) -S $< -o $@
            
    2.2 Makefile 中的变量

    顶层 Makefile 定义并向环境中输出了很多变量。为各个子文件夹下的 Makefile 传递一些信息。有些变量。比方 SUBDIRS,不仅在顶层 Makefile 中定义并且赋初值,并且在 arch/*/Makefile 还作了扩充。



    经常使用的变量有下面几类:

    1) 版本号信息
    版本号信息有:VERSION,PATCHLEVEL, SUBLEVEL, EXTRAVERSION,KERNELRELEASE。版本号信息定义了当前内核的版本号。比方 VERSION=2。PATCHLEVEL=4,SUBLEVEL=18,EXATAVERSION=-rmk7。它们共同构成内核的发行版本号KERNELRELEASE:2.4.18-rmk7

    2) CPU 体系结构:ARCH
    在顶层 Makefile 的开头。用 ARCH 定义目标 CPU 的体系结构,比方 ARCH:=arm 等。很多子文件夹的 Makefile 中,要依据 ARCH 的定义选择编译源文件的列表。



    3) 路径信息:TOPDIR, SUBDIRS
    TOPDIR 定义了 Linux 内核源码所在的根文件夹。

    比如,各个子文件夹下的 Makefile 通过 $(TOPDIR)/Rules.make 就能够找到 Rules.make 的位置。
    SUBDIRS 定义了一个文件夹列表。在编译内核或模块时,顶层 Makefile 就是依据 SUBDIRS 来决定进入哪些子文件夹。

    SUBDIRS 的值取决于内核的配置,在顶层 Makefile 中 SUBDIRS 赋值为 kernel drivers mm fs net ipc lib;依据内核的配置情况,在 arch/*/Makefile 中扩充了 SUBDIRS 的值,參见4)中的样例。



    4) 内核组成信息:HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS
    Linux 内核文件 vmlinux 是由下面规则产生的:


    vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
    $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o /
    --start-group /
    $(CORE_FILES) /
    $(DRIVERS) /
    $(NETWORKS) /
    $(LIBS) /
    --end-group /
    -o vmlinux

    能够看出。vmlinux 是由 HEAD、main.o、version.o、CORE_FILES、DRIVERS、NETWORKS 和 LIBS 组成的。这些变量(如 HEAD)都是用来定义连接生成 vmlinux 的目标文件和库文件列表。

    当中。HEAD在arch/*/Makefile 中定义,用来确定被最先链接进 vmlinux 的文件列表。比方,对于 ARM 系列的 CPU,HEAD 定义为: 
    HEAD            := arch/arm/kernel/head-$(PROCESSOR).o /
                       arch/arm/kernel/init_task.o

    表明 head-$(PROCESSOR).o 和 init_task.o 须要最先被链接到 vmlinux 中。PROCESSOR 为 armv 或 armo,取决于目标 CPU。 CORE_FILES,NETWORK。DRIVERS 和 LIBS 在顶层 Makefile 中定义,并且由 arch/*/Makefile 依据须要进行扩充。 CORE_FILES 相应着内核的核心文件。有 kernel/kernel.o。mm/mm.o,fs/fs.o,ipc/ipc.o,能够看出,这些是组成内核最为关键的文件。同一时候。arch/arm/Makefile 对 CORE_FILES 进行了扩充:

    # arch/arm/Makefile

    # If we have a machine-specific directory, then include it in the build.
    MACHDIR         := arch/arm/mach-$(MACHINE)
    ifeq ($(MACHDIR),$(wildcard $(MACHDIR)))
    SUBDIRS         += $(MACHDIR)
    CORE_FILES      := $(MACHDIR)/$(MACHINE).o $(CORE_FILES)
    endif

    HEAD            := arch/arm/kernel/head-$(PROCESSOR).o /
                       arch/arm/kernel/init_task.o
    SUBDIRS         += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe
    CORE_FILES      := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
    LIBS            := arch/arm/lib/lib.a $(LIBS)


    5) 编译信息:CPP, CC, AS, LD, AR,CFLAGS,LINKFLAGS
    在 Rules.make 中定义的是编译的通用规则,详细到特定的场合。须要明白给出编译环境,编译环境就是在以上的变量中定义的。针对交叉编译的要求。定义了 CROSS_COMPILE。

    比方:


    CROSS_COMPILE   = arm-linux-
    CC              = $(CROSS_COMPILE)gcc
    LD              = $(CROSS_COMPILE)ld
    ......

    CROSS_COMPILE 定义了交叉编译器前缀 arm-linux-,表明全部的交叉编译工具都是以 arm-linux- 开头的,所以在各个交叉编译器工具之前,都增加了 $(CROSS_COMPILE),以组成一个完整的交叉编译工具文件名称,比方 arm-linux-gcc。


    CFLAGS 定义了传递给 C 编译器的參数。


    LINKFLAGS 是链接生成 vmlinux 时,由链接器使用的參数。LINKFLAGS 在 arm/*/Makefile 中定义。比方:

    # arch/arm/Makefile

    LINKFLAGS       :=-p -X -T arch/arm/vmlinux.lds


    6) 配置变量CONFIG_*
    .config 文件里有很多的配置变量等式,用来说明用户配置的结果。

    比如 CONFIG_MODULES=y 表明用户选择了 Linux 内核的模块功能。
    .config 被顶层 Makefile 包括后,就形成很多的配置变量,每一个配置变量具有确定的值:y 表示本编译选项相应的内核代码被静态编译进 Linux 内核;m 表示本编译选项相应的内核代码被编译成模块。n 表示不选择此编译选项;假设根本就没有选择。那么配置变量的值为空。

    2.3 Rules.make 变量

    前面讲过,Rules.make 是编译规则文件。全部的 Makefile 中都会包括 Rules.make。Rules.make 文件定义了很多变量,最为重要是那些编译、链接列表变量。

    O_OBJS,L_OBJS,OX_OBJS。LX_OBJS:本文件夹下须要编译进 Linux 内核 vmlinux 的目标文件列表,当中 OX_OBJS 和 LX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。



    M_OBJS。MX_OBJS:本文件夹下须要被编译成可装载模块的目标文件列表。相同,MX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。

    O_TARGET,L_TARGET:每一个子文件夹下都有一个 O_TARGET 或 L_TARGET,Rules.make 首先从源码编译生成 O_OBJS 和 OX_OBJS 中全部的目标文件。然后使用 $(LD) -r 把它们链接成一个 O_TARGET 或 L_TARGET。O_TARGET 以 .o 结尾,而 L_TARGET 以 .a 结尾。



    2.4 子文件夹 Makefile

    子文件夹 Makefile 用来控制本级文件夹下面源码的编译规则。我们通过一个样例来解说子文件夹 Makefile 的组成:

    #
    # Makefile for the linux kernel.
    #
    # All of the (potential) objects that export symbols.
    # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.

    export-objs := tc.o

    # Object file lists.

    obj-y :=
    obj-m :=
    obj-n :=
    obj- :=

    obj-$(CONFIG_TC) += tc.o
    obj-$(CONFIG_ZS) += zs.o
    obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o

    # Files that are both resident and modular: remove from modular.

    obj-m := $(filter-out $(obj-y), $(obj-m))

    # Translate to Rules.make lists.

    L_TARGET := tc.a

    L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
    LX_OBJS := $(sort $(filter     $(export-objs), $(obj-y)))
    M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
    MX_OBJS := $(sort $(filter     $(export-objs), $(obj-m)))

    include $(TOPDIR)/Rules.make

    a) 凝视
    对 Makefile 的说明和解释,由#開始。



    b) 编译目标定义
    相似于 obj-$(CONFIG_TC) += tc.o 的语句是用来定义编译的目标,是子文件夹 Makefile 中最重要的部分。编译目标定义那些在本子文件夹下。须要编译到 Linux 内核中的目标文件列表。为了仅仅在用户选择了此功能后才编译。全部的目标定义都融合了对配置变量的推断。
    前面说过,每一个配置变量取值范围是:y,n,m 和空。obj-$(CONFIG_TC) 分别相应着 obj-y,obj-n,obj-m。obj-。假设 CONFIG_TC 配置为 y。那么 tc.o 就进入了 obj-y 列表。

    obj-y 为包括到 Linux 内核 vmlinux 中的目标文件列表;obj-m 为编译成模块的目标文件列表;obj-n 和 obj- 中的文件列表被忽略。配置系统就依据这些列表的属性进行编译和链接。
    export-objs 中的目标文件都使用了 EXPORT_SYMBOL() 定义了公共的符号。以便可装载模块使用。

    在 tc.c 文件的最后部分。有 "EXPORT_SYMBOL(search_tc_card);",表明 tc.o 有符号输出。
    这里须要指出的是,对于编译目标的定义。存在着两种格式,各自是老式定义和新式定义。

    老式定义就是前面 Rules.make 使用的那些变量,新式定义就是 obj-y,obj-m。obj-n 和 obj-。Linux 内核推荐使用新式定义,只是因为 Rules.make 不理解新式定义,须要在 Makefile 中的适配段将其转换成老式定义。

    c) 适配段
    适配段的作用是将新式定义转换成老式定义。在上面的样例中,适配段就是将 obj-y 和 obj-m 转换成 Rules.make 能够理解的 L_TARGET。L_OBJS,LX_OBJS,M_OBJS,MX_OBJS。
    L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) 定义了 L_OBJS 的生成方式:在 obj-y 的列表中过滤掉 export-objs(tc.o)。然后排序并去除反复的文件名称。这里使用到了 GNU Make 的一些特殊功能,详细的含义可參考 Make 的文档(info make)。

    d) include $(TOPDIR)/Rules.make

    3. 配置文件

    3.1 配置功能概述

    除了 Makefile 的编写。另外一个重要的工作就是把新功能增加到 Linux 的配置选项中,提供此项功能的说明,让用户有机会选择此项功能。

    全部的这些都须要在 config.in 文件里用配置语言来编写配置脚本。 
    在 Linux 内核中。配置命令有多种方式:

    配置命令 解释脚本 
    Make config, make oldconfig scripts/Configure 
    Make menuconfig scripts/Menuconfig 
    Make xconfig scripts/tkparse 

    以字符界面配置(make config)为例,顶层 Makefile 调用 scripts/Configure, 依照 arch/arm/config.in 来进行配置。命令执行完后产生文件 .config,当中保存着配置信息。

    下一次再做 make config 将产生新的 .config 文件,原 .config 被改名为 .config.old

    3.2 配置语言

    1) 顶层菜单
    mainmenu_name /prompt/ /prompt/ 是用'或"包围的字符串,'与"的差别是'…'中可使用$引用变量的值。

    mainmenu_name 设置最高层菜单的名字,它仅仅在 make xconfig 时才会显示。

    2) 询问语句 

        bool            /prompt/ /symbol/
            hex             /prompt/ /symbol/ /word/
            int             /prompt/ /symbol/ /word/
            string          /prompt/ /symbol/ /word/
            tristate        /prompt/ /symbol/

    询问语句首先显示一串提示符 /prompt/,等待用户输入。并把输入的结果赋给 /symbol/ 所代表的配置变量。不同的询问语句的差别在于它们接受的输入数据类型不同。比方 bool 接受布尔类型( y 或 n ),hex 接受 16 进制数据。

    有些询问语句还有第三个參数 /word/。用来给出缺省值。

    3) 定义语句 

            define_bool     /symbol/ /word/
            define_hex      /symbol/ /word/
            define_int      /symbol/ /word/
            define_string   /symbol/ /word/
            define_tristate /symbol/ /word/

    不同于询问语句等待用户输入。定义语句显式的给配置变量 /symbol/ 赋值 /word/。

    4) 依赖语句 

            dep_bool        /prompt/ /symbol/ /dep/ ...
            dep_mbool       /prompt/ /symbol/ /dep/ ...
            dep_hex         /prompt/ /symbol/ /word/ /dep/ ...
            dep_int         /prompt/ /symbol/ /word/ /dep/ ...
            dep_string      /prompt/ /symbol/ /word/ /dep/ ...
            dep_tristate    /prompt/ /symbol/ /dep/ ...

    与询问语句相似,依赖语句也是定义新的配置变量。

    不同的是,配置变量/symbol/的取值范围将依赖于配置变量列表/dep/ …。这就意味着:被定义的配置变量所相应功能的取舍取决于依赖列表所相应功能的选择。以dep_bool为例,假设/dep/ …列表的全部配置变量都取值y,则显示/prompt/。用户可输入随意的值给配置变量/symbol/,可是仅仅要有一个配置变量的取值为n,则/symbol/被强制成n。


    不同依赖语句的差别在于它们由依赖条件所产生的取值范围不同。

    5) 选择语句


    choice          /prompt/ /word/ /word/

    choice 语句首先给出一串选择列表。供用户选择当中一种。比方 Linux for ARM 支持多种基于 ARM core 的 CPU,Linux 使用 choice 语句提供一个 CPU 列表,供用户选择:

             choice 'ARM system type' /
            "Anakin                 CONFIG_ARCH_ANAKIN /
             Archimedes/A5000       CONFIG_ARCH_ARCA5K /
             Cirrus-CL-PS7500FE     CONFIG_ARCH_CLPS7500 /
    ……
             SA1100-based           CONFIG_ARCH_SA1100 /
             Shark                  CONFIG_ARCH_SHARK" RiscPC
             
    Choice 首先显示 /prompt/,然后将 /word/ 分解成前后两个部分,前部分为相应选择的提示符,后部分是相应选择的配置变量。用户选择的配置变量为 y,其余的都为 n。



    6) if语句


            if [ /expr/ ] ; then
              /statement/ 
              ...
            fi
            
            if [ /expr/ ] ; then
              /statement/
              ...
            else
              /statement/
              ...
            fi
            
    if 语句对配置变量(或配置变量的组合)进行推断,并作出不同的处理。推断条件 /expr/ 能够是单个配置变量或字符串,也能够是带操作符的表达式。操作符有:=,!=,-o,-a 等。



    7) 菜单块(menu block)语句 

    mainmenu_option next_comment
    comment '…..'

    endmenu

    引入新的菜单。在向内核增加新的功能后,须要相应的增加新的菜单,并在新菜单下给出此项功能的配置选项。

    Comment 后带的凝视就是新菜单的名称。全部归属于此菜单的配置选项语句都写在 comment 和 endmenu 之间。



    8) Source 语句
    source /word/
    /word/ 是文件名称,source 的作用是调入新的文件。

    3.3 缺省配置

    Linux 内核支持非常多的硬件平台,对于详细的硬件平台而言,有些配置就是必需的,有些配置就没必要的。

    另外,新增加功能的正常执行往往也须要一定的先决条件。针对新功能,必须作相应的配置。因此,特定硬件平台能够正常执行相应着一个最小的基本配置,这就是缺省配置。

    Linux 内核中针对每一个 ARCH 都会有一个缺省配置。

    在向内核代码增加了新的功能后,假设新功能对于这个 ARCH 是必需的,就要改动此 ARCH 的缺省配置。改动方法例如以下(在 Linux 内核根文件夹下):

    备份 .config 文件 
    cp arch/arm/deconfig .config 
    改动 .config 
    cp .config arch/arm/deconfig 
    恢复 .config 
    假设新增的功能适用于很多的 ARCH,仅仅要针对详细的 ARCH,反复上面的步骤就能够了。



    3.4 help file

    大家都有这种经验,在配置 Linux 内核时,遇到不懂含义的配置选项,能够查看它的帮助。从中可得到选择的建议。下面我们就看看怎样给给一个配置选项增加帮助信息。

    全部配置选项的帮助信息都在 Documentation/Configure.help 中,它的格式为:

    <description>
    <variable name>
    <help file>

    <description> 给出本配置选项的名称。<variable name> 相应配置变量。<help file> 相应配置帮助信息。在帮助信息中,首先简单描写叙述此功能。其次说明选择了此功能后会有什么效果,不选择又有什么效果。最后,不要忘了写上"假设不清楚,选择 N(或者)Y",给不知所措的用户以提示。

    4. 实例

    对于一个开发人员来说,将自己开发的内核代码增加到 Linux 内核中,须要有三个步骤。

    首先确定把自己开发代码放入到内核的位置;其次,把自己开发的功能增加到 Linux 内核的配置选项中,使用户能够选择此功能;最后,构建子文件夹 Makefile,依据用户的选择。将相应的代码编译到终于生成的 Linux 内核中去。下面,我们就通过一个简单的样例--test driver,结合前面学到的知识,来说明怎样向 Linux 内核中增加新的功能。

    4.1 文件夹结构

    test driver 放置在 drivers/test/ 文件夹下:

    $cd drivers/test
    $tree
    .
    |-- Config.in
    |-- Makefile
    |-- cpu
    |   |-- Makefile
    |   `-- cpu.c
    |-- test.c
    |-- test_client.c
    |-- test_ioctl.c
    |-- test_proc.c
    |-- test_queue.c
    `-- test
        |-- Makefile
        `-- test.c
        
    4.2 配置文件

    1) drivers/test/Config.in 

    #
    # TEST driver configuration
    #
    mainmenu_option next_comment
    comment 'TEST Driver'

    bool 'TEST support' CONFIG_TEST
    if [ "$CONFIG_TEST" = "y" ]; then
      tristate 'TEST user-space interface' CONFIG_TEST_USER
      bool 'TEST CPU ' CONFIG_TEST_CPU
    fi

    endmenu

    因为 test driver 对于内核来说是新的功能,所以首先创建一个菜单 TEST Driver。

    然后。显示 "TEST support",等待用户选择;接下来推断用户是否选择了 TEST Driver。假设是(CONFIG_TEST=y)。则进一步显示子功能:用户接口与 CPU 功能支持;因为用户接口功能能够被编译成内核模块,所以这里的询问语句使用了 tristate(因为 tristate 的取值范围包括 y、n 和 m。m 就是相应着模块)。

    2) arch/arm/config.in
    在文件的最后增加:source drivers/test/Config.in,将 TEST Driver 子功能的配置纳入到 Linux 内核的配置中。

    4.3 Makefile

    1)drivers/test/Makefile


    #       drivers/test/Makefile
    #
    #       Makefile for the TEST.
    #

    SUB_DIRS     :=
    MOD_SUB_DIRS := $(SUB_DIRS)
    ALL_SUB_DIRS := $(SUB_DIRS) cpu

    L_TARGET := test.a
    export-objs := test.o test_client.o

    obj-$(CONFIG_TEST)              += test.o test_queue.o test_client.o
    obj-$(CONFIG_TEST_USER)         += test_ioctl.o
    obj-$(CONFIG_PROC_FS)           += test_proc.o

    subdir-$(CONFIG_TEST_CPU)       += cpu

    include $(TOPDIR)/Rules.make

    clean:
            for dir in $(ALL_SUB_DIRS); do make -C $$dir clean; done
            rm -f *.[oa] .*.flags
            
    drivers/test 文件夹下终于生成的目标文件是 test.a。在 test.c 和 test-client.c 中使用了 EXPORT_SYMBOL 输出符号,所以 test.o 和 test-client.o 位于 export-objs 列表中。然后,依据用户的选择(详细来说,就是配置变量的取值),构建各自相应的 obj-* 列表。因为 TEST Driver 中包一个子文件夹 cpu。当 CONFIG_TEST_CPU=y(即用户选择了此功能)时,须要将 cpu 文件夹增加到 subdir-y 列表中。

    2)drivers/test/cpu/Makefile 

    #       drivers/test/test/Makefile
    #
    #       Makefile for the TEST CPU 
    #

    SUB_DIRS     :=
    MOD_SUB_DIRS := $(SUB_DIRS)
    ALL_SUB_DIRS := $(SUB_DIRS)

    L_TARGET := test_cpu.a

    obj-$(CONFIG_test_CPU)       += cpu.o


    include $(TOPDIR)/Rules.make

    clean:
            rm -f *.[oa] .*.flags
            

    3)drivers/Makefile 

    ……
    subdir-$(CONFIG_TEST) += test
    ……
    include $(TOPDIR)/Rules.make

    在 drivers/Makefile 中增加 subdir-$(CONFIG_TEST)+= test。使得在用户选择 TEST Driver 功能后,内核编译时能够进入 test 文件夹。



    4)Makefile 

    ……
    DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o
    DRIVERS-$(CONFIG_TEST) += drivers/test/test.a
    DRIVERS-$(CONFIG_TEST_CPU) += drivers/test/cpu/test_cpu.a

    DRIVERS := $(DRIVERS-y)
    ……

    在顶层 Makefile 中增加 DRIVERS-$(CONFIG_TEST) += drivers/test/test.a 和 DRIVERS-$(CONFIG_TEST_CPU) += drivers/test/cpu/test_cpu.a。

    怎样用户选择了 TEST Driver,那么 CONFIG_TEST 和 CONFIG_TEST_CPU 都是 y,test.a 和 test_cpu.a 就都位于 DRIVERS-y 列表中,然后又被放置在 DRIVERS 列表中。

    在前面以前提到过。Linux 内核文件 vmlinux 的组成中包括 DRIVERS,所以 test.a 和 test_cpu.a 终于可被链接到 vmlinux 中。

    5. 參考

    Document/kbuild/makefiles.txt,Linux Kernel Source code 
    Document/kbuild/config-language.txt,Linux Kernel Source code 
    Contributing to the Linux Kernel--The Linux Configuration System。Linux Journal,http://www.linuxjournal.com/categories.php?op=newindex&catid=178 
    Unreliable Guide To Hacking The Linux Kernel,Paul Rusty Russell。rusty@rustcorp.com.au 

     

     

     

     

    当我们编写完一个驱动后,我们要把它以模块形式编译或者直接编译

    进内核时,须要改动相关文件。当中最重要的便是kconfig ,makefile。

    主要是分析一下三者之间的关系。然后就其语法简要的谈一下。

         当我们在内核源码文件夹下执行make (或者make menuconfig等

    命令)命令时。实际上是依据makefile 来进行编译的。

    我在mini2440

    开发板上编写了一个按键控制led灯的驱动。文件名称为buttons_leds_z

    hao.c属于字符驱动。因此在/driver/char/文件夹下的makefile部分最

    后增加一行

    obj-$(CONFIG_BUTTONS_LEDS_ZHAO)      +=

    buttons_leds_zhao.o

    例如以下:

    obj-y    += mem.o random.o tty_io.o n_tty.o tty_ioctl.o

    tty_ldisc.o tty_buffer.o tty_port.o


    obj-$(CONFIG_BFIN_JTAG_COMM)    += bfin_jtag_comm.o


    obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o

    consolemap_deftbl.o


    obj-$(CONFIG_HW_CONSOLE)        += vt.o defkeymap.o


    obj-$(CONFIG_AUDIT)             += tty_audit.o

    obj-$(CONFIG_BUTTONS_LEDS_ZHAO)      +=

    buttons_leds_zhao.o

    当中第一行obj-y  中的y表示编译进内核,而obj-$(CONFIG_LEGAC

    Y_PTYS)  中CONFIG_LEGACY_PTYS则表示一个变量。相似于我们C

    语言中的变量。用$( )来表示,它一般能够取三种值y ,m ,n.y表示

    编译进内核。而m则表示以模块的方式进行编译,n表示不编译进内

    核。

    obj-y    += 等号后面的.o后缀文件则是由该文件夹下的相应名称的

    .c文件编译而来。


    而上面CONFIG_LEGACY_PTYS变量的取值则是通过.config文件来集

    中赋值的。.config部分内容例如以下

    # Character devices 

    CONFIG_VT=y


    CONFIG_CONSOLE_TRANSLATIONS=y


    CONFIG_VT_CONSOLE=y


    CONFIG_HW_CONSOLE=y

      
    # CONFIG_VT_HW_CONSOLE_BINDING is not set

      
    # CONFIG_DEVKMEM is not set


    CONFIG_MINI2440_HELLO_MODULE=m


    CONFIG_BUTTONS_LEDS_ZHAO=m


    CONFIG_LEDS_MINI2440=m


    CONFIG_MINI2440_BUTTONS=m


    CONFIG_MINI2440_BUZZER=y


    CONFIG_MINI2440_ADC=y


    # CONFIG_SERIAL_NONSTANDARD is not set


         从上面几行我们能够看到。在makefile里面的变量都是在.config中

    赋值的。当我们在源码文件夹下输入make命令时,都是默认从.config

    中读入。

         因此。在输入make之前,用ls  -a 查看一下是否有该文件。

    对于

    仅仅包括几个文件的project来说。手动写.config和makefile并非一件非常难

    的事情。但假设是一个包括有几百个文件的项目来说,则是一件比較困

    难的事情。

    能够用autoconf来自己主动生成.config,automake来制作

    makefile。看起来问题是解决的,但实际上,这种做法缺乏一定的灵活

    性。不能实现按需定制的要求。假设要增加或删掉某个驱动。将要在

    .config文件里找到相应的项进行改动。

    非常的不方便。因此,便出现了

    kconfig。

    当我们在内核源码文件夹下输入make menuconfig时,出现例如以下内容:

    .config - Linux Kernel v2.6.32.2 Configuration 
    ──────────────────────────────────────────────────────────────────────────────────────────────────
    ┌──────────────────────────────── Linux Kernel Configuration ─────────────────────────────────┐ 
    │  Arrow keys navigate the menu.  <Enter> selects submenus --->.  Highlighted letters are     │ 
    │  hotkeys.  Pressing <Y> includes, <N> excludes, <M> modularizes features.  Press <Esc><Esc> │ 
    │  to exit, <?

    > for Help, </> for Search.  Legend: [*] built-in  [ ] excluded  <M> module     │ 
    │  < > module capable                                                                         │ 
    │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ 
    │ │             General setup  --->                                                         │ │ 
    │ │         [*] Enable loadable module support  --->                                        │ │ 
    │ │         -*- Enable the block layer  --->                                                │ │ 
    │ │             System Type  --->                                                           │ │ 
    │ │             Bus support  --->                                                           │ │ 
    │ │             Kernel Features  --->                                                       │ │ 
    │ │             Boot options  --->                                                          │ │ 
    │ │             CPU Power Management  --->                                                  │ │ 
    │ │             Floating point emulation  --->                                              │ │ 
    │ │             Userspace binary formats  --->                                              │ │ 
    │ │             Power management options  --->                                              │ │ 
    │ │         [*] Networking support  --->                                                    │ │ 
    │ │             Device Drivers  --->                                                        │ │ 
    │ │             File systems  --->                                                          │ │ 
    │ └─────────┴(+)────────────────────────────────────────────────────────────────────────────┘ │ 
    ├─────────────────────────────────────────────────────────────────────────────────────────────┤
    │                              <Select>    < Exit >    < Help >                               │ 
    └─────────────────────────────────────────────────────────────────────────────────────────────┘

                  它是通过读取在内核源码文件夹下的Kconfig文件来配置的。

    在/drivers/char/下的文件夹kconfig部分内容例如以下:

    config DEVKMEM 
            bool "/dev/kmem virtual device support" 
            default y 
            help 
              Say Y here if you want to support the /dev/kmem device. The 
              /dev/kmem device is rarely used, but can be used for certain 
              kind of kernel debugging operations. 
              When in doubt, say "N".

    config MINI2440_HELLO_MODULE 
            tristate "Mini2440 module sample" 
            depends on MACH_MINI2440 
            default m if MACH_MINI2440 
            help 
              Mini2440 module sample.

    config BUTTONS_LEDS_ZHAO 
            tristate "Mini2440 button  and leds sample" 
            depends on MACH_MINI2440 
            default m if MACH_MINI2440 
            help 
              Mini2440  button and leds  module sample.


    其详细语法格式说明例如以下:

    configkeyword是一个新的配置选项的入口     其后的选项MINI2440_H

    ELLO_MODULE省略了CONFIG。完整的表示为CONFIG_MINI2440

    _HELLO_MODULE,也即是当我们将该选项设置成y时。它将自己主动的将

    .config的CONFIG_MINI2440_HELLO_MODULE=m改写成

    CONFIG_MINI2440_HELLO_MODULE=y。


    紧接着的是菜单的属性 最基本的有2种tristate ,boolean 。

    tristate表

    示三态:编译进内核(y),编译成模块(m)。不编译(n)。boolean 主

    要有两种y或ndepend则表示依赖项  default缺省的编译选项 m表示默

    认该文件表示以模块方式编译。后面的help是帮助信息,当我们选中

    help菜单时就能够看见,它没必要的。随着操作系统升级,编译选项

    达到几千个。对于一般人来说,要搞清每一个选项是非常困难的,一般非常

    多选项都是默认的。

            总的来说。三者之间的关系例如以下:当我们在内核源码文件夹下输入

    makemenuconfig时,在出现的菜单界面中选择一项时。它会自己主动跟新

    .config相应项的值。假设我们没有选择。则会在.config问下插入一行

    凝视。相似于# CONFIG_SERIAL_NONSTANDARD is not set,当

    我们输入make时。依据makefile文件来编译,makefile文件里的变量

    值则由.config来进行赋值操作。

    仅仅仅仅在kconfig中增加选项,仅仅会在

    菜单界面中显示,即使此时选择y或m。也不会编译文件。还须要在

    makefile文件里依照规定增加相应行才干进行编译。

    简单图解例如以下:

               

    kconfig------->.config---------->makefile



查看全文
  • 相关阅读:
    Some notes in Stanford CS106A(4)
    Some notes in Stanford CS106A(3)
    Some notes in Stanford CS106A(2)
    Some notes in Stanford CS106A(1)
    将前台页面的数据传到后台的方法(不调用ajax,少量数据)
    12、(扩展)获取省份表,填充于下拉列表框的简易js
    iframe刷新问题
    MVC基础
    DataList
    序列化
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10564778.html
  • Copyright © 2011-2022 走看看