[转帖] 内核编译学习笔记之完整篇(v1.1.1)

 注 :该文章参考了如下内容 :

A)kernel-HOWTO

B)Module-HOWTO

C)man 手册

D)CU : RedHat Linux 2.6内核如何build kernel-sourcecode的rpm包 :

          http://linux.chinaunix.net/bbs/v ... code%B5%C4rpm%B0%FC

作者 :ailms <ailms{@}qq{dot}com>

版本 :v1.1.1

完成时间  :2007/09/29 22:48

**************************************************************************************


下面的东西都是在俺的 PC 实验得来的,可能由于环境不同会造成某些结果的不一致,欢迎各位朋友多多指正,补充 ! ^_^

目录

一、编译前的准备工作

二、编译内核的方式

三、/usr/src 目录的结构

四、2.4 内核编译过程步骤

五、2.4 下如何单独编译某个模块

六、关于 “depmod: *** Unresolved symbols ” 的问题

七、2.6 内核编译过程步骤

    a) make help

      b) 单个模块的编译

    c)如何导出当前内核的 .config (v1.1)

      d)如何生成 rpm 包 (V1.1)

八、补丁部分

    a)diff 命令的基本用法以及如何生成补丁文件

    b)补丁文件内容解读

    c)patch 命令的用法 :打补丁、测试、恢复(卸载)

    d)patchutils 工具包及 lsdiff、grepdiff 、splitdiff、combinediff 命令的使用 (V1.1)

    e)补丁的分类 :增量和差分型  [ 注 :资料上并没有明确定义,但为了便于自己记忆,所以借用备份领域的术语 ]

      f)如何给 Linux 内核打补丁:从 2.6.10 → 2.6.12.6

九、patch-kernel 脚本分析

十、patch-kernel 脚本应用实例
一、编译内核前的准备工作

1、为什么需要编译内核?

    需要手工编译内核的理由有很多,例如
   
    a)内核开发
   
    b)新版内核提供了你主机上某个硬件的驱动
   
    c)需要使用新的功能
   
    d)原来的内核过于臃肿,想裁减掉一些不必要的功能
   
    e)其他...
   
    不过编译内核之前还是需要考虑其他事情,如果只是想弄出一个 vmlinuz 来那很简单,关键是该内核日后的使用 :
   
    a)是否只能通过重编译内核来解决,有没有其他的方法
   
    b)新内核是否足够稳定?会否对那些应用产生影响?是否存在兼容性问题?
   
    c)新版本内核有那些已知的漏洞
   
    d)其他
   
    e)欢迎补充!!


2、如果是重新编译现有的内核,最好先备份整个源代码目录

一个 make mrproper 就可以把 .config 文件干掉,到时 make menuconfig 一个个重新选简直是令人抓狂 ,所以最好把该文件备份
       
3、查看 Documentation/Changes 文件

该文件告诉了要编译该版本的内核所需要的一些软件以及最低版本要求,例如

QUOTE:
 
  Current Minimal Requirements
============================

Upgrade to at *least* these software revisions before thinking you've
encountered a bug!  If you're unsure what version you're currently
running, the suggested command should tell you.

Again, keep in mind that this list assumes you are already
functionally running a Linux 2.2 kernel.  Also, not all tools are
necessary on all systems; obviously, if you don't have any PCMCIA (PC
Card) hardware, for example, you probably needn't concern yourself
with pcmcia-cs.

o  Gnu C                  2.95.3                  # gcc --version
o  Gnu make              3.77                    # make --version
o  binutils              2.9.1.0.25              # ld -v
o  util-linux            2.10o                  # fdformat --version
o  modutils              2.4.2                  # insmod -V
o  e2fsprogs              1.25                    # tune2fs
o  jfsutils              1.0.12                  # fsck.jfs -V
o  reiserfsprogs          3.6.3                  # reiserfsck -V 2>&1|grep reiserfsprogs
o  pcmcia-cs              3.1.21                  # cardmgr -V
o  PPP                    2.4.0                  # pppd --version
o  isdn4k-utils          3.1pre1                # isdnctrl 2>&1|grep version
4、使用 scripts/ver_linux 脚本进行快速检查

在源代码目录下(假设为 /usr/src/linux-2.6.20.1)有一个 scripts/ 目录,里面有很多有用的脚本,

其中一个叫做 ver_linux

[Copy to clipboard] [ - ]CODE:
[root@monitor scripts]# ll ver_linux
-rw-r--r--    1 root    root        2569 2002-11-29  ver_linux
[root@monitor scripts]#
由于没有执行权限,所以用 bash -f 来执行它。当然你也可以用 chmod a+x 来加上该权限

[Copy to clipboard] [ - ]CODE:
        [root@monitor scripts]# bash -f ver_linux
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.

Linux monitor.no7.com 2.4.20-8smp #1 SMP Thu Mar 13 17:45:54 EST 2003 i686 i686 i386 GNU/Linux

Gnu C                  3.2.2
Gnu make              3.79.1
util-linux            2.11y
mount                  2.11y
modutils              2.4.22
e2fsprogs              1.32
jfsutils              1.0.17
reiserfsprogs          3.6.4
pcmcia-cs              3.1.31
PPP                    2.4.1
isdn4k-utils          3.1pre4
Linux C Library        2.3.2
Dynamic linker (ldd)  2.3.2
Procps                2.0.11
Net-tools              1.60
Kbd                    1.08
Sh-utils              4.5.3
Modules Loaded        iptable_filter ip_tables autofs e100 microcode nls_iso8859-1 nls_cp437 vfat fat loop lvm-mod keybdev mousedev hid input usb-ohci usbcore ext3 jbd aic7xxx sd_mod scsi_mod
[root@monitor scripts]#
5、最好保存每个 make 命令的输出,例如 make <target> 2>&1 |tee /tmp/make-<target>.out

6、仔细阅读 tarball 中自带的 README 文件、Documentation/HOWTO 文件以及任何与你此次编译相关的文件

7、make menuconfig 过程中如果有不懂的选项,可以选择 <help> ,如果还是看不懂,就按照建议说的做

二、编译内核的方式

你可以通过 rpm (source rpm 或者 binary rpm)或者 tarball  的方式来编译。

1、安装方面 :

rpm 方式 :简单,可能有厂家专门优化的配置。但缺乏灵活性,一般都会预装很多东西,特别是一大堆的驱动模块

tarball 方式 :复杂、容易出错(例如选少了某个驱动的支持,导致新内核无法正常使用)。但提供足够的灵活性,编译什么东西都由你自己决定。
   
2、卸载方面 :

rpm 方式 :比较难。因为新内核是通过 rpm -ivh ,而不是 rpm -Uvh ,所以装完之后会有两个 kernel rpm 存在,一旦想卸载的话比较麻烦,rpm -e 会报错
       
tarball 方式 :很简单,直接把 /boot 下的相关文件和内核源代码树,/lib/modules 对应目录删除,修改 grub.conf 就可以了
三、/usr/src 目录的结构

下面是 2.4 内核的 :

[Copy to clipboard] [ - ]CODE:
[root@mail src]# ll
total 12
drwxr-xr-x    2 root    root        4096 Jan 25  2003 debug
lrwxrwxrwx    1 root    root          14 Sep 17 06:20 linux-2.4 -> linux-2.4.20-8
drwxr-xr-x  16 root    root        4096 Sep 17 06:20 linux-2.4.20-8
drwxr-xr-x    7 root    root        4096 Sep 17 06:20 redhat
[root@mail src]#
可以看到主要分成两类 :

1、内核源代码目录,例如 linux-2.4.20-8/ 。有多个内核就有多个这样的目录

2、redhat/ 目录。该目录是用于编译 sorce rpm 用的。其结构是 :

[Copy to clipboard] [ - ]CODE:
[root@monitor redhat]# find . -maxdepth 2 -type d
.
./BUILD                                                                                                               
./BUILD/kernel-2.4.2031.9custom               
./RPMS                                                                                                               
./RPMS/athlon                                                                                       
./RPMS/i386
./RPMS/i486
./RPMS/i586
./RPMS/i686
./RPMS/noarch
./SOURCES                                                                                                       
./SPECS                                                                                                               
./SRPMS                                                                                                               
[root@monitor redhat]#
BUILD/ 存放编译过程中的临时内容                                                                                   

BUILD/kernel-<release>/ 就是编译新版 kernel 时产生的目录。如果是编译其他的 src rpm 也会生成相应的目录         

RPMS/ 是存放编译好的二进制 rpm 包的目录                                                                       

RPMS/<platform>/ 是按平台区分的存放二进制 rpm 包的目录,编译后的二进制 rpm 在那个目录可以通过 $(arch) 命令获知                                                                                                               

SOURCES/ 是存放 source rpm 中的 tar.gz 的内容的。编译前会把 tar.gz 的内容解压到这里                               

SPECS/ 目录是存放 source rpm 中的 spec 文件的                                                                     

SRPMS/ 目录是存放编译好的 source rpm 的。如果你指定不生成 source rpm ,则该目录下不会有内容                       
                                                                                                                 
       
下面是 2.6 内核的 :

[Copy to clipboard] [ - ]CODE:
[root@mail src]# ll
total 16
drwxr-xr-x  6 root root 4096 Sep 27 17:05 kernels
drwxr-xr-x  7 root root 4096 Sep 16 22:54 redhat
[root@mail src]#


[Copy to clipboard] [ - ]CODE:
[root@mail src]# cd kernels/
[root@mail kernels]# ll
total 32
drwxr-xr-x  17 root root 4096 Sep 16 22:53 2.6.9-5.EL-hugemem-i686
drwxr-xr-x  17 root root 4096 Sep 26 21:10 2.6.9-5.EL-i686
drwxr-xr-x  17 root root 4096 Sep 16 22:53 2.6.9-5.EL-smp-i686
drwxrwxr-x  20 root root 4096 Sep 27 17:13 linux-2.6.20.1
[root@mail kernels]#
可以看到把多个内核源代码目录都集中放到 kernels/ 下,而不是直接放在 /usr/src/ 下。同时源代码目录也和 2.4 有稍微不同,具体待各位自己发现

gyjyxj 2007-10-31 16:25
四、2.4 内核编译过程步骤

这部分内容随便一搜就很多了,我也就不多说,把大概的过程列一下。这里以编译 2.4.35 为例

1、解开 tar 包到 /usr/src/ 下

2、 如果是重新编译内核的话,记得备份旧的 .config 文件并执行 make 。不要以 .config.bak 这样的名字备份,因为 make mrproper 

        会删除 .config.* 文件 !如果是编译新内核的话,把旧的 .config 文件拷贝到新的内核源代码目录下。
             
3、执行 make clean  mrproper

4、 执行 make oldconfig ,这样可以不用经历原来的选择过程,直接使用旧的配置文件否则执行 make menuconfig 

5、make dep 检查依赖性是否存在问题

6、编辑 /usr/src/linux/Makefile 的 EXTRAVERSION ,给这个内核加上一个你自己的名称 !例如 '.custom' ,这样编译出来的内核版本就是 2.4.35.custom

          不要忘记该步,否则后面的 make modules_install 新产生的模块文件会把 /lib/modules/2.4.35/ 下的内容都覆盖掉。

7、执行 make bzImage 生成内核的二进制文件

8、执行 'make moudles' 和 'make modules_install'

9、第8步是非常久的。

10、使用 cp 把 /usr/src/linux/arch/i386/boot/bzImage 文件拷贝到 /boot 下,重命名为你想要的内核名称,一般是 vmlinuz-2.x.x.-<your_version>

            再把 /usr/src/linux-2.4.35/System.map 拷贝到 /boot 下,重命名为 System.map-2.4.35.custom
                                       
            把 /usr/src/linux-2.4.35/.config 拷贝到 /boot 下,重命名为 config-2.4.35.custom       

11、修改 grub.conf 或者 lilo.conf ,加入相应内容。

12、重启并检查新内核是否可用,并检查对应用是否有影响。

13、用 mkbootdisk 命令创建 bootdisk

14、如果有时间可以用 make rpm 创建自己的内核 rpm 包,不过目前只在 rehdat 自己提供的 kernel source rpm 包上成功过,在 kerne.org 下在的源代码

        都失败了。

15、执行 make clean 把不用的文件删除

16、把 .config 文件备份到一个安全的位置

注 1 :其实编译内核时不一定要以 root 身份进行,例如你可以把 tar 包解压到你的 HOME 目录下,并按上面一步步做,直至 make modules

但因为 make modules_install 需要写 /lib/modules/ 目录,所以只有 root 才有这个权限。

五、2.4 下如何单独编译某个模块

有时候我们编译好了内核,模块文件也生成了。但在日后的使用过程中想增加某个模块应该怎么办呢?下面就以增加 reiserfs 、jfs 、xfs 模块为例进行说明。

当前的内核版本是 2.4.35.normal ,所以新生成的模块也将放在 /lib/modules/2.4.35.normal/fs/ 下

1、执行 make dep 2>&1 |tee /tmp/make_dep.out

2、复制 Makefile 为 Makefile.onlymodule

3、修改 Makefile.onlymodule 的 EXTRAVERSION 为 .onlymodule 。之所以这么做是因为不想覆盖当前内核的模块。
         
    也就是把 Makefile.onlymodule 的 SUBDIRS 为 :SUBDIRS =fs/reiserfs fs/jfs fs/xfs
             
4、执行make -f Makefile.onlymodule modules 2>&1 |tee /tmp/make_only_modules.out 生成上面的模块

    记得要加上 -f 参数,否则使用的还是 Makefile ,而不是 Makefile.onlymodule 文件
                               
5、执行make -f Makefile.onlymodule modules_install 2>&1 |tee /tmp/make_only_modules_install.out 安装模块

6、下面把生成好的模块文件拷贝到当前内核的模块目录下

[Copy to clipboard] [ - ]CODE:
[root@mail fs]# cd /lib/modules/2.4.35.onlymodule/kernel/fs
[root@mail fs]#
[root@mail fs]# ll
total 12
drwxr-xr-x    2 root    root        4096 Sep 19 01:15 jfs
drwxr-xr-x    2 root    root        4096 Sep 19 01:15 reiserfs
drwxr-xr-x    2 root    root        4096 Sep 19 01:15 xfs
[root@mail fs]#       
[root@mail fs]# uname -a
Linux mail.bob.com 2.4.35.normal #1 SMP Wed Sep 19 00:46:00 CST 2007 i686 i686 i386 GNU/Linux
[root@mail fs]#
[root@mail fs]# cp -a * /lib/modules/2.4.35.normal/kernel/fs/
[root@mail fs]#
可以看到上面的 /lib/modules/2.4.35.onlymodule/kernel/fs/ 下只有 jfs/、reiserfs/、xfs/ 三个目录,这就是因为 SUBDIRS 指定只生成这3个目录而已。

所以如果我们上面不修改 EXTRAVERSION 的话,则会把当前内核的模块目录(/lib/modules/2.4.35.normal/) 下的所有其他内容都删除,

再拷贝这3个目录 !!

而在 Kernel-HOWTO 中则没有修改 EXTRAVERSION 一步,直接修改 SUBDIRS ,结果就如同上面所说

7、这样我们就有了 reiserfs、jfs、xfs 文件系统的模块了。下面执行 depmod -a 生成新的 modules.dep 文件

注 :最好先备份原来的 /lib/modules/2.4.35.normal/modules.dep 文件,再执行 depmod

[Copy to clipboard] [ - ]CODE:
[root@mail modules]# depmod -a
[root@mail modules]# ll /lib/modules/2.4.35.normal/modules.dep
-rw-r--r--    1 root    root        8363 Sep 19 01:18 /lib/modules/2.4.35.normal/modules.dep
[root@mail modules]#
8、在新的 modules.dep 中查找相应的行 :

[Copy to clipboard] [ - ]CODE:
[root@mail modules]# grep -i 'reiserfs/|xfs/|jfs' /lib/modules/2.4.35.normal/modules.dep
/lib/modules/2.4.35.normal/kernel/fs/jfs/jfs.o:
/lib/modules/2.4.35.normal/kernel/fs/reiserfs/reiserfs.o:
/lib/modules/2.4.35.normal/kernel/fs/xfs/xfs.o:
[root@mail modules]#
可以看到已经有这些模块的行了

9、尝试加载这些模块

[Copy to clipboard] [ - ]CODE:
[root@mail modules]# modprobe jfs
[root@mail modules]# modprobe reiserfs
[root@mail modules]# modprobe xfs
[root@mail modules]# lsmod |grep fs
xfs                  594884  0  (unused)
reiserfs              298800  0  (unused)
jfs                  192248  0  (unused)
[root@mail modules]#
可以看到成功加载了

10、下面把 /lib/modules/2.4.35.onlymodule 删除,因为已经用不到了。

[Copy to clipboard] [ - ]CODE:
[root@mail modules]# rm -fr 2.4.35.onlymodule/
[root@mail modules]#

gyjyxj 2007-10-31 16:27
六、关于 “depmod: *** Unresolved symbols ” 的问题

不知道你是否注意到,前面有一个 System.map 文件,这个文件的具体作用在 Kernel-HOWOTO 中有讲,不过一般不用关心它

因为它是自动生成的。但是该文件的正确与否却会影响到模块的正常加载。下面以1个例子来说明

例如此前我们没有选择 ACPIP 支持,而现在我们想把该功能加到内核中,下面是 .config 文件中对应的部分

QUOTE:
# ACPI Support
#
CONFIG_ACPI=y
CONFIG_ACPI_BOOT=y
CONFIG_ACPI_BUS=y
CONFIG_ACPI_INTERPRETER=y
CONFIG_ACPI_EC=y
CONFIG_ACPI_POWER=y
CONFIG_ACPI_PCI=y
CONFIG_ACPI_MMCONFIG=y
CONFIG_ACPI_SLEEP=y
CONFIG_ACPI_SYSTEM=y
CONFIG_ACPI_AC=m
CONFIG_ACPI_BATTERY=m
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_PROCESSOR=m
CONFIG_ACPI_THERMAL=m
CONFIG_ACPI_ASUS=m
CONFIG_ACPI_TOSHIBA=m
如果直接按照上面的方法编译模块(不执行 make bzImage )的再执行 depmod -a ,会出现下面的错误

[Copy to clipboard] [ - ]CODE:
[root@mail 2.4.34.4]# depmod -a -n -F /boot/System.map-2.4.34.4 2.4.34.4  |more
depmod: /lib/modules/2.4.34.4/modules.dep.bak is not an ELF file
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/ac.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/asus_acpi.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/battery.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/button.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/fan.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/processor.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/thermal.o
depmod: *** Unresolved symbols in /lib/modules/2.4.34.4/kernel/drivers/acpi/toshiba_acpi.o
1、执行 make clean  bzImage

2、把新的 bzImage、.config、System.map 都拷贝到 /boot 下

3、现在重新执行 make -f Makefile.onlymodules modules

4、同样把我们需要的模块文件拷贝过去就可以。

5、再次执行 depmod ,这次不再出错了 !!!

6、这说明是由于此前没有执行 make bzImage 所致,导致 System.map 文件的内容不正确,

[Copy to clipboard] [ - ]CODE:
[root@mail 2.4.34.4]# depmod -a -F /boot/System.map-2.4.34.4 2.4.34.4 -n 2>/dev/null |grep -i 'unresolved'
[root@mail 2.4.34.4]#
7、去掉 -n 再次执行,可以看到 modules.dep 生成了 :

[Copy to clipboard] [ - ]CODE:
[root@mail 2.4.34.4]# ll modules.dep
-rw-r--r--    1 root    root        7513 Sep 20 00:22 modules.dep
[root@mail 2.4.34.4]#
8、检查 modules.dep 中是否含有 acpi 相关信息 :

[Copy to clipboard] [ - ]CODE:
[root@mail 2.4.34.4]# grep -i acpi modules.dep
/lib/modules/2.4.34.4/kernel/drivers/acpi/ac.o:
/lib/modules/2.4.34.4/kernel/drivers/acpi/asus_acpi.o:
/lib/modules/2.4.34.4/kernel/drivers/acpi/battery.o:
/lib/modules/2.4.34.4/kernel/drivers/acpi/button.o:
/lib/modules/2.4.34.4/kernel/drivers/acpi/fan.o:
/lib/modules/2.4.34.4/kernel/drivers/acpi/processor.o:
/lib/modules/2.4.34.4/kernel/drivers/acpi/thermal.o:    /lib/modules/2.4.34.4/kernel/drivers/acpi/processor.o
/lib/modules/2.4.34.4/kernel/drivers/acpi/toshiba_acpi.o:
[root@mail 2.4.34.4]#
所以当出现 'Unresolved symbols' 的问题时,有可能和 System.map 文件版本有关
七、2.6 内核的编译


1、RPM 方式编译

这部分见 http://linux.chinaunix.net/bbs/v ... code%B5%C4rpm%B0%FC

2、tarball 方式编译

个人感觉 2.6 的编译过程比 2.4 简单很多,有很多东西 make 都替你作了,就连修改 grub.conf 这样的东西也算在内。

而且 2.6 的 Makefile 中还有一个名为 help 的 target ,执行 make help 可以看到该 Makeilfe 中可用的 target

而在 2.4 的 Makefile 中并没有该 target

[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.20.16]# grep help Makefile
# To see a list of typical targets execute "make help"
# Basic helpers built in scripts/
                        cscope TAGS tags help %docs check% /
# Additional helpers built in scripts/
help:
        @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help
        @$(MAKE) $(build)=$(package-dir) help
        @$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp
        @$(if $(archhelp),$(archhelp),/
                echo '  No architecture specific help defined for $(ARCH)')
help:
[root@mail linux-2.6.20.16]#
下面是执行 make help 的输出

[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.9]# make help
Cleaning targets:
  clean          - remove most generated files but keep the config
  mrproper        - remove all generated files + config + various backup files

Configuration targets:
  oldconfig      - Update current config utilising a line-oriented program
  menuconfig      - Update current config utilising a menu based program
  xconfig        - Update current config utilising a QT based front-end
  gconfig        - Update current config utilising a GTK based front-end
  defconfig      - New config with default answer to all options
  allmodconfig    - New config selecting modules when possible
  allyesconfig    - New config where all options are accepted with yes
  allnoconfig    - New minimal config

Other generic targets:
  all            - Build all targets marked with [*]
* vmlinux        - Build the bare kernel
* modules        - Build all modules
  modules_install - Install all modules
  dir/            - Build all files in dir and below
  dir/file.[ois]  - Build specified target only
  rpm            - Build a kernel as an RPM package
  tags/TAGS      - Generate tags file for editors
  cscope          - Generate cscope index

Static analysers
  buildcheck      - List dangling references to vmlinux discarded sections
                    and init sections from non-init sections
  checkstack      - Generate a list of stack hogs
  namespacecheck  - Name space analysis on compiled kernel

Kernel packaging:
  rpm-pkg        - Build the kernel as an RPM package
  binrpm-pkg      - Build an rpm package containing the compiled kernel & modules
  deb-pkg        - Build the kernel as an deb package

Documentation targets:
  Linux kernel internal documentation in different formats:
  sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF)
  htmldocs (HTML), mandocs (man pages, use installmandocs to install)

Architecture specific targets (i386):
* bzImage      - Compressed kernel image (arch/i386/boot/bzImage) 
install      - Install kernel using
                  (your) ~/bin/installkernel or
                  (distribution) /sbin/installkernel or
                  install to $(INSTALL_PATH) and run lilo

  bzdisk      - Create a boot floppy in /dev/fd0
  fdimage      - Create a boot floppy image

  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
  make O=dir [targets] Locate all output files in "dir", including .config
  make C=1  [targets] Check all c source with $CHECK (sparse)
  make C=2  [targets] Force check of all c source with $CHECK (sparse)

Execute "make" or "make all" to build all targets marked with [*]
For further info see the ./README file
[root@mail linux-2.6.9]#
例如 V 变量是用于控制是否启用 verbose 模式,默认是 0 (不启用)

O 变量控制 make 生成的文件放到那里,默认是当前目录

比较有用的有 clean 、mrproper、oldconfig、menuconfig、modules_install、<dir/> 、<dir/file.ko>、rpm 等几个

3、2.6 内核的编译过程

2.6 内核的比较简单,只有几个步骤而已

        a) make mrproper  clean ,同样需要先备份 .config 文件

        b) make oldconfig 或者 make menuconfig

        c) make

        d) make modules_install

        e) make install

其中 make 等同于 make dep bzImage modules ,而 make install 会做如下事情 :

        a) 把 bzImage、System.map 都拷贝到 /boot 下并自动改名为 vmlinz-<releas> 和 System.map-<release>

        b) 自动生成 initrd ,而且是 cpio 格式的,不再是原来的 image 格式

        c) 自动修改 grub.conf ,加上新的内核,但不会修改默认引导的内核。这点和 rpm 方式安装新内核不同。



4、单个模块的编译

下面以 ntfs 为例进行说明

        a)直接生成模块文件

[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.20.1]# make M='fs/ntfs'
  LD      fs/ntfs/built-in.o
  CC [M]  fs/ntfs/aops.o
  CC [M]  fs/ntfs/attrib.o
  CC [M]  fs/ntfs/collate.o
  CC [M]  fs/ntfs/compress.o
  CC [M]  fs/ntfs/debug.o
  CC [M]  fs/ntfs/dir.o
  CC [M]  fs/ntfs/file.o
  CC [M]  fs/ntfs/index.o
  CC [M]  fs/ntfs/inode.o
  CC [M]  fs/ntfs/mft.o
  CC [M]  fs/ntfs/mst.o
  CC [M]  fs/ntfs/namei.o
  CC [M]  fs/ntfs/runlist.o
  CC [M]  fs/ntfs/super.o
  CC [M]  fs/ntfs/sysctl.o
  CC [M]  fs/ntfs/unistr.o
  CC [M]  fs/ntfs/upcase.o
  CC [M]  fs/ntfs/bitmap.o
  CC [M]  fs/ntfs/lcnalloc.o
  CC [M]  fs/ntfs/logfile.o
  CC [M]  fs/ntfs/quota.o
  CC [M]  fs/ntfs/usnjrnl.o
  LD [M]  fs/ntfs/ntfs.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      fs/ntfs/ntfs.mod.o
  LD [M]  fs/ntfs/ntfs.ko               
[root@mail linux-2.6.20.1]#
上面最后显示的 fs/ntfs/ntfs.ko 就是我们想要的。

        b)手工拷贝带模块文件到

[Copy to clipboard] [ - ]CODE:
[root@mail fs]# pwd
/lib/modules/2.6.20.1/kernel/fs
[root@mail fs]# mkdir ntfs
[root@mail fs]#
[root@mail fs]# cd ntfs
[root@mail ntfs]# ll
total 0
[root@mail ntfs]# cp -a /usr/src/linux-2.6.20.1/fs/ntfs/ntfs.ko .
[root@mail ntfs]#                       
c)执行 depmod -a 生成新的 modules.dep 文件

[Copy to clipboard] [ - ]CODE:
[root@mail ntfs]# depmod -a
[root@mail ntfs]#
[root@mail 2.6.20.1]# ll modules.dep
-rw-r--r--  1 root root 92323 Sep 27 01:00 modules.dep               
[root@mail 2.6.20.1]#
d)尝试手工加载

[Copy to clipboard] [ - ]CODE:
手工尝试加载
[root@mail ntfs]# modprobe ntfs
[root@mail ntfs]#
[root@mail ntfs]# lsmod |grep ntfs
ntfs                  206740  0
[root@mail ntfs]#
可以看到 ntfs 模块已经加载成功了 !!!

gyjyxj 2007-10-31 16:29
5、 如何获取当前内核的配置(.config 文件)

在 2.4 的时候,我经常碰到一个问题就是不小心把 .config 文件弄丢了,除非事先有备份,否则只能 make menuconfig 一个个重新选。

但在 2.6 就不同了,在 Gerneal Setup 部分有一个功能叫做 "Kernel .config support" ,意思如下

[转帖] 内核编译学习笔记之完整篇(v1.1.1)_第1张图片
一旦你选中它,还有另外一个功能出现,就是 "Enabel access to .config through /proc/config.gz“
[转帖] 内核编译学习笔记之完整篇(v1.1.1)_第2张图片
建议把这个选上。有了这个,上面的问题就迎刃而解了,方法有二 :

        a)通过 scripts/extract_ikconfig 脚本从一个 bzImage 文件中提出出来。不过目前试了很多次,总是报下面的错误

[Copy to clipboard] [ - ]CODE:
        [root@mail scripts]# ./extract-ikconfig  /boot/vmlinuz-2.6.20.1 
        cc: ./scripts/binoffset.c: No such file or directory
        cc: no input files
        [root@mail scripts]#
       
b)通过 /proc/config.gz 文件获取,这是最方便的方法之一。步骤如下 :

[Copy to clipboard] [ - ]CODE:
        [root@mail proc]# ll /proc/config.gz
        -r--r--r--  1 root root 15192 Sep 27 01:12 /proc/config.gz
        [root@mail proc]# file /proc/config.gz
        /proc/config.gz: gzip compressed data, from Unix, max compression
        [root@mail proc]#
        [root@mail proc]# cat /proc/config.gz |gzip -d > /tmp/config
        [root@mail proc]# ll /tmp/config
        -rw-r--r--  1 root root 58949 Sep 27 01:13 /tmp/config
        [root@mail proc]#
        [root@mail proc]# cd /tmp
        [root@mail tmp]# more config
        #
        # Automatically generated make config: don't edit
        # Linux kernel version: 2.6.20.1
        # Thu Sep 27 00:07:58 2007
        #
        CONFIG_X86_32=y
        CONFIG_GENERIC_TIME=y
        CONFIG_LOCKDEP_SUPPORT=y
        CONFIG_STACKTRACE_SUPPORT=y
        CONFIG_SEMAPHORE_SLEEPERS=y
        CONFIG_X86=y
        CONFIG_MMU=y
        CONFIG_GENERIC_ISA_DMA=y
        CONFIG_GENERIC_IOMAP=y
(省略)
       
这样是不是很方便呢 ^_^ !
6、生成 rpm 包


首先它会调用 make spec 在 /usr/src/redhat/SPECS/ 下生成一个 kernel.spec 文件

然后在 rpmbuild -ba 该 spec 文件

[Copy to clipboard] [ - ]CODE:
[root@mail SPECS]# ps -ef |grep rpm
root    19536 19501  0 23:06 pts/0    00:00:00 make rpm
root    19761 19536  0 23:06 pts/0    00:00:00 make -f scripts/Makefile.build obj=/usr/src/kernels/linux-2.6.20.16/scripts/package rpm
root    20478 19761  0 23:08 pts/0    00:00:00 rpmbuild --target i386 -ta ../kernel-2.6.20.16.tar.gz
root    20503 20478  0 23:08 pts/0    00:00:00 /bin/sh -e /var/tmp/rpm-tmp.64176
root    32099 27815  0 23:16 pts/1    00:00:00 grep rpm
[root@mail SPECS]#
这个过程很久,和整个编译流程差不多久

当你看到类似下面的输出

QUOTE:
  INSTALL sound/synth/snd-util-mem.ko
  INSTALL sound/usb/snd-usb-audio.ko
  INSTALL sound/usb/snd-usb-lib.ko
  INSTALL sound/usb/usx2y/snd-usb-usx2y.ko
if [ -r System.map -a -x /sbin/depmod ]; then /sbin/depmod -ae -F System.map -b /var/tmp/kernel-2.6.20.16-root -r 2.6.20.16; fi
+ cp arch/i386/boot/bzImage /var/tmp/kernel-2.6.20.16-root/boot/vmlinuz-2.6.20.16
+ cp System.map /var/tmp/kernel-2.6.20.16-root/boot/System.map-2.6.20.16
+ cp .config /var/tmp/kernel-2.6.20.16-root/boot/config-2.6.20.16
+ /usr/lib/rpm/brp-compress
Processing files: kernel-2.6.20.16-4
Provides: kernel-2.6.20.16 kernel-drm
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/kernel-2.6.20.16-root

Wrote: /usr/src/redhat/SRPMS/kernel-2.6.20.16-4.src.rpm               
Wrote: /usr/src/redhat/RPMS/i386/kernel-2.6.20.16-4.i386.rpm       
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.30844
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd kernel-2.6.20.16
+ exit 0
rm ../kernel-2.6.20.16.tar.gz
[root@mail linux-2.6.20.16]#
下面查看生成的 rpm 包

[Copy to clipboard] [ - ]CODE:
[root@mail SRPMS]# ll |grep '2.6.20' --color
-rw-r--r--  1 root root 57218857 Sep 27 23:39 kernel-2.6.20.16-4.src.rpm
[root@mail SRPMS]#
[root@mail redhat]# cd RPMS
[root@mail RPMS]# cd i386/
[root@mail i386]# ll
total 72160
-rw-r--r--  1 root root 73808854 Sep 27 23:43 kernel-2.6.20.16-4.i386.rpm
[root@mail i386]#
下面是 binary rpm 包的内容

[Copy to clipboard] [ - ]CODE:
[root@mail i386]# rpm -qlp kernel-2.6.20.16-4.i386.rpm |more
/boot/System.map-2.6.20.16
/boot/config-2.6.20.16
/boot/vmlinuz-2.6.20.16
/lib/modules
/lib/modules/2.6.20.16
/lib/modules/2.6.20.16/build
/lib/modules/2.6.20.16/kernel
/lib/modules/2.6.20.16/kernel/arch
/lib/modules/2.6.20.16/kernel/arch/i386
/lib/modules/2.6.20.16/kernel/arch/i386/crypto
/lib/modules/2.6.20.16/kernel/arch/i386/crypto/aes-i586.ko
(省略)
日后你可以使用该 rpm 来安装或者升级内核,不需要重新编译和安装模块了。

gyjyxj 2007-10-31 16:30
八、补丁部分

补丁是内核的一个补充或者修改,例如修改某些错误,增加某些功能等。

补丁的体积一般很小,但也有很大的(在后面可以看到),这是它的一个优点,下载一个几十KB的文件总比下载一个动辄几十MB 的内核源代码包要快得多

所以说补丁也不能忽视的。

要学习如何使用补丁,就必须从 diff 命令学起,因为补丁就是通过它来生成的。

1、我们先给出 diff 命令的主要选项

        a)-e :ed 模式

        b)-u :unified 模式

        c)-i :忽略大小写

        d)-s :文件相同时报告

        e)-r :递归

        f)-N :如果文件只存在于一方,则当成对方存在同名空文件。

        g)--exclude= :排除匹配该 shell wildcard 的文件或者子目录

        h)--exclude-from= :从指定文件读取 exluce 信息

        i)-b :忽略空格的差异

        j)-B :忽略空行的差异

        k)-I :忽略指定模式的差异

        l)--side-by-side :分列输出格式。


2、diff 的输出格式

diff 有5种输出格式,分别是 normal、ed、RCS、Context、Unified 。这5种各有不同,其中最常用的就是 normal 和 unified 格式,

其中 unified 格式也是内核补丁所采用的格式。它和直观,但所包含的内容也比 ed 格式或者 normal 格式的多,所以体积比较大,

特别是对于一些重大版本的升级更是如此。

下面只介绍 Normal 格式和 Unified 格式,ed 格式输出内容很少,不利于我们的阅读,但执行起来比较快

假设有两个文件 a 和 b,内容如下

[Copy to clipboard] [ - ]CODE:
[bob@mail bob]$ cat -n a
    1  ebc
    2  de
    3  123
    4  ok1
[bob@mail bob]$ cat -n b
    1  de
    2  abc
    3  123
    4  ok
[bob@mail bob]$
下面是 Normal 格式的输出

[Copy to clipboard] [ - ]CODE:
[bob@mail bob]$ diff a b
1d0                                                                                # 注释 :删除文件 a 的第1行 (ebc 行)
< ebc
2a2                                                                                # 注释 :插入 abc 到新的 a 文件的第2行处 ,也就是 dc → abc → 123 → ok1
> abc
4c4                                                                                # 注释 :把新的 a 文件的第4行(ok1)删除,改为 ok ,并插入到第4行处
< ok1               
---                                                                                                也就是 dc → abc → 123 → ok
> ok
[bob@mail bob]$
下面是 Unified 格式的输出

[Copy to clipboard] [ - ]CODE:
[bob@mail bob]$ diff -u a b
--- a  2007-09-20 17:23:40.000000000 +0800
+++ b  2007-09-20 17:23:41.000000000 +0800
@@ -1,4 +1,4 @@
-ebc                                                # 注释 :删除 a 的 ebc 行
de
+abc                                                # 注释 :在 de 后插入 abc 行       
123
-ok1                                                # 注释 :删除 123 后的 ok1 行
+ok                                                        # 注释 :插入 ok 行
[bob@mail bob]$
上面只是把结果输出到 stdout ,你可以通过 IO 重定向把它保存起来。

3、使用diff 生成补丁

我们需要3个目录 ,分别是 :

QUOTE:
        /home/bob/old :模拟开发者上的旧版本目录
        /home/bobnew :模拟开发者上的新版本目录
        /tmp/mine :这个是我们机器上的目录,将要更新的就是该目录下的文件
下面是生成补丁的过程

[Copy to clipboard] [ - ]CODE:
[bob@mail bob]$ diff -Nru $(pwd)/old/ $(pwd)/new/ > new.patch
[bob@mail bob]$
[bob@mail bob]$ file new.patch
new.patch: 'diff' output text                                               
[bob@mail bob]$
查看补丁文件 new.patch 的内容

[Copy to clipboard] [ - ]CODE:
[bob@mail bob]$cat new.patch
diff -Nru /home/bob/old/a /home/bob/new/a
--- /home/bob/old/a    2007-09-20 23:30:43.000000000 +0800
+++ /home/bob/new/a    2007-09-20 23:30:46.000000000 +0800
@@ -1,6 +1,5 @@
-ebc
de
+abc
123
-ok1
-### tmpline
-
+ok
+# tmpline
diff -Nru /home/bob/old/b /home/bob/new/b
--- /home/bob/old/b    2007-09-21 16:07:28.000000000 +0800
+++ /home/bob/new/b    2007-09-21 16:08:05.000000000 +0800
@@ -1,3 +1,5 @@
-redhat 9
+rehdat 9
RHEL4
Windows
+CentOS
+Slackware
[bob@mail bob]$
上面有多行以 diff -Nru 开头的行,后面是 --- 和 +++ 开头的行,

对每个文件的修改都有这3行,diff -Nru 是给出生成指定文件的补丁的命令,--- 是指旧版本的文件,+++ 是指新版本的文件

可以看到补丁文件实际上就是由多个这样的块组成的。


4、下面用 new.patch 来”尝试“升级我们的文件

/tmp/mine/  目录和 /home/bob/old/ 相比,后者就类似于发布该补丁的主机上的目录,前者就是我们想用该补丁升级的内容所在的目录

在打补丁之前需要做一件事,就是先查看补丁文件中的路径结构是否和我们的结构一致,也就是决定 -p 的值。

下面给出一个例子

[Copy to clipboard] [ - ]CODE:
[bob@mail mine]$ head -n3 ../new.patch   
diff -Nru /home/bob/old/a /home/bob/new/a
--- /home/bob/old/a    2007-09-20 23:30:43.000000000 +0800
+++ /home/bob/new/a    2007-09-20 23:30:46.000000000 +0800
[bob@mail mine]$ patch -p4 < ../new.patch --dry-run                        # 注释 :可以看到要指向 /tmp/mine/a,必须去掉前面的4个/ ,只剩下 ‘a’ 或者 ‘b’ 就可以
patching file a                                                                                                       
patching file b
[bob@mail mine]$
如果使用了错误的 -p 值会怎样呢?

[Copy to clipboard] [ - ]CODE:
[bob@mail mine]$ patch -p3 < ../new.patch --dry-run                       
can't find file to patch at input line 4                                                                        # 注释 :提示错误路径,因为 /tmp/mine 下没有 old/ 目录
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff -Nru /home/bob/old/a /home/bob/new/a
|--- /home/bob/old/a    2007-09-20 23:30:43.000000000 +0800
|+++ /home/bob/new/a    2007-09-20 23:30:46.000000000 +0800
--------------------------
File to patch:
(此处按 CTRL-C )
[bob@mail mine]$
注 :建议在真正打补丁之前,都要用 --dry-run 先测试一番,以免无畏浪费时间

5、使用 new.patch ”真正“升级

[bob@mail mine]$ patch -b -p4 < ../new.patch
patching file a
patching file b
[bob@mail mine]$
[/code]

[Copy to clipboard] [ - ]CODE:
[bob@mail mine]$ ll
total 16
-rw-rw-r--    1 bob      bob            24 Sep 21 16:42 a
-rw-rw-r--    1 bob      bob            28 Sep 21 15:57 a.orig                # 注释 :这就是 -b 的作用,把源文件备份为 xxx.orig
-rw-rw-r--    1 bob      bob            40 Sep 21 16:42 b
-rw-rw-r--    1 bob      bob            23 Sep 21 16:17 b.orig
[bob@mail mine]$
可以看到有 .orig 文件存在,这是 -b 选项所造成的,-b 用于强制备份每个修改过的文件

6、查看新版本的文件的内容

[Copy to clipboard] [ - ]CODE:
查看新的 a 、b 文件的内容
[bob@mail mine]$ cat a
de
abc
123
ok
# tmpline
[bob@mail mine]$
[bob@mail mine]$ cat b
rehdat 9
RHEL4
Windows
CentOS
Slackware                                       
[bob@mail mine]$
是否变成了和 /home/bob/new/ 下的 a 和 b 文件一样的内容了呢 ! ^_^

7、如何撤销一个补丁

如果一个补丁我们打到一半报错了,应该怎么办呢?或者说我们发现该补丁有 bug ,想卸载它呢?

这就要用到 -R 选项了,-R 是 reverse (相反)的意思,顾名思义就是去掉之前打的补丁,回到原来的老样子

[Copy to clipboard] [ - ]CODE:
[bob@mail mine]$ rm -f *.rej
[bob@mail mine]$
[bob@mail mine]$ patch -R -p4 < ../new.patch 
patching file a
patching file b
[bob@mail mine]$
[bob@mail mine]$ cat a
ebc
de
123
ok1
### tmpline

[bob@mail mine]$ cat b
redhat 9
RHEL4
Windows
[bob@mail mine]$
可以看到 a 和 b 文件又变成原来的内容了

8、重复打补丁会怎样?

假设我们刚刚打了 new.patch ,然后又再打一次会怎样呢?

[Copy to clipboard] [ - ]CODE:
[bob@mail mine]$ patch -b -p4 < ../new.patch
patching file a
Reversed (or previously applied) patch detected!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file a.rej
patching file b
Reversed (or previously applied) patch detected!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file b.rej
[bob@mail mine]$ ll
total 24
-rw-rw-r--    1 bob      bob            24 Sep 21 16:42 a
-rw-rw-r--    1 bob      bob            28 Sep 21 15:57 a.orig
-rw-rw-r--    1 bob      bob          116 Sep 21 16:46 a.rej
-rw-rw-r--    1 bob      bob            40 Sep 21 16:42 b
-rw-rw-r--    1 bob      bob            23 Sep 21 16:17 b.orig
-rw-rw-r--    1 bob      bob          121 Sep 21 16:46 b.rej
[bob@mail mine]$
可以看到生成了.rej 文件,一旦 patch 生成了 .rej ,就意味着有某些文件无法正确地被修改。这有可能是你自己改过源文件所致


9、如何自动忽略已经打过的补丁?

如果想让 patch 自动忽略这些已经打过的补丁呢?用 -N 选项

[Copy to clipboard] [ - ]CODE:
[root@mail mine]# patch -N -i ../new.patch
patching file a
Reversed (or previously applied) patch detected!  Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file a.rej
patching file b
Reversed (or previously applied) patch detected!  Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file b.rej
The next patch would empty out the file c,
which is already empty!  Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file c.rej
[root@mail mine]#
可以看到即使用了 -N 或者 --forward ,还是会生成 .rej 文件。但不会再次提问了。

gyjyxj 2007-10-31 16:31
补丁工具包之 patchutils

patchutils 工具包

当你拿到一个补丁,你会想知道它究竟会修改那些文件 。或者你想知道该补丁文件是否会修改某个文件,这些应该怎么实现呢?

patchutils 是系统自带的一个工具包,顾名思义就是专门服务于 patch 文件的。它提供了很多的命令,例如 lsdiff、grepdiff 等。

[Copy to clipboard] [ - ]CODE:
[bob@mail tmp]$ rpm -qi patchutils
Name        : patchutils                  Relocations: (not relocateable)
Version    : 0.2.19                            Vendor: Red Hat, Inc.
Release    : 1                            Build Date: Sat 25 Jan 2003 01:59:14 PM CST
Install Date: Mon 17 Sep 2007 06:20:02 AM CST      Build Host: porky.devel.redhat.com
Group      : Applications/System          Source RPM: patchutils-0.2.19-1.src.rpm
Size        : 128817                          License: GPL
Signature  : DSA/SHA1, Mon 24 Feb 2003 02:43:34 PM CST, Key ID 219180cddb42a60e
Packager    : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
URL        : http://cyberelk.net/tim/patchutils/
Summary    : A collection of programs for manipulating patch files
Description :
This is a collection of programs that can manipulate patch files in
a variety of ways, such as interpolating between two pre-patches,
combining two incremental patches, fixing line numbers in hand-edited
patches, and simply listing the files modified by a patch.
[bob@mail tmp]$
它提供的命令有

QUOTE:
combinediff          (1)  - create a cumulative unified patch from two incremental patches
dehtmldiff          (1)  - get usable diff from an HTML page
editdiff [rediff]    (1)  - fix offsets and counts of a hand-edited diff
espdiff              (1)  - apply the appropriate transformation to a set of patches
filterdiff          (1)  - extract or exclude diffs from a diff file
fixcvsdiff          (1)  - fix problematic diff files
flipdiff: nothing appropriate
grepdiff            (1)  - show files modified by a diff containing a regex
interdiff            (1)  - show differences between two diff files
lsdiff              (1)  - show which files are modified by a patch
recountdiff          (1)  - recompute patch counts and offsets
rediff              (1)  - fix offsets and counts of a hand-edited diff
splitdiff            (1)  - separate out incremental patches
unwrapdiff: nothing appropriate
我只介绍 lsdiff 和 grepdiff ,还有 splitdiff 和 combinediff 命令也可以学一下。

2、lsidff 命令

lsdiff 命令的常用选项有 :

        -n :显示每个 hunk 定义在 patch 文件中的行号
       
        -v :verbose 模式
       
        --number-files :类似于 cat -n

        --files= :只列出指定旧文件的 hunk
       
        --strip= :输出文件名之前去掉路径前面的 n 个目录
       
        --addprefix= :在输出文件名时加上指定前缀
       
        -s :打印每个旧(源)文件的最终结果(增加/修改/删除)
       
        -i :显示文件名路径匹配指定模式的 hunk
       
        -x :排除文件名路径匹配指定模式的 hunk
       
        --version :显示版本信息
       
        --filter :模仿 filterdiff 的操作

3、lsdiff 应用实例

lsdiff 的默认输出

[Copy to clipboard] [ - ]CODE:
[bob@mail tmp]$ lsdiff new.patch
/home/bob/old/a
/home/bob/old/b
/home/bob/old/c
[bob@mail tmp]$
lsdiff -n 的输出

[Copy to clipboard] [ - ]CODE:
[bob@mail tmp]$ lsdiff new.patch -n
2      /home/bob/old/a
15      /home/bob/old/b
25      /home/bob/old/c
[bob@mail tmp]$

[bob@mail tmp]$ grep -n '/home/bob/old/' new.patch 
1:diff -Nru /home/bob/old/a /home/bob/new/a
2:--- /home/bob/old/a  2007-09-20 23:30:43.000000000 +0800
14:diff -Nru /home/bob/old/b /home/bob/new/b
15:--- /home/bob/old/b  2007-09-21 16:07:28.000000000 +0800
24:diff -Nru /home/bob/old/c /home/bob/new/c
25:--- /home/bob/old/c  2007-09-23 21:27:50.000000000 +0800
[bob@mail tmp]$
lsdiff -v 的输出

[Copy to clipboard] [ - ]CODE:
[bob@mail tmp]$ lsdiff -v new.patch
diff -Nru /home/bob/old/a /home/bob/new/a
/home/bob/old/a
diff -Nru /home/bob/old/b /home/bob/new/b
/home/bob/old/b
diff -Nru /home/bob/old/c /home/bob/new/c
/home/bob/old/c
[bob@mail tmp]$ lsdiff -v new.patch -n
diff -Nru /home/bob/old/a /home/bob/new/a
2      /home/bob/old/a
        4      Hunk #1
diff -Nru /home/bob/old/b /home/bob/new/b
15      /home/bob/old/b
        17      Hunk #1
diff -Nru /home/bob/old/c /home/bob/new/c
25      /home/bob/old/c
        27      Hunk #1
[bob@mail tmp]$
lsidff -s 的输出

-        :删除该文件。表示新目录下没有该文件,但旧目录有
! :修改该文件
+ :新增该文件。表示新目录下有该文件,但旧目录没有。

[Copy to clipboard] [ - ]CODE:
[bob@mail bob]$ ll old
total 16
-rw-rw-r--    1 bob      bob            28 Sep 20 23:30 a
-rw-rw-r--    1 bob      bob            23 Sep 21 16:07 b
-rw-r--r--    1 root    root          17 Sep 23 21:27 c
-rw-rw-r--    1 bob      bob            3 Sep 24 11:23 e                # 注释 :该文件不存在于 new/ 目录下,属于删除的。
[bob@mail bob]$

[bob@mail bob]$ ll new
total 12
-rw-rw-r--    1 bob      bob            42 Sep 24 11:21 a
-rw-rw-r--    1 bob      bob            40 Sep 21 16:08 b
-rw-r--r--    1 root    root            0 Sep 23 21:23 c
-rw-rw-r--    1 bob      bob            3 Sep 24 11:22 d                # 注释 :该文件不存在于 old/ 目录下,属于新增加的。
[bob@mail bob]$

[bob@mail bob]$ lsdiff -s new.patch
! /home/bob/old/a
! /home/bob/old/b
! /home/bob/old/c
+ /home/bob/old/d
- /home/bob/old/e
[bob@mail bob]$
lsdiff -i 的输出

lsdiff -i 指定一个 shell wildcard ,用于匹配文件名(不匹配路径)

[Copy to clipboard] [ - ]CODE:
[bob@mail tarball]$ lsdiff patch-2.4.35 |more
a/Documentation/Configure.help
a/Documentation/SubmittingDrivers
a/Documentation/kernel-parameters.txt
a/Documentation/networking/e1000.txt

[bob@mail tarball]$ lsdiff -i "e1000.txt" patch-2.4.35 
[bob@mail tarball]$ lsdiff -i "*e1000.txt" patch-2.4.35
a/Documentation/networking/e1000.txt
[bob@mail tarball]$
4、grepdiff 命令应用实例

grepdiff 和 lsdiff 不同的地方在于,它搜索的是修改的内容部分,而不是文件名。

而且 grepdiff 支持 regex ,而 lsdiff 只支持 shell wildcard

从下面的例子就可以知道了

[Copy to clipboard] [ - ]CODE:
[n7css@monitor n7css]$ grepdiff '.*e1000.*' patch-2.4.35 -n|cat -n
    1  226    a/Documentation/networking/e1000.txt
    2  1171    a/MAINTAINERS                # 注释 :这个文件的文件名并没有 e1000 字样,但由于其中一个 hunk 含有 e1000 ,所以被列出来了。
    3  2441    a/drivers/net/e1000/Makefile
    4  2454    a/drivers/net/e1000/e1000.h
    5  2812    a/drivers/net/e1000/e1000_ethtool.c
    6  4900    a/drivers/net/e1000/e1000_hw.c
    7  13336  a/drivers/net/e1000/e1000_hw.h
    8  15482  a/drivers/net/e1000/e1000_main.c
    9  21097  a/drivers/net/e1000/e1000_osdep.h
    10  21236  a/drivers/net/e1000/e1000_param.c
    11  21968  b/drivers/net/e1000/kcompat.c
    12  22043  b/drivers/net/e1000/kcompat.h
[n7css@monitor n7css]$
但 lsdiff 则不会这样

[Copy to clipboard] [ - ]CODE:
[n7css@monitor n7css]$ lsdiff -i "*e1000*" patch-2.4.35 -n |cat -n
    1  226    a/Documentation/networking/e1000.txt
    2  2441    a/drivers/net/e1000/Makefile
    3  2454    a/drivers/net/e1000/e1000.h
    4  2812    a/drivers/net/e1000/e1000_ethtool.c
    5  4900    a/drivers/net/e1000/e1000_hw.c
    6  13336  a/drivers/net/e1000/e1000_hw.h
    7  15482  a/drivers/net/e1000/e1000_main.c
    8  21097  a/drivers/net/e1000/e1000_osdep.h
    9  21236  a/drivers/net/e1000/e1000_param.c
    10  21968  b/drivers/net/e1000/kcompat.c
    11  22043  b/drivers/net/e1000/kcompat.h
[n7css@monitor n7css]$
可以看到 a/MATAINNANCE 文件没有被列出,因为它的文件名不含 e1000 字样
给内核打补丁

给内核打补丁和给普通文件打补丁没有什么不同,关键是要弄清楚那个补丁才是你需要的。

linux 内核有两种补丁 :

        1、增量型补丁 :表示这个补丁是在前一补丁版上生成的,例如 patch-2.4.9 是在 2.4.8 内核的基础上生成的。
       
        2、差分型补丁:表示这个补丁是对上一个 base version 的基础上生成的,例如 2.6.20.6 是在 2.6.20 的基础上生成的,而不是在 2.6.20.5 基础杀功能生成的。
       
2、如何区分补丁的类型

这主要通过查看补丁文件的 Makefile 就知道了。

还是以 patch-2.4.9 为例

QUOTE:
diff -u --recursive --new-file v2.4.8/linux/Makefile linux/Makefile
--- v2.4.8/linux/Makefile        Sun Aug 12 13:27:58 2001
+++ linux/Makefile        Thu Aug 16 11:12:49 2001
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 4
-SUBLEVEL = 8               
+SUBLEVEL = 9               
EXTRAVERSION =
可以看到 EXTRAVERSION 从 8 修改为 9 ,也就是说它要求当前内核的 EXTRAVERSION 必须是 8 ,完整版本是 2.4.8 ,该补丁将升级到 2.4.9

下面是一个”差分型“的补丁的例子

QUOTE:
diff --git a/Makefile b/Makefile
index e44ff6b..50d6d02 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 35
-EXTRAVERSION =       
+EXTRAVERSION = .3                                 
可以看到它要求当前内核的 EXTRAVERSION 必须是空,也就是2.4.35 ,补丁将升级到 2.4.35.3

所以如果你当前的内核版本是 2.4.35.1 ,则必须先用 patch -R < patch-2.4.35.1 退回到 2.4.35 版本,然后再 patch < 2.4.35.3 升级

3、常用的 patch 模式


        a)从 2.x.y → 2.x.y+1 : 直接升级
       
        b)从 2.x.y.z → 2.x.y+1 :先用 patch -R 退回到 2.x.y 再升级到 2.x.y+1
       
        c)从 2.x.y → 2.x.y+1.z :先升级到 2.x.y+1 ,再直接升级到 2.x.y+1.z
       
        d)从 2.x.y.z → 2.x.y.z+1 :先用 patch -R 退回到 2.x.y 再升级到 2.x.y.z+1


4、内核打补丁实例

下面以从 2.6.10 升级到 2.6.12.6 为例说明

需要下载的有



1、linux-2.6.10

2、patch-2.6.11

3、patch-2.6.12

4、patch-2.6.12.6



[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.10]# pwd
/usr/src/kernels/linux-2.6.10
[root@mail linux-2.6.10]#

[root@mail linux-2.6.10]# ll -h patch*
-rw-r--r--  1 root root 22M Sep 27 22:31 patch-2.6.11
-rw-r--r--  1 root root 24M Sep 27 22:31 patch-2.6.12
-rw-r--r--  1 root root 50K Sep 27 22:31 patch-2.6.12.6
[root@mail linux-2.6.10]#

[root@mail linux-2.6.10]# head -n5 Makefile
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 10
EXTRAVERSION =
NAME=Woozy Numbat
[root@mail linux-2.6.10]#


[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.10]# head -3 patch-2.6.11
diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS  2005-03-01 23:39:08 -08:00
+++ b/CREDITS  2005-03-01 23:39:08 -08:00

[root@mail linux-2.6.10]# patch -s -p1 --dry-run < patch-2.6.11 
[root@mail linux-2.6.10]#
[root@mail linux-2.6.10]# patch -s -p1  < patch-2.6.11         
[root@mail linux-2.6.10]#
[root@mail linux-2.6.10]# head -n5 Makefile
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 11                                                       
EXTRAVERSION =
NAME=Woozy Numbat
[root@mail linux-2.6.10]#


[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.10]# patch -s -p1 --dry-run < patch-2.6.12
[root@mail linux-2.6.10]#
[root@mail linux-2.6.10]# patch -s -p1  < patch-2.6.12       
[root@mail linux-2.6.10]#
[root@mail linux-2.6.10]# head -5 Makefile
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 12                                                               
EXTRAVERSION =
NAME=Woozy Numbat
[root@mail linux-2.6.10]#


[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.6.10]# patch -s -p1 --dry-run < patch-2.6.12.6
[root@mail linux-2.6.10]#
[root@mail linux-2.6.10]# patch -s -p1  < patch-2.6.12.6         
[root@mail linux-2.6.10]#
[root@mail linux-2.6.10]# head -n5 Makefile
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 12
EXTRAVERSION = .6
NAME=Woozy Numbat
[root@mail linux-2.6.10]#


[Copy to clipboard] [ - ]CODE:
[root@mail kernels]# mv linux-2.6.10 linux-2.6.12.6
[root@mail kernels]# ll -d linux-2.6.12.6
drwxrwxr-x  18 bob bob 4096 Sep 27 22:31 linux-2.6.12.6
[root@mail kernels]#
打好补丁不意味着就 ok 了,你还需要重新编译内核,也就是前面讲的一堆东西

gyjyxj 2007-10-31 16:32
九、patch-kernel 脚本分析

在 tarball 中有一个 scripts/ 目录,里面有一个 patch-kernel 脚本,用于自动升级内核。

当你要打的 patch 较多时,使用该脚本是一个不错的选择。

下面会对其内容逐行分析

[Copy to clipboard] [ - ]CODE:
#! /bin/sh
# Script to apply kernel patches.                                               
#  usage: patch-kernel [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]     
#    The source directory defaults to /usr/src/linux, and the patch             
#    directory defaults to the current directory.
# e.g.
#  scripts/patch-kernel . ..     
#      Update the kernel tree in the current directory using patches in the   
#      directory above to the latest Linus kernel
#  scripts/patch-kernel . .. -ac
#      Get the latest Linux kernel and patch it with the latest ac patch
#  scripts/patch-kernel . .. 2.4.9
#      Gets standard kernel 2.4.9
#  scripts/patch-kernel . .. 2.4.9 -ac
#      Gets 2.4.9 with latest ac patches
#  scripts/patch-kernel . .. 2.4.9 -ac11
#      Gets 2.4.9 with ac patch ac11
#  Note: It uses the patches relative to the Linus kernels, not the
#  ac to ac relative patches
#
# It determines the current kernel version from the top-level Makefile.
# It then looks for patches for the next sublevel in the patch directory.
# This is applied using "patch -p1 -s" from within the kernel directory.
# A check is then made for "*.rej" files to see if the patch was
# successful.  If it is, then all of the "*.orig" files are removed.
#
#      Nick Holloway <[email protected]>, 2nd January 1995.
#
# Added support for handling multiple types of compression. What includes
# gzip, bzip, bzip2, zip, compress, and plaintext.
#
#      Adam Sulmicki <[email protected]>, 1st January 1997.
#
# Added ability to stop at a given version number
# Put the full version number (i.e. 2.3.31) as the last parameter
#      Dave Gilbert <[email protected]>, 11th December 1999.

# Fixed previous patch so that if we are already at the correct version
# not to patch up.
#
# Added -ac option, use -ac or -ac9 (say) to stop at a particular version
#      Dave Gilbert <[email protected]>, 29th September 2001.
使用 patch-kernel 的前提是 Makefile 的 EXTRAVERSION 值必须为空

patch-kernel 脚本的功能就是自动给指定内核打上补丁,它有两种工作模式 :

1、一种是用于处理多个”增量型“的补丁,这通过 <stopversion> 选项控制

  但前提是你要准备从当前版本到 <stopversion> 所必须的每个”增量型“补丁。

2、一种是用于处理”差分型“的补丁,它是通过 -ac 指定。同样也有两种模式 :
   
    a)如果 -ac 后面没有任何参数,则自动升级到 <patch-dir> 下最高版本的那个补丁,且只打该补丁而已

    b)如果 -ac 后面带指定版本,则直接升级到该指定版本

patch-kernel 脚本的语法格式为 :patch-kernel <source-dir> <patch-dir> [stopversion] [-ac [stopversion]]

其中 <source-dir> 是指你要升级的内核源代码所在的目录。例如 :

1、patch-kernel . .. :表示在上级目录查找所有”增量型“ patch ,并自动升级到最高版本

2、patch-kernel . .. -ac :表示在上级目录查找所有 ”差分型“ patch ,并自动升级到最高版本

3、patch-kernel . .. 2.4.9 :表示使用上级目录的 patch-2.4.9 升级当前目录下的内核源代码

4、patch-kernel . .. 2.4.9 -ac :表示使用上级目录的最新版本的”差分补丁“文件升级当前目录下的内核源代码到 2.4.9

5、patch-kernel . .. 2.4.9 -ac9 :表示使用上级目录的 patch-2.4.9-ac*.* 文件升级当前内核到 2.4.9

[Copy to clipboard] [ - ]CODE:

# Set directories from arguments, or use defaults.

sourcedir=${1-/usr/src/linux}        # 注释 :sourcedir 默认返回 /usr/src/linux
patchdir=${2-.}                      # 注释 :patchdir 默认返回当前目录(.)
stopvers=${3-imnotaversion}          # 注释 :stopvers 默认返回 immotaversion

if [ "$1" = -h -o "$1" = --help -o ! -r "$sourcedir/Makefile" ]; then        # 注释 :这部分是对用户输入的命令进行语法的检查
cat << USAGE
usage: patch-kernel [-h] [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]
  The source directory defaults to /usr/src/linux, and
  the patch directory defaults to the current directory.
USAGE
exit 1
fi


[Copy to clipboard] [ - ]CODE:
# See if we have any -ac options    # 注释 :检查用户是否指定了 -ac 选项
for PARM in $*                        # 注释 :检查所有位置参数,
do
  case $PARM in                            # 如果 PARM 的值是匹配 '-ac*' ,则把 PARM 的值赋予变量 gotac
  -ac*)
    gotac=$PARM;                          # 如果没有发现任何 -ac* 字符串,则 gotac 的值为空

esac;
done

# 注释 :gotac 变量的值控制了 patch 的方式是”增量“还是”差分型“


[Copy to clipboard] [ - ]CODE:
下面的 findfile 函数用于在 <patch-dir> 指定的目录下查找任何名为 patch-x.y.z 的文件。

并能够根据常用的扩展名自动设置其解压方式,可以识别的扩展名有 :

1、.gz :使用 gunzip -dc 解压

2、.bz :使用 bunzip -dc 解压

3、.bz2 :使用 bunzip2 -dc 解压

4、.zip :使用 unzip -d 解压

5、.Z :使用 uncompress -c 解压

6、无扩展名。使用 cat 直接输出

7、如果都不是,则返回 1

# ---------------------------------------------------------------------------
# Find a file, first parameter is basename of file
# it tries many compression mechanisms and sets variables to say how to get it
findFile () {
  filebase=$1;

  if [ -r ${filebase}.gz ]; then
  ext=".gz"
  name="gzip"
  uncomp="gunzip -dc"
  elif [ -r ${filebase}.bz  ]; then
  ext=".bz"
    name="bzip"
  uncomp="bunzip -dc"
  elif [ -r ${filebase}.bz2 ]; then
  ext=".bz2"
  name="bzip2"
  uncomp="bunzip2 -dc"
  elif [ -r ${filebase}.zip ]; then
  ext=".zip"
  name="zip"
  uncomp="unzip -d"
  elif [ -r ${filebase}.Z ]; then
  ext=".Z"
  name="uncompress"
  uncomp="uncompress -c"
  elif [ -r ${filebase} ]; then
  ext=""
  name="plaintext"
  uncomp="cat"
  else
  return 1;
fi

  return 0;
}


[Copy to clipboard] [ - ]CODE:
# ---------------------------------------------------------------------------
# Apply a patch and check it goes in cleanly
# First param is patch name (e.g. patch-2.4.9-ac5) - without path or extension

下面的 applyPatch()函数的作用是 :

1、首先打印一个提示信息

2、接下来是解压和打补丁

3、如果 patch 成功(返回0),则输出 “done"

4、否则输出 ”failed,Cleanup up yourself“ ,并返回 1

5、再检查 $sourcedir 下是否存在以 .rej 结尾的文件(含隐藏文件),如果有则打印一个信息 “Aborting.Reject files found"

  表示有某些 hunk 没有成功 apply ,并返回 1

6、如果没有找到 .rej 文件,则表示整个 patch 成功地 apply 了。再查找是否有 .orig 文件。这些文件是 patch 在工作时

            自动备份的源文件(见 patch 的 --backup-if-mismatch)并删除它们 ,最后返回 0 的 exit status

applyPatch () {
  echo -n "Applying $1 (${name})... "
  if $uncomp ${patchdir}/$1${ext} | patch -p1 -s -N -E -d $sourcedir
  then
    echo "done."
  else
    echo "failed.  Clean up yourself."
    return 1;
  fi
  if [ "`find $sourcedir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ]
  then
    echo "Aborting.  Reject files found."
    return 1;
  fi
  # Remove backup files
  find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} /;

  return 0;
}


[Copy to clipboard] [ - ]CODE:


下面开始正式的打补丁流程。

首先需要找出当前的内核版本,方法是在 Makefile 中找出 VERSION、PATCHLEVEL、SUBLEVEL、EXTRAVERSION 行

并去掉等号两边的空格,然后执行它们。

# set current VERSION, PATCHLEVEL, SUBLEVEL, EXTERVERSION
eval `sed -n -e 's/^/([A-Z]*/) = /([0-9]*/)$//1=/2/p' -e 's/^/([A-Z]*/) = /(-[-a-z0-9]*/)$//1=/2/p' $sourcedir/Makefile`


if [ -z "$VERSION" -o -z "$PATCHLEVEL" -o -z "$SUBLEVEL" ]
then
    echo "unable to determine current kernel version" >&2
    exit 1
fi

如果 VERSION、PATCHLEVEL、SUBLEVEL 中的任意一个为空则报错

补充 :EXTRAVERSION 可以为空,而且默认就是空


[Copy to clipboard] [ - ]CODE:

echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL${EXTRAVERSION}"

# 注释 :输出当前的内核版本

if [ x$EXTRAVERSION != "x" ]
then
  echo "I'm sorry but patch-kernel can't work with a kernel source tree that is not a base version"
exit 1;
fi

如果 $EXTRAVERSION 变量的值不为空,则输出上面的提示信息并退出

表示 patch-kernel 这个脚本只能用于”干净“的版本,也就是你在 kernel.org 下载且没有自己编译过的版本


[Copy to clipboard] [ - ]CODE:
下面是一个”无限循环“, ':' 在 bash 中代表 true 的含义,类似于 true 命令

补充 :这部分是针对 SUBLEVEL 的升级的,而不是针对 EXTRAVERSION 的升级的。也就是说从 2.4.5 升级到 2.4.9 这样的

对于 2.4.35.1 升级到 2.4.35.3 这种情况不会执行下面的 while 部分代码

while :
do
    CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"        # 注释 :把 VERSION、PATCHLEVEL、SUBLEVEL 的值合并在一起赋予变量 CURRENTVERSION
    if [ $stopvers = $CURRENTFULLVERSION ]                        # 注释 :如果 stopvers 变量的值刚好等于 CURRENTVERSION  的值,则
    then       
        echo "Stoping at $CURRENTFULLVERSION base as requested."        # 注释 :表示当前版本刚好就是要升级的目标版本,不需要再执行后面的工作了。
        break                                                            # 注释 :这里退出 while 循环
    fi
                                                               
    SUBLEVEL=`expr $SUBLEVEL + 1`                                # 注释 :如果目标版本不等于当前版本,则先把 SUBLEVEL 的值加1
    FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"                # 注释 :把新的 SUBLEVEL、VERSION、PATCHLEVEL 的值合并在一起,赋予 FULLVERSION         

    patch=patch-$FULLVERSION                                    # 注释 :设置 patch 文件的名称为 patch-$FULLVERSION

  # See if the file exists and find extension                    # 注释 :然后调用上面的 findfile 函数到 $patchdir 下查找有无该 patch 文件
  findFile $patchdir/${patch} || break                                    如果没有则跳出 while 循环

    # Apply the patch and check all is OK                        # 注释 :如果找到 patch 文件的话,接下来就是打补丁了,调用的是上面的 applypatch 函数
    applyPatch $patch || break
done

上面之所以要做成无限循环是因为要实现自动按顺序 apply 多个补丁的功能。例如当前版本是 2.34.2 ,stopvers 是 2.34.6

且 patchdir 下有 2.34.3 ,2.34.4 ,2.34,5 , 2.34.6 这4个补丁文件,则流程如下 ;

1、首先判断当前版本 (2.34.2)!= 2.34.6 则查找 patchdir 下的 patch-2.34.3.xxx 文件(xxx 就是 finfile 中指定的那些扩展名)

2、并 apply 该补丁,这时内核的 SUBLEVEL 将会变成 2.34.3

3、再次判断 2.34.3 !=  2.34.6 ,在 patchdir 下查找 2.34.4 补丁,如果找到则 apply 该补丁

4、依此类推,直到 SUBLEVEL = 2.34.6 (也就是 apply patch-2.34.6.xxx 补丁后)

5、这时 stopvers 等于 CURRENTVERSION 则跳出 while 循环,apply 多个补丁的工作也就完成了

补充 :所以这要求你事先得把多个 patch 放在 pathdir 目录下


[Copy to clipboard] [ - ]CODE:

# 注释 :-ac 功能

if [ x$gotac != x ]; then                                                    # 注释 :如果 gotac 变量的值不为空,则
  # Out great user wants the -ac patches
# They could have done -ac (get latest) or -acxx where xx=version they want   
if [ $gotac == "-ac" ]                                                                # 注释 :如果 gotac 变量的值等于 "-ac" ,则
then
  # They want the latest version
  HIGHESTPATCH=0                                                                            # 注释 :将 HIGHIEST 变量的值设置为 0
  for PATCHNAMES in $patchdir/patch-${CURRENTFULLVERSION}-ac*/.*                            # 注释 :在 patchdir 下查找类似 patch-x.y.z-ac<N>.* 的文件
  do
  ACVALUE=`echo $PATCHNAMES | sed -e 's/^.*patch-[0-9.]*-ac/([0-9]*/).*//1/'`                # 注释:并尝试取出文件名中 ac 后面的 <N>,赋予变量 ACVALUE
  # Check it is actually a recognised patch type
  findFile $patchdir/patch-${CURRENTFULLVERSION}-ac${ACVALUE} || break                        # 注释 :用 findfile 函数判断该文件的类型和解压方式

    if [ $ACVALUE -gt $HIGHESTPATCH ]                                                          # 注释 :如果 ACVALUE 的值大于 HIGHESTPATCH 的值     
  then
    HIGHESTPATCH=$ACVALUE                                                                        # 则把 ACVALUE 的值给 HIGHESTPATCH 变量
    fi
  done

  if [ $HIGHESTPATCH -ne 0 ]                                                                    # 注释 :如果最终找到一个 ac 文件,则
  then       
  findFile $patchdir/patch-${CURRENTFULLVERSION}-ac${HIGHESTPATCH} || break                        # 用 findfile 判断其类型和解压方式
  applyPatch patch-${CURRENTFULLVERSION}-ac${HIGHESTPATCH}                                        # 注释 :并调用 applypatch 打上该补丁
  else
    echo "No ac patches found"                                                                  # 如果最终一个 ac 文件都找不到则报错
  fi
else                                                                                    # 注释 :如果 gotac 变量的值不为空,则表示用户指定了 ac 版本
  # They want an exact version
  findFile $patchdir/patch-${CURRENTFULLVERSION}${gotac} || {                                # 注释 :首先用 findfile 查找该 ac 文件的类型和解压方式
    echo "Sorry, I couldn't find the $gotac patch for $CURRENTFULLVERSION.  Hohum."          # 如果 findfile 失败,则打印一个错误信息并退出
  exit 1
  }
  applyPatch patch-${CURRENTFULLVERSION}${gotac}                                            # 注释 :再调用 applypatch 打上该补丁
fi
fi

补充 :可以看到 patch-kernel 并不负责修改目录的名称和执行剩下的 make xxx 操作

补充 ;也可以看到如果要从 2.4.35 升级到 2.4.35.3 ,需要把 patch-2.4.35.3.bz2 改名为 patch-2.4.35-ac3.gz ,然后使用 patch-kernel . .. 2.4.35 -ac3

gyjyxj 2007-10-31 16:32
十、patch-kernel 脚本应用实例

当前版本

[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.4.34.4]# head -n 4 Makefile
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 34
EXTRAVERSION =
[root@mail linux-2.4.34.4]#               
现有补丁文件

[Copy to clipboard] [ - ]CODE:
[root@mail src]# ll patch*
-rw-r--r--    1 root    root        7782 Sep 25 00:16 patch-2.4.34.4
-rw-r--r--    1 root    root      1218800 Sep 25 00:24 patch-2.4.35
-rw-r--r--    1 root    root        8098 Sep 25 00:24 patch-2.4.35-ac1                # 注释 :这两个实际上是用不到的
-rw-r--r--    1 root    root        8972 Sep 25 00:24 patch-2.4.35-ac2
-rw-r--r--    1 root    root        10604 Sep 25 00:13 patch-2.4.35-ac3
[root@mail src]#
使用 patch-kernel 升级到 2.4.35 版本

[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.4.34.4]# scripts/patch-kernel . .. 2.4.35
Current kernel version is 2.4.34
Applying patch-2.4.35 (plaintext)... done.
Stoping at 2.4.35 base as requested.
[root@mail linux-2.4.34.4]#
直接升级到 2.4.35.3

[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.4.34.4]# scripts/patch-kernel . .. 2.4.35 -ac3
Current kernel version is 2.4.35
Stoping at 2.4.35 base as requested.
Applying patch-2.4.35-ac3 (plaintext)... done.
[root@mail linux-2.4.34.4]#


[Copy to clipboard] [ - ]CODE:
[root@mail linux-2.4.34.4]# head -n 4 Makefile
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 35
EXTRAVERSION = .3
[root@mail linux-2.4.34.4]#
可以看到 EXTRAVERSION 变成了 .3 了,也就是说明成功了。

你可能感兴趣的:([转帖] 内核编译学习笔记之完整篇(v1.1.1))