第26章、Linux 核心编译与管理

26.1. 编译前的任务:认识核心与取得核心原始码
我们在第一章里面就谈过 Linux 其实指的是核心!这个『核心 (kernel)』是整个操作系统的最底层,他负责了整个硬件的驱动,以及提供各种系统所需的核心功能,包括防火墙机制、是否支持 LVM 或 Quota 等文件系统等等,这些都是核心所负责的!所以在第二十章的开机流程中,我们也会看到 MBR 内的 loader 加载核心档案来驱动整个系统的硬件! 也就是说,如果你的核心不认识某个最新的硬件,那么该硬件也就无法被驱动,你当然也就无法使用该硬件!

26.1.1. 什么是核心 (Kernel)
这已经是整个 Linux 基础的最后一篇了,所以,底下这些数据你应该都要『很有概念』才行~ 不能只是『好像有印象』,就复习一下核心的相关知识吧!

一、Kernel
还让得我们在第十一章的 BASH shell 提到过:计算机真正在工作的东西其实是『硬件』, 例如数值运算要使用到 CPU、数据储存要使用到硬盘、图形显示会用到显示适配器、音乐发声要有音效芯片、连接 Internet 可能需要网络卡等等。那么如何控制这些硬件呢?那就是核心的工作了!也就是说,你所希望计算机帮你达成的各项工作, 都需要透过『核心』的帮助才行!当然如果你想要达成的工作是核心所没有提供的, 那么你自然就没有办法透过核心来控制计算机使他工作!
举例来说,如果你想要有某个网络功能 (例如核心防火墙机制) ,但是你的核心偏偏忘让加进去这项功能, 那么不论你如何『卖力』的设定该网络套件,很抱歉!不来电!换句话说,你想要让计算机进行的工作,都必须要『核心有支持』才可以 !这个标准不论在 Windows 或 Linux 这几个操作系统上都相同!如果有一个人开发出来一个『全新的硬件』,目前的核心不论 Windows 或 Linux 都不支持,那么不论你用什么系统!这个硬件都是英雄无用武之地! 那么是否了解了『核心』的重要了呢?所以我们才需要来了解一下如何编译我们的核心!
那么核心到底是什么啊?其实核心就是系统上面的一个档案而已, 这个档案包含了驱动主机各项硬件的侦测程序与驱动模块。在第二十章的开机流程分析中,我们也提到这个档案被读入主存储器的时机, 当系统读完 BIOS 并加载 MBR 内的开机管理程序后,就能够加载核心到内存当中。然后核心开始侦测硬件, 挂载根目录并取得核心模块来驱动所有的硬件,之后呼叫 /sbin/init 就能够依序启动所有系统所需要的服务了!
这个核心档案通常被放置成 /boot/vmlinuz ,不过也不见得, 因为一部主机上面可以拥有多个核心档案,只是开机的时候仅能选择一个来加载而已。 甚至我们也可以在一个 distribution 上面放置多个核心,然后以这些核心来做成多重引导!

二、核心模块 (kernel module) 的用途
既然核心档案都已经包含了硬件侦测与驱动模块,那么什么是核心模块啊?要注意的是, 现在的硬件更新速度太快了,如果我的核心比较旧,但我换了新的硬件,那么,这个核心肯定无法支持! 怎么办?重新拿一个新的核心来处理吗?开玩笑~核心的编译过程可是很麻烦的~
所以为了这个缘故,我们的 Linux 很早之前就已经开始使用所谓的模块化设定了! 亦即是将一些不常用的类似驱动程序的咚咚独立出核心,编译成为模块,然后, 核心可以在系统正常运作的过程当中加载这个模块到核心的支持。如此一来, 我在不需要更动核心的前提之下,只要编译出适当的核心模块,并且加载他,我的 Linux 就可以使用这个硬件啦!简单又方便!
我的模块就是放在 /lib/modules/$(uname -r)/kernel/ 当中!

三、自制核心 - 核心编译
刚刚上面谈到的核心其实是一个档案,那么这个档案怎么来的?当然是透过原始码 (source code) 编译而成的!因为核心是直接被读入到主存储器当中的,所以当然要将他编译成为系统可以认识的数据才行!也就是说, 我们必须要取得核心的原始码,然后利用第二十二章 Tarball 安装方式提到的编译概念来达成核心的编译才行!(这也是本章的重点!)

四、关于驱动程序 - 是厂商的责任还是核心的责任?
现在我们知道硬件的驱动程序可以编译成为核心模块,所以可以在不改变核心的前提下驱动你的新硬件。 但是,很多朋友还是常常感到困惑,就是 Linux 上面针对最新硬件的驱动程序总是慢了几个脚步, 所以觉得好像 Linux 的支持度不足!其实不可以这么说的,为什么呢?因为在 Windows 上面,对于最新硬件的驱动程序需求,基本上,也都是厂商提供的驱动程序才能让该硬件工作的, 因此,在这个『驱动程序开发』的工作上面来说,应该是属于硬件发展厂商的问题, 因为他要我们买他的硬件,自然就要提供消费者能够使用的驱动程序!
所以如果大家想要让某个硬件能够在 Linux 上面跑的话,那么似乎可以发起一人一信的方式,强烈要求硬件开发商发展 Linux 上面的驱动程序!这样一来,也可以促进 Linux 的发展!

26.1.2. 更新核心的目的
除了 BIOS 之外,核心是操作系统中最早被加载到内存的咚咚, 他包含了所有可以让硬件与软件工作的信息,所以如果没有搞定核心的话, 那么你的系统肯定会有点小问题!好了,那么是不是将『所有目前核心有支持的东西都给他编译进去我的核心中, 那就可以支持目前所有的硬件与可执行的工作了!』?
这话说的是没错,我相信不太有人会这样做!
说这个就是要你了解到,核心的编译重点在于『你要你的 Linux 作什么?』,如果没有必要的工作,就干脆不要加在你的核心当中了!这样才能让你的 Linux 跑得更稳、更顺畅!这也是为什么我们要编译核心的最主要原因了!

