Thinking in XiaoQiang
世人皆有悲哀,只有你不明白
posts - 56,comments - 150,trackbacks - 0
使用预编译的 RPM 以及从源代码编译应用程序

级别: 初级

Chris Walden
电子商务架构师, IBM Developer Relations
2004 年 1 月

Column iconIBM 电子商务架构师 Chris Walden 将通过他在 developerWorks 上发表的九篇系列文章来指导您如何在 Linux 环境中运用您的 Windows 操作技巧。在这最后一部分中,我们将下载和编译一个软件包,讨论自动化包管理的优点和缺点,同时了解 RPM 系统。

安装 Linux 时首先注意到的事情之一,就是 Linux 发行版本中有如此多可用的包。大多数发行版本都附带了 Linux 操作系统、安装工具和管理工具。它们还包括 Internet 工具、开发工具、办公工具、游戏,以及一些您不曾听说过的程序。Linux 发行版本附带 数千个可用包的情况并不鲜见。如果您没有选择“完整安装”,则只会安装这些包的一个子集。

现在您可能想知道“如何删除不想要的包?如何安装遗漏了的包?是否能够使用不是该发行版本附带的软件?”

RPM
在安装 Linux 时,您或许会注意到关于正在安装的 RPM 的许多信息。 RPM 代表 Redhat Package Manager(Redhat 包管理器),这是 Redhat 的贡献,现在已成为管理 Redhat 和 UnitedLinux 以及其他许多发行版本上的软件的标准。

RPM 本质上就是一个包,包含可以立即在特定机器体系结构上安装和运行的 Linux 软件。例如,在“ 第 3 部分. Webmin 简介”中,我们通过一个 RPM 安装了 Webmin 包。最初加载到发行版本中的所有软件都是通过一个 RPM 来安装的。

RPM 剖析
RPM 是文件包。它包括的 .spec 文件提供了关于包及其功能和依赖关系(即在该包能够运行之前必须安装其他哪些包)的信息。.spec 还包含包中的文件清单,指定这些文件必须加载到系统中的何处,以及它们的初始权限如何。RPM 还包含安装前脚本,这是由包开发人员编写的。RPM 其次还包含已编译的二进制文件。最后,RPM 包含了安装后脚本。

RPM 结构
.spec 安装前脚本 二进制文件 二进制文件 ... 二进制文件 安装后脚本

在安装 RPM 时,系统首先检查该包的依赖关系是否得到满足。如果不满足, 安装过程就会终止,除非您指定了迫使安装无论如何都要继续的选项。

如果一切顺利,安装前脚本就会运行。这个脚本可以做任何事情。它通常创建用户和目录。然而,它可以做许多类型的动态配置,甚至以自定义的方式编译运行系统的源代码。

了解 RPM 来自何处
RPM 在安装时将文件复制到您的系统上,并执行脚本。由于 RPM 是以 root 身份运行的,因此所有这些功能都以 root 身份执行。因而在将某个 RPM 安装到系统之前,知道它的由来是很重要的。就像许多 Windows 软件一样,恶意的代码可以像包含在其他包中一样容易地包含在 RPM 中。来自厂商的 RPM 一般都是安全的,但是要对从未知来源随机下载和安装的内容保持警惕。

如果安装前脚本成功完成,二进制文件将依照清单被复制到系统上。在复制完所有的文件和设置了它们的权限之后,安装后脚本就会运行。同样,这个脚本几乎能够做任何事情。

一旦完成所有这些步骤,关于包的信息就被添加到 RPM 数据库,安装过程就完成了。使用这种简单的机制,您能够执行通过更完善的商业安装程序所能执行的所有功能。

RPM 数据库
RPM 的优雅之处是 RPM 数据库。这个数据库通常位于 /var/lib/rpm 目录,它包含关于系统上已安装的每个 RPM 的信息。这个数据库知道包之间的依赖关系,当删除某个包将导致其他包无法工作时,它将发出警告。这个数据库知道最初随某个包安装的每个文件以及这些文件在系统上的最初状态。它还知道每个包的文档和配置文件的位置。这听起来好像是大量的信息,事实上确实如此。但它并不是过多而庞大的。在一个包含 1,066 个包、由 203,272 个文件组成的系统上,数据库文件仅有 45 MB!在加载和卸载包时,RPM 使用这个数据库来检查依赖关系。用户还可以在这个数据库中查询关于包的信息。

