精华内容
下载资源
问答
  • 如果用户在安装Linux时,安装了内核的源代码,则会发现一个linux-x.y.z的子目录。该目录下存放着内核x.y.z的源代码。此外,还会发现一个指向该目录的链接linux。删除该连接,然后将新内核的源文件拷贝到/usr/src目录...

    一.获取内核源码

    二.解压内核源码

    首先以root帐号登录,然后进入/usr/src子目录。如果用户在安装Linux时,安装了内核的源代码,则会发现一个linux-x.y.z的子目录。该目录下存放着内核x.y.z的源代码。此外,还会发现一个指向该目录的链接linux。删除该连接,然后将新内核的源文件拷贝到/usr/src目录中,并解压:

    # tar zxvf Linux-2.3.14.tar.gz

    文件释放成功后,在/usr/src目录下会生成一个linux子目录。其中包含了内核2.3.14的全部源代码。 将/usr/include/asm、/usr/inlude/linux、/usr/include/scsi链接到/usr/src/linux/include目录下的对应目录中。

    # cd /usr/include

    # rm -Rf asm linux

    # ln -s /usr/src/linux/include/asm-i386 asm

    # ln -s /usr/src/linux/include/linux linux

    # ln -s /usr/src/linux/include/scsi scsi

    删除源代码目录中残留的.o文件和其它从属文件。

    # cd /usr/src/linux

    # make mrproper

    三.增量补丁

    有时不需要完全重新安装,只需打增量补丁,类似升级,在内核源码树根目录运行:

    patch-p1< ../patch-x.y.z

    四.内核源码树目录:

    arch:包含和硬件体系结构相关的代码,每种平台占一个相应的目录。和32位PC相关的代码存放在i386目录下,其中比较重要的包括kernel(内核核心部分)、mm(内存管理)、math-emu(浮点单元仿真)、lib(硬件相关工具函数)、boot(引导程序)、pci(PCI总线)和power(CPU相关状态)。

    block:部分块设备驱动程序。

    crypto:常用加密和散列算法(如AES、SHA等),还有一些压缩和CRC校验算法。

    Documentation:关于内核各部分的通用解释和注释。

    drivers:设备驱动程序,每个不同的驱动占用一个子目录。

    fs:各种支持的文件系统,如ext、fat、ntfs等。

    include:头文件。其中,和系统相关的头文件被放置在linux子目录下。

    init:内核初始化代码(注意不是系统引导代码)。

    ipc:进程间通信的代码。

    kernel:内核的最核心部分,包括进程调度、定时器等,和平台相关的一部分代码放在arch/*/kernel目录下。

    lib:库文件代码。

    mm:内存管理代码,和平台相关的一部分代码放在arch/*/mm目录下。

    net:网络相关代码,实现了各种常见的网络协议。

    scripts:用于配置内核文件的脚本文件。

    security:主要是一个SELinux的模块。

    sound:常用音频设备的驱动程序等。

    usr:实现了一个cpio。

    在i386体系下,系统引导将从arch/i386/kernel/head.s开始执行,并进而转移到init/main.c中的main()函数初始化内核。

    五.配置内核

    # cd /usr/src/linux

    内核配置方法有三种:

    (1)命令行: make config

    (2)菜单模式的配置界面: make menuconfig

    (3) X window:make xconfig

    Linux的内核配置程序提供了一系列配置选项。对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。由于内核的配置选项非常多,本文只介绍一些比较重要的选项。

    1、Code maturity level options(代码成熟度选项)

    Prompt for development and/or incomplete code/drivers (CONFIG_EXPERIMENTAL) [N/y/?] 如果用户想要使用还处于测试阶段的代码或驱动,可以选择“y”。如果想编译出一个稳定的内核,则要选择“n”。

    2、Processor type and features(处理器类型和特色)

    (1)、Processor family (386, 486/Cx486, 586/K5/5x86/6x86, Pentium/K6/TSC, PPro/6x86MX) [PPro/6x86MX] 选择处理器类型,缺省为Ppro/6x86MX。

    (2)、Maximum Physical Memory (1GB, 2GB) [1GB] 内核支持的最大内存数,缺省为1G。

    (3)、Math emulation (CONFIG_MATH_EMULATION) [N/y/?] 协处理器仿真,缺省为不仿真。

    (4)、MTRR (Memory Type Range Register) support (CONFIG_MTRR) [N/y/?]

    选择该选项,系统将生成/proc/mtrr文件对MTRR进行管理,供X server使用。

    (5)、Symmetric multi-processing support (CONFIG_SMP) [Y/n/?] 选择“y”,内核将支持对称多处理器。

    3、 Loadable module support(可加载模块支持)

    (1)、Enable loadable module support (CONFIG_MODULES) [Y/n/?] 选择“y”,内核将支持加载模块。

    (2)、Kernel module loader (CONFIG_KMOD) [N/y/?] 选择“y”,内核将自动加载那些可加载模块,否则需要用户手工加载。

    4、 General setup(一般设置)

    (1)、Networking support (CONFIG_NET) [Y/n/?] 该选项设置是否在内核中提供网络支持。

    (2)、PCI support (CONFIG_PCI) [Y/n/?] 该选项设置是否在内核中提供PCI支持。

    (3)、PCI access mode (BIOS, Direct, Any) [Any] 该选项设置Linux探测PCI设备的方式。选择“BIOS”,Linux将使用BIOS;选择“Direct”,Linux将不通过BIOS;选择 “Any”,Linux将直接探测PCI设备,如果失败,再使用BIOS。

    (4)Parallel port support (CONFIG_PARPORT) [N/y/m/?] 选择“y”,内核将支持平行口。

    5、 Plug and Play configuration(即插即用设备支持)

    (1)、Plug and Play support (CONFIG_PNP) [Y/m/n/?] 选择“y”,内核将自动配置即插即用设备。

    (2)、ISA Plug and Play support (CONFIG_ISAPNP) [Y/m/n/?] 选择“y”,内核将自动配置基于ISA总线的即插即用设备。

    6、 Block devices(块设备)

    (1)、Normal PC floppy disk support (CONFIG_BLK_DEV_FD) [Y/m/n/?] 选择“y”,内核将提供对软盘的支持。

    (2)、Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support (CONFIG_BLK_DEV_IDE) [Y/m/n/?] 选择“y”,内核将提供对增强IDE硬盘、CDROM和磁带机的支持。

    7、 Networking options(网络选项)

    (1)、Packet socket (CONFIG_PACKET) [Y/m/n/?] 选择“y”,一些应用程序将使用Packet协议直接同网络设备通讯,而不通过内核中的其它中介协议。

    (2)、Network firewalls (CONFIG_FIREWALL) [N/y/?] 选择“y”,内核将支持防火墙。

    (3)、TCP/IP networking (CONFIG_INET) [Y/n/?] 选择“y”,内核将支持TCP/IP协议。

    (4)The IPX protocol (CONFIG_IPX) [N/y/m/?] 选择“y”,内核将支持IPX协议。

    (5)、Appletalk DDP (CONFIG_ATALK) [N/y/m/?] 选择“y”,内核将支持Appletalk DDP协议。

    8、SCSI support(SCSI支持)

    如果用户要使用SCSI设备,可配置相应选项。

    9、Network device support(网络设备支持)

    Network device support (CONFIG_NETDEVICES) [Y/n/?] 选择“y”,内核将提供对网络驱动程序的支持。

    10、Ethernet (10 or 100Mbit)(10M或100M以太网)

    在该项设置中,系统提供了许多网卡驱动程序,用户只要选择自己的网卡驱动就可以了。此外,用户还可以根据需要,在内核中加入对FDDI、PPP、SLIP和无线LAN(Wireless LAN)的支持。

    11、Character devices(字符设备)

    (1)、Virtual terminal (CONFIG_VT) [Y/n/?] 选择“y”,内核将支持虚拟终端。

    (2)、Support for console on virtual terminal (CONFIG_VT_CONSOLE) [Y/n/?]

    选择“y”,内核可将一个虚拟终端用作系统控制台。

    (3)、Standard/generic (dumb) serial support (CONFIG_SERIAL) [Y/m/n/?]

    选择“y”,内核将支持串行口。

    (4)、Support for console on serial port (CONFIG_SERIAL_CONSOLE) [N/y/?]

    选择“y”,内核可将一个串行口用作系统控制台。

    12、Mice(鼠标)

    PS/2 mouse (aka "auxiliary device") support (CONFIG_PSMOUSE) [Y/n/?] 如果用户使用的是PS/2鼠标,则该选项应该选择“y”。

    13、Filesystems(文件系统)

    (1)、Quota support (CONFIG_QUOTA) [N/y/?] 选择“y”,内核将支持磁盘限额。

    (2)、Kernel automounter support (CONFIG_AUTOFS_FS) [Y/m/n/?] 选择“y”,内核将提供对automounter的支持,使系统在启动时自动 mount远程文件系统。

    (3)、DOS FAT fs support (CONFIG_FAT_FS) [N/y/m/?] 选择“y”,内核将支持DOS FAT文件系统。

    (4)、ISO 9660 CDROM filesystem support (CONFIG_ISO9660_FS) [Y/m/n/?]

    选择“y”,内核将支持ISO 9660 CDROM文件系统。

    (5)、NTFS filesystem support (read only) (CONFIG_NTFS_FS) [N/y/m/?]

    选择“y”,用户就可以以只读方式访问NTFS文件系统。

    (6)、/proc filesystem support (CONFIG_PROC_FS) [Y/n/?] /proc是存放Linux系统运行状态的虚拟文件系统,该项必须选择“y”。

    (7)、Second extended fs support (CONFIG_EXT2_FS) [Y/m/n/?] EXT2是Linux的标准文件系统,该项也必须选择“y”。

    14、Network File Systems(网络文件系统)

    (1)、NFS filesystem support (CONFIG_NFS_FS) [Y/m/n/?] 选择“y”,内核将支持NFS文件系统。

    (2)、SMB filesystem support (to mount WfW shares etc.) (CONFIG_SMB_FS)

    选择“y”,内核将支持SMB文件系统。

    (3)、NCP filesystem support (to mount NetWare volumes) (CONFIG_NCP_FS)

    选择“y”,内核将支持NCP文件系统。

    15、Partition Types(分区类型)

    该选项支持一些不太常用的分区类型,用户如果需要,在相应的选项上选择“y”即可。

    16、Console drivers(控制台驱动)

    VGA text console (CONFIG_VGA_CONSOLE) [Y/n/?] 选择“y”,用户就可以在标准的VGA显示方式下使用Linux了。

    17、Sound(声音)

    Sound card support (CONFIG_SOUND) [N/y/m/?] 选择“y”,内核就可提供对声卡的支持。

    18、Kernel hacking(内核监视)

    Magic SysRq key (CONFIG_MAGIC_SYSRQ) [N/y/?] 选择“y”,用户就可以对系统进行部分控制。一般情况下选择“n”。

    六、 编译内核   (一)、建立编译时所需的从属文件   # cd /usr/src/linux   # make dep   (二)、清除内核编译的目标文件   # make clean   (三)、编译内核   # make zImage   内核编译成功后,会在/usr/src/linux/arch/i386/boot目录中生成一个新内核的映像文件zImage。如果编译的内核很大的话,系统会提示你使用make bzImage命令来编译。这时,编译程序就会生成一个名叫bzImage的内核映像文件。   (四)、编译可加载模块   如果用户在配置内核时设置了可加载模块,则需要对这些模块进行编译,以便将来使用insmod命令进行加载。   # make modules   # make modelus_install   编译成功后,系统会在/lib/modules目录下生成一个2.3.14子目录,里面存放着新内核的所有可加载模块。 七、 启动新内核   (一)、将新内核和System.map文件拷贝到/boot目录下   # cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz-2.3.14   # cp /usr/src/linux/System.map /boot/System.map-2.3.14   # cd /boot   # rm -f System.map   # ln -s System.map-2.3.14 System.map   (二)、配置/etc/lilo.conf文件。在该文件中加入下面几行:   default=linux-2.3.14   image=/boot/vmlinuz-2.3.14   label=linux-2.3.14   root=/dev/hda1   read-only   (三)、使新配置生效   # /sbin/lilo   (四)、重新启动系统   # /sbin/reboot   新内核如果不能正常启动,用户可以在LILO:提示符下启动旧内核。然后查出故障原因,重新编译新内核即可。

    展开全文
  • Linux内核的配置系统由三部分组成,分别是: Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则; 配置文件(config.in):给用户提供配置选择的功能; 配置工...

    转载地址:http://www.cnblogs.com/xiaotlili/archive/2011/08/03/2126751.html

    1. 配置系统的基本结构

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

    Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则; 
    配置文件(config.in):给用户提供配置选择的功能; 
    配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 Make config、Make menuconfig 和 make xconfig)。
    这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。

    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 **_defconfig,(针对SMDK2410的默认设置的配置文件位于:arch/arm/configs/s3c2410_defconfig,将这个文件拷贝到根目录下成为.config文件。在make menuconfig中加载这个默认的config文件;针对plugD的:arch/arm/configs/plugD_defconfig) 配置后,产生了 .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 中。

    展开全文
  • Linux内核的配置系统由三部分组成,分别是: Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则; 配置文件(config.in):给用户提供配置选择的功能; 配置工具:包括配置命令...

    1. 配置系统的基本结构

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

    Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则;
    配置文件(config.in):给用户提供配置选择的功能;
    配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 Make config、Make menuconfig 和 make xconfig)。
    这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。

    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 **_defconfig,(针对SMDK2410的默认设置的配置文件位于:arch/arm/configs/s3c2410_defconfig,将这个文件拷贝到根目录下成为.config文件。在make menuconfig中加载这个默认的config文件;针对plugD的:arch/arm/configs/plugD_defconfig) 配置后,产生了 .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 中。


    原文:http://www.cnblogs.com/xiaotlili/archive/2011/08/03/2126751.html

    展开全文
  • 如何编译和运行一个arm linux 内核 1. 准备工具 linux4.0 内核 busybox工具包 2. busybox手工编译一个最小的文件系统 cd busybox export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabi- make menuconfig ...

    如何编译和运行一个arm linux 内核

    1. 准备工具

    • linux4.0 内核
    • busybox工具包

    2. busybox手工编译一个最小的文件系统

    cd busybox
    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabi-
    make menuconfig 
    

    进入menuconfig之后,配制成静态编译。
    在这里插入图片描述
    在make & make install 编译完成后,在busybox根目录下会有一个“install”目录,该目录存放了编译好的文件系统需要的一些命令集合。
    把_install目录复制到linux-4.0目录下。进入_install目录,先创建etc,dev等目录。

    mkdir proc
    mkdir dev
    mkdir mnt
    mkdir -p etc/init.d/
    

    在_install/etc/init.d/目录下新建一个rcS文件,并写入如下内容。

    mkdir -p /proc
    mkdir -p /tmp
    mkdir -p /sys
    mkdir -p /mnt
    /bin/mount -a
    mkdir -p /dev/pts
    mkdir -t devpts devpts /dev/pts
    echo /sbin/mdev > /proc/sys/kernel/hotplug
    mdev -s
    

    chmod +x _install/etc/init.d/rcS
    在_install/etc目录下新建一个fstab文件,并写入如下内容:

    proc /proc proc defaults 0 0
    tmpfs /tmp tmpfs defaults 0 0
    sysfs /sys sysfs defaults 0 0
    tmpfs /dev tmpfs defaults 0 0
    debugfs /sys/kernel/debug debugfs defaults 0 0
    

    在_install/etc目录下新建一个inittab文件,并写入如下内容:

    ::sysinit:/etc/init.d/rcS
    ::respawn:-/bin/sh
    ::askfirst:-/bin/sh
    ::ctrlaltdel:/bin/umount -a -r
    

    在_install/dev 目录下新建如下设备节点,这时需要root权限。

    cd _install/dev/
    sudo mknod console c 5 1
    sudo mknod null c 1 3
    

    3.编译内核

    cd linux-4.0
    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabi-
    make vexpress_defconfig
    
    

    配置initramfs,在initramfs source file 中填入_install,并把 Default kernel command string 清空。
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    配置memory split 为“3G/1G user/kernel split”,并打开高端内存。
    在这里插入图片描述

    make bzImage -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
    make dtbs
    

    4.运行QEMU虚拟机

    运行QEMU虚拟机模拟4核Cortex-A9的Versatile Express开发平台。

    qemu-system-arm -M vexpress-a9 -smp 4 -m 200M -kernel arch/arm/boot/zImage arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic
    
    展开全文
  • HACK #2 如何编译Linux内核 本节介绍编译Linux内核的方法。当发现bug而修改源代码或者添加新功能时,就需要对内核进行重新编译,生成二进制映像文件。另外,如果想要使用发布版内核中无效的功能或者驱动程序时,...
  • 如何编译Linux内核

    2016-08-27 13:46:37
    如何编译Linux内核 内核,是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。Linux作为一个自由软件,在广大爱好者的支持下,内核版本不断...
  • 如何编译 Linux 内核

    2018-06-02 17:07:56
    曾经有一段时间,升级 Linux 内核让很多用户打心里有所畏惧。...考虑一下,既然升级内核如此容易,为什么你不愿意自行编译一个呢?这里列举一些可能的原因:你想要简单了解编译内核的过程你需要启用...
  • 如果有的话,没关系,今天小编就来教大家如何编译安装新的内核。在编译安装Linux内核之前先检查我们的虚拟机所在的磁盘空间,预留空间10G以上,不然编译安装内核无法完成。下面我们就开始内核的编译安装吧。(1)下载...
  • 内核,是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序...如果用户想要使用这些新特性,或想根据自己的系统度身定制一个更高效,更稳定的内核,就需要重新编译内核。本文将以RedHat Linux 6.0(ke...
  • 如何编译linux 内核

    2015-01-13 11:32:13
    内核,是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动...如果用户想要使用这些新特性,或想根据自己的系统度身定制一个更高效,更稳定的内核,就需要重新编译内核。本文将以RedHat Linux 6.0(kernel 2.
  • G:\Linux 大全\如何编译一个内核 - Ubuntu方式.rar

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,136
精华内容 454
关键字:

如何编译一个linux内核

linux 订阅