一、Linux 核心特色,与默认核心对终端用户的角色
Linux 的核心有几个主要的特色,除了『Kernel 可以随时、随各人喜好而更动』之外,Kernel 的『版本更动次数太频繁』也是一个特点!所以除非你有特殊需求, 否则一次编译成功就可以!不需要随时保持最新的核心版本,而且也没有必要 (编译一次核心要粉久的ㄋㄟ!) 。话说到这里又突然想到今天看到的一篇文章,大意是说老板想要雇用的人会希望是 Linux 的老手,因为他们比较容易了解问题的所在,除此之外,如果有任何问题发生,由于其使用 Linux 是可以随时修补漏洞的!但是如果是 Windows 的话,就得要将机器关闭,直到 MS 推出修补套件后才能再启用~
那么是否『我就一定需要在安装好了 Linux 之后就赶紧给他编译核心呢?』, 老实说,『并不需要的』!这是因为几乎每一个 distribution 都已经预设编译好了相当大量的模块了, 所以用户常常或者可能会使用到的数据都已经被编译成为模块,也因此我们使用者确实不太需要重新来编译核心!尤其是『一般的用户, 由于系统已经将核心编译的相当的适合一般使用者使用了,因此一般入门的使用者,基本上, 不太需要编译核心』。

二、核心编译的可能目的
那么我闲闲没事干跑来写个什么东西?当然是有需要才会来编译核心!编译核心的时机可以归纳为几大类:

  • 新功能的需求:
    我需要新的功能,而这个功能只有在新的核心里面才有,那么为了获得这个功能,只好来重新编译我的核心了。例如 iptables 这个防火墙机制只有在 2.4.xx 以后的版本里面才有,而新开发的主板芯片组, 很多也需要新的核心推出之后,才能正常而且有效率的工作!

  • 原本核心太过臃肿:
    如果你是那种对于系统『稳定性』很要求的人,对于核心多编译了很多莫名其妙的功能而不太喜欢的时候, 那么就可以重新编译核心来取消掉该功能;

  • 与硬件搭配的稳定性:
    由于原本 Linux 核心大多是针对 Intel 的 CPU 来作开发的,所以如果你的 CPU 是 AMD 的系统时,有可能 (注意!只是有可能,不见得一定会如此) 会让系统跑得『不太稳!』。此外,核心也可能没有正确的驱动新的硬件,此时就得重新编译核心来让系统取得正确的模块才好。

  • 其他需求 (如嵌入式系统):
    就是你需要特殊的环境需求时,就得自行设计你的核心!( 像是一些商业的软件包系统,由于需要较为小而美的操作系统, 那么他们的核心就需要更简洁有力了!)

另外,需要注意重新编译核心虽然可以针对你的硬件作优化的步骤 (例如刚刚提到的 CPU 的问题!) ,不过由于这些优化的步骤对于整体效能的影响是很小很小的, 因此如果是为了增加效能来编译核心的话,基本上,效益不大!然而,如果是针对『系统稳定性』来考虑的话, 那么就有充分的理由来支持你重新编译核心!
『如果系统已经运行很久了,而且也没有什么大问题, 加上我又不增加冷门的硬设备,那么建议就不需要重新编译核心了』, 因为重新编译核心的最主要目的是『想让系统变的更稳!』既然你的 Linux 主机已经达到这个目的了,何必再编译核心?不过,就如同前面提到的, 由于预设的核心不见得适合你的需要,加上预设的核心可能并无法与你的硬件配备相配合, 此时才开始考虑重新编译核心吧!
由于『核心的主要工作是在控制硬件 !』所以编译核心之前, 请先了解一下你的硬件配备,与你这部主机的未来功能!由于核心是『越简单越好 !』所以只要将这部主机的未来功能给他编进去就好了! 其他的就不用去理他了!

26.1.3. 核心的版本
核心的版本问题,我们在第一章已经谈论过, 主要的版本定义为:『[主].[次].[释出]-[修改]』的样式。 你只要知道 2.6.x 是稳定版本,2.5.x 是测试用版本即可。 我们要使用最新的核心来重新编译核心时,大多就是使用那种偶数的核心版本啦!不过这里还是要再提一遍 !就是『 2.4.x 与 2.6.x 是两个具有相当大差异的核心版本, 两者之间使用到的函式库基本上已经不相同了,所以在升级之前,如果你的核心原本是 2.4.xx 版,那么就升级到 2.4.xx 版本的最新版,不要由 2.4.xx 直接升级到 2.6.xx 版,否则到时可能会欲哭无泪~~』, 这个问题在讨论区一再地被提起!这里再次说明!
此外,2.4.xx 与 2.6.xx 的比较中,并不是 2.6.xx 就一定比 2.4.xx 还要新,因为这两种版本同时在进行维护与升级的工作!如果有兴趣的话,可以前往 Linux 核心网站 http://www.kernel.org 一看究竟,你就可以了解目前的核心变动情况了!
基本上,目前最新的 distributions ,包括 CentOS, FC, SuSE, Mandriva 等等,都使用 2.6 的核心, 所以,你可以直接由 http://www.kernel.org 下载最新的 2.6.xx 版本的核心来尝试编译!目前 (2009/07/27) 可以查到的最新版本是 2.6.30 , 底下我们将主要以这个版本来测试。另外,由于较新的核心版本可能会多出一些选项, 因此若有不同的项目也没有关系!稍微查看一下说明内容就可以了解了!

26.1.4. 核心原始码的取得方式:distributions 预设、最新、patch
既然核心是个档案,要制作这个档案给系统使用则需要编译,既然要有编译,当然就得要有原始码! 那么原始码怎么来?基本上,依据你的 distributions 去挑选的核心原始码来源主要有:

一、原本 distribution 提供的核心原始码档案
事实上,各主要 distributions 在推出他们的产品时,其实已经都附上了核心原始码了! 以我们的 CentOS 5.x 为例,你可以在国家高速网络中心网站下载相关的核心 SRPM 的档案! 由于 CentOS 5.x 一直有在进行更新动作,因此你也可以在 update 的目录底下找到核心原始码!如下连结所示:

你或许会说:既然要重新编译,那么干嘛还要使用原本 distributions 释出的原始码啊?真没创意~ 话不是这么说,因为原本的 distribution 释出的原始码当中,含有他们设定好的预设设定值, 所以,我们可以轻易的就了解到当初他们是如何选择与核心及模块有关的各项设定项目的参数值, 那么就可以利用这些可以配合我们 Linux 系统的默认参数来加以修改,如此一来, 我们就可以『修改核心,调整到自己喜欢的样子』!而且编译的难度也会比较低一点!

二、取得最新的稳定版核心原始码
虽然使用 distribution 释出的核心 source code 来重新编译比较方便,但是,如此一来, 新硬件所需要的新驱动程序,也就无法藉由原本的核心原始码来编译啊! 所以如果是站在要更新驱动程序的立场来看,当然使用最新的核心可能会比较好!
Linux 的核心目前是由其发明者 Linus Torvalds 所属团队在负责维护的,而其网站在底下的站址上,在该网站上可以找到最新的 kernel 信息!不过,美中不足的是目前的核心越来越大了 (linux-2.6.30.3.tar.bz2 这一版,这一个档案大约 57MB 了!),所以如果你的 ISP 连外很慢的话,那么使用台湾的映射站台来下载不失为一个好方法:

三、保留原本设定:利用 patch 升级核心原始码
如果 (1)你曾经自行编译过核心,那么你的系统当中应该已经存在前几个版本的核心原始码, 以及上次你自行编译的参数设定值才对; (2)如果你只是想要在原本的核心底下加入某些特殊功能, 而该功能已经针对核心原始码推出 patch 补丁档案时。那你该如何进行核心原始码的更新,以便后续的编译呢?
其实每一次核心释出时,除了释出完整的核心压缩文件之外,也会释出『该版本与前一版本的差异性 patch 档案』, 关于 patch 的制作我们已经在第二十二章当中提及, 你可以自行前往参考。这里仅是要提供给你的信息是,每个核心的 patch 仅有针对前一版的核心来分析而已, 所以,万一你想要由 2.6.27 升级到 2.6.30 的话,那么你就得要下载 patch-2.6.28, patch-2.6.29, patch-2.6.30 等档案,然后『依序』一个一个的去进行 patch 的动作后, 才能够升级到 2.6.30 !这个重要!不要忘记了。
但是,如果你想要升级 2.6.30 的修改版本到 2.6.30.3 时,由于修改版本是针对 2.6.30 来制作的, 因此你只要下载 patch-2.6.30.3 来直接将 2.6.30 升级至 2.6.30.3 即可。但反过来说,如果你要从 2.6.30.2 升级到 2.6.30.3 呢?很抱歉的是,并没有 2.6.30.2 到 2.6.30.3 的补丁档案,所以你必须要将 2.6.30.2 还原至 2.6.30, 然后才能使用 patch-2.6.30.3 来升级 2.6.30 !注意这个差异!
同样的,如果是某个硬件或某些非官方认定的核心添加功能网站所推出的 patch 档案时,你也必须要了解该 patch 档案所适用的核心版本, 然后才能够进行 patch ,否则容易出现重大错误!这个项目对于某些商业公司的工程师来说是很重要的。 举例来说,我的一个高中同学在业界服务,他主要是进行类似 Eee PC 开发的计划,然而该计划的硬件是该公司自行推出的! 因此,该公司必须要自行搭配核心版本来设计他们自己的驱动程序,而该驱动程序并非 GPL 授权,因此他们就得要自行将驱动程序整合进核心!如果改天他们要将这个驱动程序释出,那么就得要利用 patch 的方式, 将硬件驱动程序档案释出,我们就得要自行以 patch 来更新核心了!
在进行完 patch 之后,你可以直接检查一下原本的设定值,如果没有问题, 就可以直接编译,而不需要再重新的选择核心的参数值,这也是一个省时间的方法! 至于 patch file 的下载,同样是在 kernel 的相同目录下,寻找文件名是 patch 开头的就是了。

26.1.5. 核心原始码的解压缩/安装/观察
由于我是比较喜欢直接由核心官网取得原始核心的,所以底下的动作是使用 2.6.30.3 这个版本的核心来安装的! 如果你想要使用 distributions 提供的 SRPM 来处理的话,得自行找到 SRPM 的相关安装方法来处理! 其实看一下第二十二章就知道该如何处理了。 总之,本章的核心原始码是由底下的连结取得的:

一、核心原始码的解压缩与放置目录
这里假设你也是下载上述的连结内的档案,然后该档案放置到 /root 底下。由于 2.6.x 核心原始码一般建议放置于 /usr/src/kernels/ 目录底下,因此你可以这样处理:
这里写图片描述
此时会在 /usr/src/kernels 底下产生一个新的目录,那就是 linux-2.6.30.3 这个目录! 我们在下个小节会谈到的各项编译与设定,都必须要在这个目录底下进行才行!那么这个目录底下的相关档案有啥咚咚? 底下就来谈谈:

二、核心原始码下的次目录
在上述核心目录下含有哪些重要数据呢?基本上有底下这些东西:

  • arch : 与硬件平台有关的项目,大部分指的是 CPU 的类别,例如 x86, x86_64, Xen 虚拟支持等;
  • block :与成组设备较相关的设定数据,区块数据通常指的是大量储存媒体!还包括类似 ext3 等文件系统的支持是否允许等。
  • crypto :核心所支持的加密的技术,例如 md5 或者是 des 等等;
  • Documentation :与核心有关的一堆说明文件,若对核心有极大的兴趣,要瞧瞧这里!
  • drivers :一些硬件的驱动程序,例如显示适配器、网络卡、PCI 相关硬件等等;
  • firmware :一些旧式硬件的微脚本 (韧体) 数据;
  • fs :核心所支持的 filesystems ,例如 vfat, reiserfs, nfs 等等;
  • include :一些可让其他过程调用的标头 (header) 定义数据;
  • init :一些核心初始化的定义功能,包括挂载与 init 程序的呼叫等;
  • ipc :定义 Linux 操作系统内各程序的沟通
  • kernel :定义核心的程序、核心状态、线程、程序的排程 (schedule)、程序的讯号 (signle) 等 ;
  • lib :一些函式库
  • mm :与内存单元有关的各项数据,包括 swap 与虚拟内存等;
  • net :与网络有关的各项协议数据,还有防火墙模块 (net/ipv4/netfilter/*) 等等;
  • security :包括 selinux 等在内的安全性设定;
  • sound :与音效有关的各项模块;
  • virt : 与虚拟化机器有关的信息,目前核心支持的是 KVM (Kernel base Virtual Machine)

这些数据先大致有个印象即可,至少未来如果你想要使用 patch 的方法加入额外的新功能时, 你要将你的原始码放置于何处?这里就能够提供一些指引了。当然,最好还是跑到 Documentation 那个目录底下去瞧瞧正确的说明, 对你的核心编译会更有帮助!

26.2. 核心编译的前处理与核心功能选择
事实上,核心的目的在管理硬件与提供系统核心功能,因此你必须要先找到你的系统硬件, 并且规划你的主机未来的任务,这样才能够编译出适合你这部主机的核心!所以,整个核心编译的重要工作就是在『挑选你想要的功能』。 底下我就以自己的一部主机软/硬件环境来说明,解释一下如何处理核心编译!

26.2.1. 硬件环境检视与核心功能要求
我的一部主机硬件环境如下 (透过 /proc/cpuinfo 及 lspci 观察):

  • CPU:AMD 的 Athlon64 3000+ (旧式,不含虚拟化功能)
  • 主板芯片组: ALi M1689 K8 北桥 及 M5249, M1563 南桥芯片 (较冷门的硬件)
  • 显示适配器: AGP 8X 的 NVidia GeForce 6600LE
  • 内存: 2.0GB 内存
  • 硬盘: WD 2.5GB 硬盘,使用 ALi, ULi 5289 SATA 接口
  • 电源控制器: ALi M7101 Power Management Controller (PMU)
  • 网络卡: 3Com 3c905C-TX/TX-M (对外)
  • 网络卡: Realtek Semiconductor RTL-8139/8139C/8139C+

硬件大致如上,至于这部主机的需求,是希望做为未来在我上课时,可以透过虚拟化功能来处理学生的练习用虚拟机。 这部主机也是我用来放置学校上课教材的机器,因此,这部主机的 I/O 需求须要好一点,未来还需要开启防火墙、 WWW 服务器功能、FTP 服务器功能等,基本上,用途就是一部小型的服务器环境。大致上需要这样的功能!

26.2.2. 保持干净原始码: make mrproper
了解了硬件相关的数据后,我们还得要处理一下核心原始码底下的残留档案才行!假设我们是第一次编译, 但是我们不清楚到底下载下来的原始码当中有没有保留目标档案 (*.o) 以及相关的配置文件存在, 此时我们可以透过底下的方式来处理掉这些编译过程的目标档案以及配置文件:
这里写图片描述
请注意,这个动作会将你以前进行过的核心功能选择档案也删除掉, 所以几乎只有第一次执行核心编译前才进行这个动作,其余的时刻,你想要删除前一次编译过程的残留数据, 只要下达:
这里写图片描述
因为 make clean 仅会删除类似目标文件之类的编译过程产生的中间档案,而不会删除配置文件! 很重要的!千万不要搞乱了!

26.2.3. 开始挑选核心功能: make XXconfig
不知道你有没有发现 /boot/ 底下存在一个名为 config-xxx 的档案?那个档案其实就是核心功能列表文件! 我们底下要进行的动作,其实就是作出该档案!而我们后续小节所要进行的编译动作,其实也就是透过这个档案来处理的! 核心功能的挑选,最后会在 /usr/src/kernels/linux-2.6.30.3/ 底下产生一个名为 .config 的隐藏档, 这个档案就是 /boot/config-xxx 的档案!那么这个档案如何建立呢?你可以透过非常多的方法来建立这个档案! 常见的方法有:(注1)

  • make menuconfig
    最常使用的,是文本模式底下可以显示类似图形接口的方式,不需要启动 X Window 就能够挑选核心功能选单!
  • make oldconfig
    透过使用已存在的 ./.config 档案内容,使用该档案内的设定值为默认值,只将新版本核心内的新功能选项列出让用户选择, 可以简化核心功能的挑选过程!对于作为升级核心原始码后的功能挑选来说,是非常好用的一个项目!
  • make xconfig
    透过以 Qt 为图形接口基础功能的图形化接口显示,需要具有 X window 的支持。例如 KDE 就是透过 Qt 来设计的 X Window,因此你如果在 KDE 画面中,可以使用此一项目。
  • make gconfig
    透过以 Gtk 为图形接口基础功能的图形化接口显示,需要具有 X window 的支持。例如 GNOME 就是透过 Gtk 来设计的 X Window,因此你如果在 GNOME 画面中,可以使用此一项目。
  • make config
    最旧式的功能挑选方法,每个项目都以条列式一条一条的列出让你选择,如果设定错误只能够再次选择,很不人性化啊!

大致的功能选择有上述的方法,不过我个人比较偏好 make menuconfig 这个项目!如果你喜欢使用图形接口, 然后使用鼠标去挑选所需要的功能时,也能使用 make xconfig 或 make gconfig ,不过需要有相关的图形接口支持! 如果你是升级核心原始码并且需要重新编译,那么使用 make oldconfig 会比较适当!好了,那么如何选择呢? 以 make menuconfig 来说,出现的画面会有点像这样:
这里写图片描述
看到上面的图示之后,你会发现画面主要分为两大部分,一个是大框框内的反白光柱,另一个则是底下的小框框, 里面有 select, exit 与 help 三个选项的内容。这几个组件的大致用法如下:

  • 『左右箭头键』:可以移动最底下的 , , 项目;
  • 『上下箭头键』:可以移动上面大框框部分的反白光柱,若该行有箭头 (—>) 则表示该行内部还有其他细项需要来设定的意思;
  • 选定项目: 以『上下键』选择好想要设定的项目之后,并以『左右键』选择 之后, 按下『 Enter 』就可以进行该项目去作更进一步的细部设定;
  • 可挑选之功能:在细部项目的设定当中,如果前面有 [ ] 或 < > 符号时,该项目才可以选择, 而选择可以使用『空格键』来选择;
  • 若为 [*]<*> 则表示编译进核心;若为 则表示编译成模块! 尽量在不知道该项目为何时,且有模块可以选,那么就可以直接选择为模块!
  • 当在细项目选择 后,并按下 Enter ,那么就可以离开该细部项目!

基本上建议只要『上下左右的箭头键、空格键、Enter』这六个按键就好了!不要使用 Esc ,否则一不小心就有可能按错的!另外,关于整个核心功能的选择上面,建议你可以这样思考:

  • 『肯定』核心一定要的功能,直接编译进核心内;
  • 『可能在未来会用到』的功能,那么尽量编译成为模块;
  • 『不知道那个东西要干嘛的,看 help 也看不懂』的话,那么就保留默认值,或者将他编译成为模块;

总之,尽量保持核心小而美,剩下的功能就编译成为模块,尤其是『需要考虑到未来扩充性』, 像我之前认为螃蟹卡就够我用的了,结果,后来竟然网站流量大增,我只好改换 3Com 的网络卡。 不过,我的核心却没有相关的模块可以使用~因为…..我自己编译的核心忘记加入这个模块了。 最后,只好重新编译一次核心的模块,真是惨痛的教训啊!

26.2.4. 核心功能细项选择
由上面的图示当中,我们知道核心的可以选择的项目有很多啊!光是第一面,就有 16 个项目,每个项目内还有不同的细项!真是很麻烦啊~每个项目其实都可能有 的说明,所以,如果看到不懂的项目,务必要使用 Help 查阅查阅! 好了,底下我们就一个一个项目来看看如何选择吧!

a. General setup
一般设定(General setup):附加版本名称、IPC 通讯、程序相关等。
与 Linux 最相关的程序互动、核心版本说明、是否使用发展中程序代码等信息都在这里设定的。 这里的项目主要都是针对核心与程序之间的相关性来设计的,基本上,保留默认值即可! 不要随便取消底下的任何一个项目,因为可能会造成某些程序无法被同时执行的困境! 不过底下有非常多新的功能,如果你有不清楚的地方,可以按 进入查阅,里面会有一些建议! 你可以依据 Help 的建议来选择新功能的启动与否!
这里写图片描述
这里写图片描述
这里写图片描述
b. loadable module + block layer
核心模块与 block layer 支持
要让你的核心能够支持动态的核心模块,那么底下的第一个设定就得要启动才行!至于第二个 block layer 则预设是启动的, 你也可以进入该项目的细项设定,选择其中你认为需要的功能即可!
这里写图片描述
c. CPU 的类型与功能选择(含虚拟化技术)
进入『Processor type and features』后,请挑选你主机的实际 CPU 形式。我这里使用的是 Athlon 64 的 CPU, 而且我的主机还有启动 Xen 这个虚拟化的服务 (在一部主机上面同时启动多个操作系统),因此,所以底下的选择是这样的:
这里写图片描述
这里写图片描述
这里写图片描述
d. 电源管理功能
如果选择了『Power management and ACPI options』之后,就会进入系统的电源管理机制中。 其实电源管理机制还需要搭配主板以及 CPU 的相关省电功能,才能够实际达到省电的效率! 不论是 Server 还是 Desktop 的使用,在目前电力不足的情况下,能省电就加以省电吧!
这里写图片描述
这里写图片描述
e. 一些总线 (bus) 的选项
这个项目则与总线有关!分为最常见的 PCI 与 PCI-express 的支持,还有笔记本电脑常见的 PCMCIA 插卡!要记住的是,那个 PCI-E 的界面务必要选取!不然你的新显示适配器可能会捉不到!
这里写图片描述
f. 编译后执行档的格式
选择『Executable file formats / Emulations』会见到如下选项。 底下的选项必须要勾选才行!因为是给 Linux 核心运作执行文件之用的数据。通常是与编译行为有关!
这里写图片描述
g. 核心的网络功能
这个『Networking support』项目是相当重要的选项,因为他还包含了防火墙相关的项目!就是未来在服务器篇会谈到的防火墙 iptables 这个数据啊!所以,千万注意了!在这个设定项目当中,很多东西其实我们在基础篇还没有讲到, 因为大部分的参数都与网络、防火墙有关!由于防火墙是在启动网络之后再设定即可,所以绝大部分的内容都可以被编译成为模块,而且也建议你编成模块 !有用到再载入到核心即可啊!
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
h. 各项装置的驱动程序
进入『Device Drivers』这个是所有硬件装置的驱动程序库!光是看到里面这么多内容,我头都昏了~ 不过,为了你自己的主机好,建议你还是得要一个项目一个项目的去挑选挑选才行~ 这里面的数据就与你主机的硬件有绝对的关系了!
在这里面真的很重要,因为很多数据都与你的硬件有关。核心推出时的默认值是比较符合一般状态的, 所以很多数据其实保留默认值就可以编的很不错了!不过,也因为较符合一般状态, 所以核心额外的编译进来很多跟你的主机系统不符合的数据,例如网络卡装置~ 你可以针对你的主板与相关硬件来进行编译。不过,还是要让得有『未来扩充性』的考虑! 之前说过,我的网络卡由螃蟹卡换成 3Com 时,核心捉不到~ 因为…我并没有将 3Com 的网络卡编译成为模块啊!
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
底下则与 Firmware Drivers 有关!基本上,都保留默认值就好了!
这里写图片描述
这里写图片描述
i. 文件系统的支援
文件系统的支持也是很重要的一项核心功能!因为如果不支持某个文件系统,那么我们的 Linux kernel 就无法认识,当然也就无法使用!例如 Quota, NTFS 等等特殊的 filesystem 。 这部份也是有够麻烦~因为涉及核心是否能够支持某些文件系统,以及某些操作系统支持的 partition table 项目。在进行选择时,也务必要特别的小心在意! 尤其是我们常常用到的网络操作系统 (NFS/Samba 等等),以及基础篇谈到的 Quota 等, 你都得要勾选!否则是无法被支持的。比较有趣的是 NTFS 在这一版的核心里面竟然有支持可写入的项目, 着实让我吓了一跳了!
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
j. 核心黑客、信息安全、密码应用
再接下来有个『Kernel hacking』的项目,那是与核心开发者比较有关的部分,这部分建议保留默认值即可, 应该不需要去修改他!除非你想要进行核心方面的研究。然后底下有个『 Security Options 』,那是属于信息安全方面的设定, 包括 SELinux 这个细部权限强化模块也在这里编入核心的!这部分可以作一些额外的设定。 另外还有『 Cryptographic API 』这个密码应用程序编程接口工具选项,也是可以保留默认值! 我们来看看有什么比较特殊的地方吧!
这里写图片描述
这里写图片描述
在密码应用程序编程接口方面,一般我们使用的账号密码登入利用的就是 MD5 这个加密机制,要让核心有支持才行!几乎所有的项目都给他做成模块即可! 不过 MD5 与 SHA1 必须要直接由核心支持比较好!

k. 虚拟化与函式库
虚拟化是近年来非常热门的一个议题,因为计算机的能力太强,所以时常闲置在那边, 此时,我们可以透过虚拟化技术在一部主机上面同时启动多个操作系统来运作,这就是所谓的虚拟化。 Linux 核心已经主动的纳入虚拟化功能!而 Linux 认可的虚拟化使用的机制为 KVM (Kernel base Virtual Machine)。 至于常用的核心函式库也可以全部编为模块!
这里写图片描述
最后,还有底下这两个项目,这两个项目与核心功能无关,但是与挑选时的配置文件案有关:
这里写图片描述
这两个项目分别是储存刚刚做好的所有项目的设定数据,另一个则是将来自其他人作的选择给他读入! 事实上,刚刚我们所做的设定只要在离开时选择 SAVE ,那么这些项目通通会记录到目前这个目录下的 .config 档案内。 而我们也可以使用上面提到的 Save Configuration 这个项目来将刚刚做完的设定储存成另外的档案, 做成这个档案的好处是,你可以在下次在其他版本的核心作选择时,直接以 Load 来将这个档案的设定项目读入,这样可以减少你还要重新挑选一遍的困境!
要请你注意的是,上面的资料主要是适用在我个人机器上面的, 目前比较习惯使用原本 distributions 提供的预设核心,因为他们也会主动的进行更新, 所以我就懒的自己重编核心了~
此外,因为我重规的地方在于『网络服务器』上面,所以里头的设定少掉了相当多的个人桌上型 Linux 的硬件编译!所以,如果你想要编译出一个适合你的机器的核心, 那么可能还有相当多的地方需要来修正的!不论如何,请随时以 Help 那个选项来看一看内容吧!反正 Kernel 重编的机率不大!花多一点时间重新编译一次! 然后将该编译完成的参数档案储存下来,未来就可以直接将该档案叫出来读入了! 所以花多一点时间安装一次就好!那也是相当值得的!

26.3. 核心的编译与安装
将最复杂的核心功能选择完毕后,接下来就是进行这些核心、核心模块的编译了!而编译完成后,当然就是需要使用~ 那如何使用新核心呢?就得要考虑 grub 这个玩意儿!底下我们就来处理处理:

26.3.1. 编译核心与核心模块
核心与核心模块需要先编译起来,而编译的过程其实非常简单,你可以先使用『 make help 』去查阅一下所有可用编译参数, 就会知道有底下这些基本功能:
这里写图片描述
我们常见的在 /boot/ 底下的核心档案,都是经过压缩过的核心档案,因此,上述的动作中比较常用的是 modules 与 bzImage 这两个,其中 bzImage 第三个字母是英文大写的 I !bzImage 可以制作出压缩过后的核心, 也就是一般我们拿来进行系统开机的信息!所以,基本上我们会进行的动作是:
这里写图片描述
上述的动作会花费非常长的时间,编译的动作依据你选择的项目以及你主机硬件的效能而不同。 最后制作出来的数据是被放置在 /usr/src/kernels/linux-2.6.30.3/ 这个目录下,还没有被放到系统的相关路径中!在上面的编译过程当中,如果有发生任何错误的话, 很可能是由于核心项目的挑选选择的不好,可能你需要重新以 make menuconfig 再次的检查一下你的相关设定! 如果还是无法成功的话,那么或许将原本的核心数据内的 .config 档案,复制到你的核心原始文件目录下, 然后据以修改,应该就可以顺利的编译出你的核心了。最后注意到,下达了 make bzImage 后,最终的结果应该会像这样:
这里写图片描述
可以发现你的核心已经编译好而且放置在 /usr/src/kernels/linux-2.6.30.3/arch/x86/boot/bzImage 里面~那个就是我们的核心档案!最重要就是他!我们等一下就会安装到这个档案! 然后就是编译模块的部分~ make modules 进行完毕后,就等着安装了!

26.3.2. 实际安装模块
安装模块前有个地方得要特别强调!我们知道模块是放置到 /lib/modules/$(uname -r) 目录下的,那如果同一个版本的模块被反复编译后来安装时,会不会产生冲突呢?举例来说,我这个 2.6.30.3 的版本第一次编译完成且安装妥当后,发现有个小细节想要重新处理,因此又重新编译过一次,那两个版本一模一样时, 模块放置的目录会一样,此时就会产生冲突了!如何是好?有两个解决方法:

  • 先将旧的模块目录更名,然后才安装核心模块到目标目录去;
  • 在 make menuconfig 时,那个 General setup 内的 Local version 修改成新的名称。

我建议使用第二个方式,因为如此一来,你的模块放置的目录名称就不会相同,这样也就能略过上述的目录同名问题! 好,那么如何安装模块到正确的目标目录呢?很简单,同样使用 make 的功能即可:
这里写图片描述
看到否,最终会在 /lib/modules 底下建立起你这个核心的相关模块!模块这样就已经处理妥当~ 接下来,就是准备要进行核心的安装了!又跟 grub 有关了~

26.3.3. 开始安装新核心与多重核心选单 (grub)
现在我们知道核心档案放置在 /usr/src/kernels/linux-2.6.30.3/arch/x86/boot/bzImage ,但是其实系统核心理论上都是摆在 /boot 底下,且为 vmlinuz 开头的档名。 此外,我们也晓得一部主机是可以做成多重引导系统的!这样说,应该知道我想要干嘛了吧? 我们将同时保留旧版的核心,并且新增新版的核心在我们的主机上面。

一、移动核心到 /boot 且保留旧核心档案
保留旧核心有什么好处呢?最大的好处是可以确保系统能够顺利开机!因为核心虽然被编译成功了, 但是并不保证我们刚刚挑选的核心项目完全适合于目前这部主机系统, 可能有某些地方我们忘记选择了,这将导致新核心无法顺利驱动整个主机系统,更差的情况是, 你的主机无法成功开机成功!此时,如果我们保留旧的核心,若新核心测试不通过,就用旧核心来启动! 保证比较不会有问题嘛!新核心通常可以这样作的:
这里写图片描述

二、建立相对应的 Initial Ram Disk (initrd)
还记得第二十章谈过的 initrd 这个玩意儿吧! 由于我的系统使用 SATA 磁盘,加上刚刚 SATA 磁盘支持的功能并没有直接编译到核心去,所以当然要使用 initrd 来加载才行! 使用如下的方法来建立 initrd 吧!记得搭配正确的核心版本!
这里写图片描述
这里写图片描述

三、编辑开机选单 (grub)
这部测试机之前是使用 Xen 的核心来启动的,但因为 Xen 核心的制作比较复杂,本章并没有实作出 Xen 虚拟机的核心。 底下我使用的是刚刚编译成功的核心来进行开机选单的设定,你会看到的配置文件与你的环境可能会有不一样! 那就来看看吧!
这里写图片描述
新增上述的特殊字体到你的配置文件当中。另外,你会发现我上头的 default 并没有修改到最新的那个核心的选单上, 因为我必须要测试一下新核心能否顺利开机!如果顺利开机且运作没有问题后,那么才来修订这个 default 的值吧!

四、重新以新核心开机、测试、修改
如果上述的动作都成功后,接下来就是重新启动并选择新核心来启动系统!如果系统顺利启动之后,你使用 uname -a 会出现类似底下的数据:
这里写图片描述
包括核心版本与支持的硬件平台都是 OK 的!那你所编译的核心就是差不多成功的! 如果运作一阵子后,你的系统还是稳定的情况下,那就能够将 default 值使用这个新的核心来作为预设开机! 这就是核心编译!那你也可以自己处理嵌入式系统的核心编译!

26.4. 额外(单一)核心模块编译
我们现在知道核心所支持的功能当中,有直接编译到核心内部的,也有使用外挂模块的,外挂模块可以简单的想成就是驱动程序!那么也知道这些核心模块依据不同的版本,被分别放置到 /lib/modules/ ( u n a m e r ) / k e r n e l / / l i b / m o d u l e s / (uname -r)/kernel/drivers/ 当中!换个角度再来思考一下,如果刚刚我自己编译的数据中,有些驱动程序忘记编译成为模块了,那是否需要重新进行上述的所有动作? 又如果我想要使用硬件厂商释出的新驱动程序,那该如何是好?

26.4.1. 编译前注意事项
由于我们的核心原本就有提供很多的核心工具给硬件开发商来使用, 而硬件开发商也需要针对核心所提供的功能来设计他们的驱动程序模块,因此, 我们如果想要自行使用硬件开发商所提供的模块来进行编译时,就需要使用到核心所提供的原始档当中, 所谓的头文件案 (header include file) 来取得驱动模块所需要的一些函式库或标头的定义! 也因此我们常常会发现到,如果想要自行编译核心模块时,就得要拥有核心原始码嘛!
那核心原始码我们知道他是可能放置在 /usr/src/ 底下,早期的核心原始码被要求一定要放置到 /usr/src/linux/ 目录下,不过,如果你有多个核心在一个 Linux 系统当中,而且使用的原始码并不相同时, 问题可就大了!所以,在 2.6 版以后,核心使用比较有趣的方法来设计他的原始码放置目录, 那就是以 /lib/modules/ ( u n a m e r ) / b u i l d / l i b / m o d u l e s / (uname -r)/source 这两个连结档来指向正确的核心原始码放置目录。如果以我们刚刚由 kernel 2.6.30.3 建立的核心模块来说, 那么他的核心模块目录底下有什么咚咚?
这里写图片描述
比较有趣的除了那两个连结档之外,还有那个 modules.dep 档案也挺有趣的, 那个档案是记录了核心模块的相依属性的地方,依据该档案,我们可以简单的使用 modprobe 这个指令来加载模块!至于核心原始码提供的头文件,在上面的案例当中, 则是放置到 /usr/src/kernels/linux-2.6.30.3/include/ 目录中,当然就是藉由 build/source 这两个链接档案来取得目录所在!
由于核心模块的编译其实与核心原本的原始码有点关系的,因此如果你需要重新编译模块时, 那除了 make, gcc 等主要的编译软件工具外,你还需要的就是 kernel-devel 这个软件 !记得一定要安装!而如果你想要在预设的核心底下新增模块的话,那么就得要找到 kernel 的 SRPM 档案了! 将该档案给他安装,并且取得 source code 后,才能够顺利的编译!

26.4.2. 单一模块编译
想象两个情况:

  • 如果我的默认核心忘记加入某个功能,而且该功能可以编译成为模块,不过, 预设核心却也没有将该项功能编译成为模块,害我不能使用时,该如何是好?
  • 如果 Linux 核心原始码并没有某个硬件的驱动程序 (module) ,但是开发该硬件的厂商有提供给 Linux 使用的驱动程序原始码,那么我又该如何将该项功能编进核心模块呢?

很有趣对吧!不过,在这样的情况下其实没有什么好说的,反正就是 『去取得原始码后,重新编译成为系统可以加载的模块』! 但是,上面那两种情况的模块编译行为是不太一样的,不过,都是需要 make, gcc 以及核心所提供的 include 头文件与函式库等等。

一、硬件开发商提供的额外模块
很多时候,可能由于核心默认的核心驱动模块所提供的功能你不满意,或者是硬件开发商所提供的核心模块具有更强大的功能, 又或者该硬件是新的,所以预设的核心并没有该硬件的驱动模块时,那你只好自行由硬件开发商处取得驱动模块, 然后自行编译!
如果你的硬件开发商有提供驱动程序的话,那么真的很好解决,直接下载该原始码,重新编译, 将他放置到核心模块该放置的地方后就能够使用了!举个例子来说,为了省电,我在 2009 年买了整合型主板来架设家用的服务器,没想到 CentOS 5.1 以前的版本对我新买的主板内建网卡支持度不足, 使用的网卡驱动程序 r8169 有问题!搜寻了 google 才发现大家都有这个问题。解决方法就是到 Realtek 官网下载网卡驱动程序来编译即可。

  • Realtek 的 r8168 网卡驱动程序:http://www.realtek.com.tw/downloads/
  • 选择『Communications Network ICs』–>『Network Interface Controlllers』–> 『10/100/1000M Gigabit Ethernet』–> 『PCI Express』–> 『Software』就能够下载了!

你可以利用各种方法将他下载后,假设这个档案放置到 /root ,那么直接将他解压缩吧! 之后就可以读一读 INSTALL/README ,然后找一下 Makefile ,就能够编译了。整体流程有点像这样:
这里写图片描述
透过这样的动作,我们就可以轻易的将模块编译起来,并且还可以将他直接放置到核心模块目录中, 同时以 depmod 将模块建立相关性,未来就能够利用 modprobe 来直接取用! 但是需要提醒你的是,当自行编译模块时, 若你的核心有更新 (例如利用自动更新机制进行在线更新) 时,则你必须要重新编译该模块一次, 重复上面的步骤才行!因为这个模块仅针对目前的核心来编译的啊!

二、利用旧有的核心原始码进行编译
如果你后来发现忘记加入某个模块功能了,那该如何是好?其实如果仅是重新编译模块的话, 那么整个过程就会变的非常简单!我们先到目前的核心原始码所在目录下达 make menuconfig , 然后将 NTFS 的选项设定成为模块,之后直接下达: make fs/ntfs/
那么 ntfs 的模块 (ntfs.ko) 就会自动的被编译出来了! 然后将该模块复制到 /lib/modules/2.6.30.3vbird/kernel/fs/ntsf/ 目录下, 再执行 depmod -a ,就可以在原来的核心底下新增某个想要加入的模块功能~

26.4.3. 核心模块管理
核心与核心模块是分不开的,至于驱动程序模块在编译的时候,更与核心的原始码功能分不开~ 因此,你必须要先了解到:核心、核心模块、驱动程序模块、核心原始码与头文件案的相关性, 然后才有办法了解到为何编译驱动程序的时候老是需要找到核心的原始码才能够顺利编译! 然后也才会知道,为何当核心更新之后,自己之前所编译的核心模块会失效~
此外,与核心模块有相关的,还有那个很常被使用的 modprobe 指令, 以及开机的时候会读取到的模块定义数据文件 /etc/modprobe.conf , 这些数据你也必须要了解才行~相关的指令说明我们已经在第二十章内谈过了, 你应该要自行前往了解!

猜你喜欢

转载自blog.csdn.net/kk53976047/article/details/79659723