使用 RPM
配合 RPM 包使用的程序被相应地命名为 rpmrpm 以多种不同的模式运行,不过最常见的任务是安装、升级、查询、验证和删除。

rpm -i (装)
在第一次安装某个包时,您要使用 -i 或安装模式。只需将 rpm 指向某个二进制包并执行它, rpm 就会把该包安装到您的系统上。安装过程一般只需几秒钟。我经常会在安装包时使用 -v (详细)开关来提供关于该过程的更多信息,以及使用 -h (哈希线)开关来通过输出在控制台上的哈希(#)符号提供安装进度更新。下面是安装某个包的例子:

清单 1. 安装 MyPackage

$ rpm -ivh MyPackage-1.0.0.i386.rpm
Preparing...                ########################################### [100%]
   1:MyPackage              ########################################### [100%]

就是这个样子!MyPackage 现在已经安装完成,可供使用了。

rpm 必须以 root 身份运行
必须以 root 身份执行 rpm 安装和删除,因为需要访问文件系统和 rpm 数据库。

rpm -e (删除)
要删除已安装的包,可使用 -e 开关。 rpm 将使用数据库来删除该包的所有文件。如果有已安装的其他包依赖正在删除的包, rpm 将会异常退出。您必须使用 nodeps 开关来执行强制删除( nodeps 还可以用于强制安装)。在使用这个开关来强制安装或删除时,务必 非常 小心。删除其他包所依赖的包,可能会导致灾难性的结果。下面这个命令删除我们在上面安装的包:


$ rpm -e MyPackage

注意,包的删除并不一定需要它的完整名称(包括版本号)。安装时需要完整名称,因为我们是在引用一个文件名称。已安装的包仅通过它们的名称来引用。包的名称是版本号之前的所有内容。

rpm -V(验证)
验证开关非常有用。它将包文件的当前状态与它们在安装时的原始状态作比较。两种状态之间的区别将用一个代码来显示:

文件验证结果

S 文件大小不一致
M 模式不一致(包括权限和文件类型)
5 MD5 校验和不一致
D 设备主要/次要编号不匹配
L readLink(2) 路径不匹配
U 用户拥有关系不一致
G 群组拥有关系不一致
T mTime 不一致

如果您对某个包运行 rpm -V ,并且发现某个可执行文件的大小发生了变化,那可能就是安全漏洞的征兆。

rpm -U(升级)
一旦某个包已经安装,尝试安装具有相同名称的包将产生一条消息,指出该包已经安装。 如果想要将某个包升级到更新的版本,可使用 -U 开关来升级。升级还具有另一个影响。当对多个包名称运行升级时,它将设法按依赖关系的顺序放置包。换句话说,必需的包将首先安装。不管某个包是否已经安装,都可以对它使用升级开关,许多人使用它而不是使用 -i 开关来执行安装和升级。下面是使用升级开关来加载多个 rpm 包的例子:

清单 2. 交互式升级

$ rpm -Uvh My*.rpm
Preparing...                ########################################### [100%]
   1:bMyPackageDep          ########################################### [ 50%]
   1:aMyPackageNew          ########################################### [100%]

在上面的例子中,bMyPackageDep 是 aMyPackageNew 的前提条件,因此尽管文件名称以相反的顺序排列, rpm 也会对它们正确排序。

rpm -q(查询)
可以从 rpm 数据库中查询多种有用的信息。对 rpm 数据库拥有读访问权限的任何用户都能够运行查询。默认情况下,全部用户都拥有读访问权限。要运行一个查询,可使用 -q 开关带上要查询的包的名称。这样将返回该包的版本。


$ rpm -q MyPackage
          
MyPackage-1.0.0

包的名称必须精确匹配,不允许使用通配符。然而,如果记不住包的完整名称,您可以使用 grep 工具来帮助找到它。可以使用 -qa 开关来查询所有已安装的包,并用 grep 来管道输出您能记住的信息。例如:

grep 之乐
grep 是一个具有广泛用途的文本搜索工具。默认情况下, grep 将搜索文件以显示您指定的行。在这里的例子中,它搜索单词“IBM”。 grep 是脚本编写和控制台工作方面的一个强大工具。


$ rpm -qa | grep IBM
          
IBMWSAppDev-Product-5.0-0
IBMWSSiteDevExp-Core-5.0-0
IBMWSSiteDev-Core-5.0-0
IBMWSTools-WAS-BASE-V5-5.0-0
IBMJava118-SDK-1.1.8-5.0
IBMWSWB-samples-5.0-0
IBMWSWB-5.0-0
IBMWSAppDev-Core-5.0-0
IBMWSAppDev-5.0-0
IBMWSTools-5.0-0

除了版本号外, rpm -q 还可以提供关于包的其他有用信息。下面就是这样一些例子:

使用 rpm 查询获取信息
rpm -q changelog 显示包的开发变更历史记录
rpm -qc 显示包的配置文件
rpm -qd 显示包的文档文件
rpm -qi 显示包描述
rpm -ql 显示包的文件的列表
rpm -qR 显示包的依赖关系

还有另一个有趣的查询命令,它针对文件而不是针对包运行。


rpm -q whatprovides <filename>

上面这个命令将识别与给定的 filename(文件名)相关联的包。filename 必须包括文件的绝对路径,因为信息就是以这种方式存储在 rpm 数据库中的。

RPM 前端
从控制台操作 rpm 很容易,但有时使用图形用户界面会更方便。在典型的 Linux 风格中,有一些前端程序为 rpm 程序提供界面。每种发行版本都有一个前端,但是它们各不相同。请参考您的发行版本文挡,以了解关于所提供的包管理工具的信息。

Webmin 软件包
Webmin 也为处理 RPM 包提供了一个基于 Web 的简单前端。

图 1. Webmin RPM 界面
图 1. Webmin RPM 界面

软件可以从这个界面容易地安装、删除和查询。还可以直接从 URL 站点安装软件。如果安装了诸如 apt 或 Redhat Network 之类的 rpm 增强工具,Webmin 将识别它们并为它们提供一个界面。

源代码
由于 Linux 是开放源代码的操作系统,它附带了编译软件所需的所有开发工具。虽然您使用的大多数包将以二进制 RPM 的形式提供,但是您并不仅限于使用那些包。如果愿意,您可以为您的系统下载原始源代码,并以自定义的方式进行编译。

应该对在生产系统上编译源代码保持谨慎,因为这样可能导致问题,或者不再支持系统上正在使用的商业软件(比如 IBM DB2)。然而,熟悉从源代码编译软件的过程将使您能够对软件应用补丁,以及使用从其他环境移植过来的包。一旦成功地编译代码,创建您自己的 RPM 也是可以做到的!

Corewars 源代码演示
为演示从源代码编译软件有多简单,我们将编译一个名为 Corewars 的模拟游戏(请参阅 参考资料)。下面是来自他们 Web 站点的关于 Corewars 的说明:“Corewars 是一款模拟游戏,其中许多武士在虚拟的计算机中奔跑时竭力相互攻击对方。可以采用两种类似汇编程序的语言中的一种来编写武士程序,这两种语言分别叫做 Corewars 和 Redcode。Corewars 是默认语言,更易于学习和理解。Redcode 提供更高级和更强大的指令,但是需要更多的时间来学习。”

编译源代码的第一步是从 Web 站点下载源代码包:

在代码下载完成之后,需要展开这个包。


tar -xvzf corewars-0.9.13.tar.gz

文件将展开到当前目录。标准的做法是将源代码包含在一个与产品名称匹配的目录中。在此例中,源代码位于一个名为 corewars-0.9.13 的目录。

首先进入该目录,找到源代码和一些文档、配置脚本和 README 文件。大多数源代码包都带有一个名为 INSTALL 和一个名为 README 的文件。您应该在编译软件之前首先阅读这些材料。它们在问题出现之前识别问题,并为您建议正确的编译和安装步骤,这样通常可以让您少走许多弯路。我在编译源代码时遇到的大多数问题都是因为我没有遵循那些指导。

通常执行的下一步是运行 configure 脚本。 configure 是 Autoconf 包的一部分,包括在 Linux 发行版本的开发工具中。这里引用一段 Autoconf 的包描述:“GNU 的 Autoconf 是一个用于配置源代码和 Makefile 的工具。通过使用 Autoconf,程序员能够创建可移植和可配置的包,因为建立包的人可以指定各种配置选项。”

configure 脚本在系统上运行一系列测试,以确定为您的发行版本和系统体系结构编译包的最佳方式。然后它为您的系统创建一个定制的 Makefile。如果在您的系统上编译时遇到问题, configure 将会告诉您。 configure 通常允许您自定义将要在编译中包括的特性,或允许您提供关于库或者其他必需文件的位置参数,以便能够成功地编译包。下面我们将不带参数执行 configure


./configure

在系统上多执行几次测试,最终就会编译成功。下面使用如下命令来生成程序:


make

如果编译有错误,就需要确定问题并修复它们。这可能是一件繁琐的任务,也许需要关于环境和程序设计的大量一般知识。如果一切顺利,我们一般会使用以下命令来安装软件:


make install

文件将被复制到系统中的正确位置,文件权限会被更新,配置文件将被复制,文档也会被添加到手册页。

现在通过执行该程序来测试我们的劳动成果。它是一个图形化的程序,因此要在启动它前运行 X 系统。上面执行的 make install 命令应该已将程序放到了可执行文件路径中。


corewars

作为对我们的奖赏,一个图形化的屏幕应该会出现。

图 2. 大功告成!
图 2. Corewars 游戏

corewars 规则的主题超出了本文的讨论范围,不过您会在手册页( man corewars )中找到关于这款有趣的模拟游戏的文档。

corewars 的编译是一个典型的场景。可能会有其他许多种变化形式,包括在 configure 脚本上使用开关来调整要编译到程序中的特性,以及从 Makefile 使用不同的命令来调整编译方式,等等。

由于这个程序不是使用 rpm 来安装的,因此 rpm 数据库中没有相应的条目。如果某个程序在安装后没有按预期运行,大多数 Makefile 都包括了一个卸载参数来删除软件:


make uninstall

务必牢记,使用原始源代码不会在 RPM 数据库中添加任何内容。以这种方式安装的软件是非托管的(unmanaged),因此应该小心进行。

源代码 RPM
当 RPM 被创建时,还有一个称作源代码 RPM 的产物。这是一个与源代码组合在一起的 SPEC 文件,设计它的目的是为了在一个或多个体系结构上生成程序。这对源代码和二进制这两个世界来说是最佳的!对于源代码 RPM,您可以在系统上定制编译软件,但是完成的产品将是一个可安装的 RPM,而不是原始的二进制。以预编译 RPM 的形式可用的大多数包还以 SRPM 的形式可用。这也许是在 Linux 中软件跨平台转移的简单途径。当您在一个不同的平台上成功地重新编译时,可考虑与整个开发社区共享完成的 RPM。

也许源代码更适合您
如果您是 Linux 新手,安装软件的方法与您过去习惯使用的方法不同。然而,RPM 安装方法是优雅的,同时提供了您很快就会欣赏的新能力。

您应该熟悉从控制台使用 rpm 的选项,不过对于日常使用,有一些前端界面选项使得 rpm 更易于管理。您的发行版本提供了这样一个界面,也有其他类似的界面可供使用,比如 Webmin 中的那一个界面。

您并不仅限于使用预编译的 rpm,还可以利用 Linux 的开放源代码性质,直接从源代码编译应用程序。对于成熟的项目,编译通常是很容易的。记住,从源代码安装的代码在 rpm 数据库中没有相应的条目。在使用源代码时,可考虑使用源代码 rpm,它组合了已编译源代码的强大能力和 rpm 的可管理性。

参考资料

关于作者
Chris Walden 是位于德克萨斯州奥斯汀的 IBM Developer Relations Technical Consulting(也称为 dragonslayers )的一名电子商务架构师,该公司为 IBM 商业伙伴提供教育、实现和咨询。他致力于 Linux 相关工作,一有机会就向身边的人宣传 Linux 的种种好处。除了完成他的架构师的职责之外,他还精通 Linux 基础设施服务器的各个领域,包括混合平台用户环境下的文件、打印以及其他应用服务等。Chris 有 10 年的计算机行业经验,从现场支持到 Web 应用开发和顾问,各个领域他都曾涉足。您可以通过 cmwalden@us.ibm.com 与 Chris 联系。
posted on 2005-10-27 09:31 小强 阅读(240) 评论(0)  编辑  收藏 所属分类: Linux

只有注册用户登录后才能发表评论。


网站导航: