【转】如何编译一个内核 - Ubuntu方式

如何编译一个内核 - Ubuntu方式

每一个Linux发行版都有自己专门的工具去构建自定义的内核. 本文主要介绍在Ubuntu平台上编译内核, 如何从www.kernel.org(也叫vanilla kernel)获得最新且未改动的内核源代码来构建一个自定义的内核, 这样你可以使用自己的内核而不是发行版的内核, 另外也介绍了如何给内核打补丁, 从而方便增加新的功能.

下面的工作我都在Ubuntu 6.10 Server ("Edgy Eft")和Ubuntu 6.06 Desktop ("Dapper Drake")上经过了测试.

我想首先要说的是文章中构建自定义内核的方式不是唯一的, 还有许多其它的方式, 这不过是我习惯的方式. 我不能保证使用后不会出现任何问题.

1. 预备工作
我推荐使用root用户执行下面所有的步骤. 如果你还没有创建root登陆口令, 请运行下面的命令:
sudo passwd root

然后, 以root身份登陆:
su

如果你想使用一般用户来替代root用户, 记住在本文所有命令前输入sudo, 比如当我运行
apt-get update

你需要运行下面的命令来替代, 等.
sudo apt-get update

1.1 Ubuntu 6.10上的/bin/sh ("Edgy Eft")
在Ubuntu 6.10, /bin/sh缺省是一个链接到/bin/dash的字符链接. 当你编译软件源代码的时候, /bin/dash似乎还存在问题. 至少我已经遇到了一些问题. 所以我把/bin/sh链接到了/bin/bash.

如果你使用Ubuntu 6.10, 现在你可以运行:
rm -f /bin/sh
ln -s /bin/bash /bin/sh

2 安装必需的软件包 (为内核编译做准备)
首先我们升级软件(包)库:
apt-get update

然后我们安装所有需要的软件包:
apt-get install kernel-package libncurses5-dev fakeroot wget bzip2

3 下载内核源代码
接下来我们下载需要的内核到/usr/src目录(去www.kernel.org网站下载你需要的内核版本, 比如. linux-2.6.18.1tar.bz2(你可以从这里下载所有的2.6内核: http://www.kernel.org/pub/linux/kernel/v2.6/). 然后下载到/usr/src目录:
cd /usr/src
wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.1.tar.bz2

然后解压内核源代码, 创建一个指向内核源代码目录的linux字符链接:
tar xjf linux-2.6.18.1.tar.bz2
ln -s linux-2.6.18.1 linux
cd /usr/src/linux

4 给内核源代码打补丁(可选)
有时你的缺省内核不支持新买的设备, 你需要安装新的驱动. 或者你需要使用虚拟技术或其它高级的技术, 而这些现有的内核都不支持. 这样情况下你需要给给内核源代码打补丁(当然补丁已经发布..)

现在我们假设你已经下载需要的补丁(以下例子我叫它patch.bz2)到/usr/src. 运行下面的命令给内核源代码直接打上补丁(你的用户必须位于/usr/src/linux目录):
bzip2 -dc /usr/src/patch.bz2 | patch -p1 --dry-run
bzip2 -dc /usr/src/patch.bz2 | patch -p1

第一个命令用于测试, 对内核没有任何影响. 如果没有显示错误, 你可以运行第二个命令给内核打补丁. 如果第一个命令有误, 请务继续的操作!

你也能够通过内核的prepatches方式打补丁. 比如, 如果你需要一个功能, 而这个功能仅存在于2.6.19-rc4中, 正式完整的内核版本仍没有发布, 而patch-2.6.19-rc4.biz2已经发布. 你可以把这个补丁打到2.6.18的内核源代码中, 但请不要达到2.6.18.1或2.6.18.2, 等. 这个规则在接下来的网页中注明: http://kernel.org/patchtypes/pre.html

prepatches等同于linux中的测试发行; 他们位于存档的测试目录中, 我们可以使用patch(1)工具对上一个完整发行版(版本号分三部分)打补丁(例如, 2.6.12-rc4 prepatch只可以给2.6.11内核源代码打补丁, 而不是2.6.11.10.)

所以如果你想编译2.6.19-rc4内核, 你必须在步骤3.1下载2.6.18(http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2)替代2.6.18.1内核源代码!

下面是如何给2.6.18打上2.6.19-rc4补丁:
cd /usr/src
wget http://www.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.19-rc4.bz2
cd /usr/src/linux
bzip2 -dc /usr/src/patch-2.6.19-rc4.bz2 | patch -p1 --dry-run
bzip2 -dc /usr/src/patch-2.6.19-rc4.bz2 | patch -p1

5. 配置内核
使用当前工作内核的配置文件做为新内核配置文件的基础是一个很好的主意. 因此我们拷贝已存的配置文件到/usr/src/linux:
cp /boot/config-`uname -r` ./.config

然后运行
make menuconfig

然后我们看到内核的配置菜单. 移动绿色光标到 Load an Alternate Configuration File 行后选择.config文件(包含了当前工作内核的配置)做为配置文件:

然后浏览内核配置菜单, 选择你需要的功能. 完成配置后, 选择Exit, 回答下面的问题(Do you wish to save your new kernel configuration? 你希望保存新的内核配置吗?), 选择Yes:

6 构建内核
执行下面命令来构建内核:
make-kpkg clean
fakeroot make-kpkg --initrd --append-to-version=-custom -j4 kernel_image kernel_headers

如果要进行交叉编译,可以进行确定架构机器上的编译。
fakeroot make-kpkg --initrd --append-to-version=-custom -j4 --arch i386 kernel_image kernel_headers (比如在64位机器上编译32位的内核)

在--append-to-version= 后面你可以写上任何字符串来区别内核版本, 但是必须以" - "符号开始而且后面不包括任何空格.

保持耐心, 内核编译需要一定时间, 主要看你的内核配置和处理器速度.

7 安装新内核
在成功构建内核后, 你在/usr/src目录能发现两个.deb软件包.
cd /usr/src
ls -l

在我的测试系统上, 他们分别名为 linux-image-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb (包含了实际的内核) 和 linux-headers-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb (包含了需要的文件, 用于以后需要编译额外的内核模块). 我是这样安装的:
dpkg -i linux-image-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb
dpkg -i linux-headers-2.6.18.1-custom_2.6.18.1-custom-10.00.Custom_i386.deb

(现在你甚至能够拷贝这两个.deb文件到其它的Ubuntu系统, 通过上面的方式安装. 你将不再需要编译内核.)

然后检查 /boot/grub/menu.lst文件, 现在你将能发现新内核使用的两个引导配置块:
vi /boot/grub/menu.lst

在我测试系统上已经添加好的引导配置块是这样的:
title Ubuntu, kernel 2.6.18.1-custom
root (hd0,0)
kernel /boot/vmlinuz-2.6.18.1-custom root=/dev/sda1 ro quiet splash
initrd /boot/initrd.img-2.6.18.1-custom
savedefault
boot

title Ubuntu, kernel 2.6.18.1-custom (recovery mode)
root (hd0,0)
kernel /boot/vmlinuz-2.6.18.1-custom root=/dev/sda1 ro single
initrd /boot/initrd.img-2.6.18.1-custom
boot

现在重启系统:
shutdown -r now

如果一切进展顺利, 你的新内核正常工作. 你还可以通过运行下面命令来检查新内核是否运行:
uname -r

这将会显示如:
2.6.18.1-custom

如果系统没有起来, 重启一下, 你会看到:

ESC进入GRUB菜单:

选择你以前的内核启动系统, 现在你能再次尝试编译新的工作内核. 不要忘记从/boot/grub/menu.1st文件中移去不需要的引导内核信息.


 

=======================================================================================================

=======================================================================================================

======================================================另一篇=====================================================

=======================================================================================================


编译 Linux2.6 内核总结 在X86, Ubuntu 上编译Linux2.6内核,总结如下:

基础知识

在介绍如何编译内核之前, 需要对内核相关概念有一定的了解. 关于Linux kernel的介绍浩如烟海, 这里只介绍系统中相关的目录, 文件及命令.

/boot

/boot/vmlinuz-<version>        : 用于启动的压缩内核镜像, 它也就是/arch/<arch>/boot中的压缩镜像.
/boot/system.map-<version>  : 存储内核符号地址.
/boot/initrd.img-<version>     : 初始化RAM硬盘时, 用来存储挂载根文件系统所需的模块.
/boot/grub/menu.lst                : grub的配置文件. (不同的发行版中它可能位于不同位置.


/lib/modules

该目录包含了内核模块及其他文件. 注意, modules中一般会有多个目录: 系统自带的内核模块在这里, 你编译自己的内核模块后, 它们也会被安装到这里. 不同的目录由内核版本号来区分. 即modules里目录的名称是内核版本号. (使用$ uname -r 可知当前系统内核所用的模块位于哪个目录).

/lib/modules/<kernel-version>/build
储存为该版本的内核编译新模块所需的文件. 包括Makefile, .config, module.symVers(模块符号信息), 内核头文件(位于include/, include/asm/中)

/lib/modules/<kernel-version>/kernel
储存内核目标文件(以.ko为后缀). 它的目录组织和内核源代码中kernel的目录组织相同.

/lib/modules/<kernel-version>/中:
modules.alias       : 模块别名定义. 模块加载工具使用它来加载相应的模块.
modules.dep        : 定义了模块间的依赖关系.
modules.symbols : 指定符号属于哪个模块.

这些文件都是文本文件, 可以查看它们.

$ uname -r

uname(1)被用来查看系统信息, 这里对我们有用的是它的"-r"选项, 它显示内核版本信息.


下载内核, 验证签名, 解压缩
http://www.kernel.org/pub/linux/kernel/下载最新版本的2.6内核. 速度还比较快. 这里以linux-2.6.17.13为例:

1, 下载内核压缩包

bzip2格式比gzip压缩效率更高, 一般就下载bz2的压缩包. 下载了内核压缩包之后, 还可下载对应的sign文件. 它被用来验证内核压缩文档的openPGP签名. 详细信息可参考这里.

wget -c http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.13.tar.bz2
wget -c http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.13.tar.bz2.sign

2, 验证签名

首先从pgp的服务器获取签名公匙, linux内核包的公匙编号是0x517D0F0E. 再利用sign文件来验证.bz2压缩包的签名.  如果输出中有类似gpg: Good signature from "Linux Kernel Archives Verification Key <ftpadmin@kernel.org>" 的内容, 说明该包是有效的. 后面给出的警告信息可以忽略.

gpg --keyserver wwwkeys.pgp.net --recv-keys 0x517D0F0E
gpg --verify linux-2.6.17.13.tar.bz2.sign linux-2.6.17.13.tar.bz2

GPG签名只是保证镜像网站提供的压缩包和kernel.org所提供的是相同的, 如果你在kernel.org下载, 不需要验证签名.

3, 解压缩

解压缩之前, 有个问题值得思考: 要将压缩包解压到何处? 即要在哪个目录进行Linux内核源代码的编译? 

内核源码树的README中有这样一段话:

Do NOT use the /usr/src/linux area! This area has a (usually incomplete) set of kernel headers that are used by the library header files.  They should match the library, and not get messed up by whatever the kernel-du-jour happens to be.

实 际上, 在我的Ubuntu系统中, /usr/src/ 目录中最初是没有linux目录的. 你可以在/usr/src中新建一个目录, 用内核版本命名, 比如/usr/src/linux-2.6.17.13. 这样, 即便之前在/usr/src中安装了linux的头文件, 也不会对它们造成影响.

我采用的方法是: 在/usr/local/src/kernel目录中进行.

编译内核时候, 若在make 后添加 "O=<complete_dir>"将会使生成的目标文件(包括.config)被放置到指定的目录. 否则, 生成的目标文件默认地被放到内核源码目录. 我们就采用默认的方法. 这是安全的.

4, 打补丁

对于kernel.org中的内核, 我个人认为没必要下载patch, 再打补丁. 费那事干嘛, 直接下载bz2包不就行了. 特定的补丁只能针对紧随其前的一个版本. 比如你想从2.6.17.1升级到2.6.17.13. 你得打12次补丁, 忒麻烦了.

但 是, 有时候需要对"官方内核"添加补丁, 以支持特定的系统. 比如ARMLinux, 它往往不是发布完整的内核, 而是发布针对特定版本的补丁包. 这种情况下就要知道如何打补丁了. 方法很简单: 把补丁下载, 解压. 得到patch-<version>. 将它放到解压后的内核目录树的父目录中(也就是补丁和内核目录在同一目录). 然后cd到内核目录树中运行:

patch -p1 <../patch-<version>


配置内核
1, 前提: 构建编译环境

显然, 需要make, gcc等工具, 在Ubuntu中, 只需一条简单命令就可安装所有的源代码编译工具: 
apt-get install build-essential

当然, 如果你的内核是要安装到不同体系结构的目标系统中, 还需要构建cross编译环境.

2, 内核配置工具介绍

Linux提供了多种内核配置工具, 最基础的是 make config, 它列出每个编译选项, 而且是基于文本的, 一般不用它.

menuconfig (make menuconfig)
menuconfig是比较主流的配置工具, 它需要curse库的支持, 在Ubuntu中默认是没有的, 先安装它: 
apt-get install libncurses5-dev 

xconfig (make xconfig)
xconfig基于X11, 使用qt库, 在Ubuntu中先安装qt库: 
# apt-get install libqt3-headers libqt3-mt-dev

3, 内核配置相关

.config配置文件
在内核树的根目录中,有一个.config文件,它记录了内核的配置选项,可直接对它进行修改,再运行(若.config不存在,对内核进行配置后会生成它,这种情况下当然不能开始就运行oldconfig). 实际上, 如果你手头有合适的 .config 文件, 可以运行 make oldconfig  直接按 .config 的内容来配置 
$ sudo make oldconfig

对内核的配置都是围绕 .config 来展开的.  即便开始 .config 文件不存在, 进行配置后会创造它. 

其实可以直接在menuconfig中加载已有的配置文件, 不要将它改名为.config. 否则完成配置, 退出menuconfig时会提示你运行 make mrproper. 上面提到的方法只是比较适合于oldconfig!

make相关命令
make oldconfig    : 基于已有的.config进行配置, 若有新的符号, 它将询问用户.
make defconfig    : 按默认选项对内核进行配置(386的默认配置是Linus做的).
make allnoconfig : 除必须的选项外, 其它选项一律不选. (常用于嵌入式系统).

make clean        : 删除生成的目标文件, 往往用它来实现对驱动的重新编译.
make mrproper : 删除包括.config在内的生成的目标文件. 

可以查看内核源码树中的README和Makefile了解上述配置方法.

4, 开始配置

1, 修改Makefile (可选)
在Makefile中, 有这样的内容:

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 16
EXTRAVERSION = .20
NAME=Sliding Snow Leopard

我们在编译内核之前, 可以先修改Makefile中的版本信息(一般是修改EXTRAVERSION, 比如EXTRAVERSION =-zp). 这样就能将自己编译的内核同别人编译的相同版本内核区分开来. 修改, 编译之后, 可使用 $ uname -r 查看内核版本信息.

但实际上, 从2.6.8的版本起可在内核版本号后面添加个性化字符串. 所以也就没有必要修改Makefile了: ()  Local version - append to kernel release

如果你即修改了Makefile中的EXTRAVERSION, 又在配置时定义了local version. 那么local version所定义的字符串将位于末尾, 紧跟在EXTRAVERSION的值之后.

另外, 如果要用到ccache, 也需要修改Makefile. 参考后面的内容!

2, 准备一个.config文件.
内核配置选项众多, 一个个去配置相当麻烦. 建议使用手头已有的配置文件. 如果你手头没有,  有多种方法获得它:

(1) 使用make defconfig将在源码树的根目录得到.config. 
(2) 使用当前系统内核的配置文件, 一般位于/boot目录中. 它的名称并不是.config.
(3) 使用别的发行版提供的配置文件(网上去下载).

slackware的.config是个不错的起点. 在它的配置文件基础上作出适合自己系统的修改, 比较方便.  也可以拷贝发行版提供商的.config文件.

3, 建议配置步骤:
(1) 将配置文件(不要将它命名为.config!)拷贝到内核源码树根目录.
(2) make menuconfig, 然后将上述的配置文件加载进去.
(3) 配置完成后, 将生成的配置文件备份(.config, 也可以在menuconfig中指定生成的配置文件名).


配置选项是最头疼的问题
: 配置时候注意驱动的问题, 尤其是网络驱动. 使用 pppoe 的话, 要选上 ppp 相关的选项. 网卡驱动也要注意, 我刚开始配置的时候, 只加上了 lspci | grep Ethernet 对应的网卡, 但是重启后找不到eth0, 一怒之下, 把所有的1000M 网卡驱动都选为模块. 总算成功. 以后有空仔细看看. 再就是声卡驱动也要注意.可参考我blog里另一篇文章:配置2.6内核选项注解

也可以到Linux KernelConfiguration Archive看一看, 虽然它里面的内容与图形化配置工具中的help大同小异. 


编译内核

配置完成后,就要进行编译了。编译2.6的内核很简单,Makefile自动检测依赖性,产生编译文件(bzImage),你也不用另外编译modules!. 只需运行:
$ make
 
使用make编译内核的技巧     

1, 可以略去编译信息(但仍能看到warning, error)
$sudo make > /dev/null
$sudo make -j2 > /dev/null

2, 加速编译过程.
(1) 可以使用 $ make -j<n> . 其中n = 2 * cpu的个数. 对于一般的单CPU系统, 通常用 $ make -j2 . 为编译过程分配2个人物, 这样在进行磁盘I/O时候, CPU就不会空闲了. 一般这个选项可以将速度提高10%左右.
 
(2) 还可以使用
ccache来提高编译速度.  Debian/Ubuntu系统中默认没有安装, 首先安装它: $ sudo apt-get install ccache . 然后更改内核根目录的Makefile, 将CC和HOSTCC变量定义前添加ccache: 
CC               = $(CROSS_COMPILE)gcc
HOSTCC      = gcc
更改为:
CC               = ccache $(CROSS_COMPILE)gcc
HOSTCC      = ccache gcc


编译生成的文件介绍

vmlinux   :  未经压缩的原始linux内核镜像.
/arch/<arch>/boot/zImage(bzImage):  使用zlib压缩后的内核镜像.
注意, 不同的体系结构对压缩后内核镜像的默认命名不同, 比如arm的是zImage, 而i386的是bzImage. (z表示zlib, bz表示"big zlib", 而非bzip2!)


安装内核
编译完成后, 在 arch/i386/boot目录中会有bzImage映象文件.

安装内核步骤如下: 
(1)在/boot目录下新建mynewkernel目录,并将bzImage拷贝到/boot/mynewkernel目录下:
$ sudo cp arch/i386/boot/bzImage /boot/mynewkernel

(2)更改/boot/mynewkernel中bzImage的名字
$ sudo mv bzImage vmlinuz-2.6.17.13

(3)备份、修改grub配置文件
$sudo cp /boot/grub/menu.lst menu.lst.origin

修改menu.list,加入以下内容(从既有的menu.list中相关的内容拷贝):
title        zp, make defconfig, 2.6.17.13
root        (hd0,2)
kernel        /boot/mynewkernel/vmlinuz-2.6.17.13 root=/dev/sda3 ro quiet splash
savedefault
boot


(4)安装模块:

$sudo make modules_install

reboot, 在grub启动菜单中选择新内核启动...


参考资料
(1) Linux-kernel-tree/README
(2) kernel-build-howto
(3) 关于ccache, 可参考IBM developworks上的这篇介绍. 

-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
也可以用:
make && make modules && make modules_install && make install 

参考:http://forum.ubuntu.org.cn/viewtopic.php?t=46958&highlight=%E7%BC%96%E8%AF%91%E5%86%85%E6%A0%B8


-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------


Linux(Ubuntu)学习札记 /liaxiz 发表于2007-06-11, 20:26         
经过两天一夜的实践,终于成功编译内核2.6.21.4,经历了五次的失败,一次次的在考验着我的耐性,还好,坚持下来了,便将这两天的经历书于此处,与所有被初次编译内核的困难折磨过的朋友们共勉。
        
        本次实践最大的收获有三点:
        1. 首次尝试到了什么是真正的定制。linu把所有的自由赋予了使用者,我们应该珍惜这份尊重,并尽情地享受这种自由。内核中许多模块许多是根本不需要的,还有一些是默认的设置不合理的,都可以根据自己的具体情况更改。
        2. 以前遗留的问题得到了解决。现在我的刻录机能读盘了,在编译内核的时候,去掉了scsi模拟ide设备的模块,这样,2.6以后的内核就可以正常识别刻录机了。
        3. 意外的惊喜。本来在2.6.20.16下,使用的是Ubuntu带得显卡驱动,但是无论怎么调,刷新率都到不了60HZ,并且,如果使用这个 xorg.conf,新内核根本无法进入Xwindows,所以,我又把xorg.conf改回刚装好Ubuntu时没换驱动时的状态,结果新内核进入了 Xwindows,并且刷新率为60HZ,真是意外的惊喜,新内核的兼容性可是好。
         
        现在反省下为什么会失败那么多次:
        1.  网上的编译方法得版本太多了,随着内核的升级,有些版本 就太老了,不免发生了些逻辑上的混乱。
        2,  第一次编译内核,可是不知深浅,在配置内核的时候,有些模块删掉了,结果无法启动。

        编译步骤如下:
        1. 到官方网站下载内核 http://kernel.org/pub/linux/kernel/v2.6
            解包到 /usr/src 目录下,命令:
                   sudo tar -xvjf linux-2.6.21.4.tar.bz2
        2. 进入到编译目录中,此后的所有操作均在该目录下进行。
                   cd /usr/src/linux-2.6.21.4/
            配置内核,推荐使用xconfig,非常直观,图形界面,需要Qt,非常稳定,编译了六次没有出现意外。
                   sudo make xconfig
            选项很多,不明白的,默认就可以了,可参考文章:
                   http://lamp.linux.gov.cn/Linux/kernel_options.html
            配置好了,保存,在目录中会创建.config文件,编译的时候是根据此文件进行。
        3.开始编译:
           自2.6内核开始,就不用make dep了,依赖关系会自动维护,并且命令也减少了,以往是:
                   sudo make dep 
                   sudo make clean 
                   sudo make bzImage 
                   sudo make modules 
                   sudo bzImage install
                   sudo make modules_install
            现在仅需要:
                   sudo make              //时间会很长
                   sudo make modules_install
                   sudo make install    //有些资料显示,这个命令可以自动更改/boot/grub/menu.lst,可是我的实践中并没有成功,而且还有错误
            本来到此因改结束了,可是在sudo make install后,并没有产生预期的结果,/boot/grub/menu.lst并没有改动,因此还得执行下述命令:
                   sudo mkinitramfs -0 /boot/initrd.img-2.6.21.4 2.6.21.4
                   sudo gedit /boot/grub/menu.lst
            加入如下内容:
                   title        Ubuntu, kernel 2.6.21.4
                   root        (hd0,6)
                   kernel        /vmlinuz-2.6.21.4 root=UUID=2f48ce41-ead0-463e-af93-b0503de13273 ro quiet splash
                   initrd       /initrd.img-2.6.21.4
                   savedefault
             绿色的字体是根据需要更改的,其他的是复制的别的核心启动项的。
             
        到此,编译,安装结束,重新启动,就可以进入新核心的系统了。因为这个核心太新了,源里还没有它的头文件,虚拟机就没法用了,等以后升级吧。

       为了这一个问题,被“残酷”地折磨了将近30个小时,但心情还是蛮愉快的。linux让我们能在痛苦中体会自由带来的乐趣,也可谓之奇。希望每一个编译过内核的朋友都能享受这一过程。  原文地址http://liaxiz.bloghome.cn/posts/97402.html
posted @ 2012-02-21 17:28  Jack204  阅读(7704)  评论(0编辑  收藏  举报