在 Red Hat Linux 7.1 上使用 RPM
简介: RPM 是广泛使用的用于交付 Linux 软件的工具,用户可以轻松的安装用 RPM 打包的产品。在本文中(系列文章的第 1 篇),IBM 软件工程师 Dan Poirier 向您演示如何在 Red Hat Linux 7.1 系统上用 RPM 打包简单软件。
发布日期: 2001 年 11 月 01 日
级别: 初级
访问情况 782 次浏览
建议: 0 (添加评论 )
RPM(Red Hat Package Manager)是用于 Linux 分发版(distribution)的最常见的软件包管理器。因为它允许分发已编译的软件,所以用户只用一个命令就可以安装软件。
RPM 是 Linux“标准基本库”版本 1.0.0 指定的安装工具。在 Linux 分发版前 10 名中,有 8 个是基于 RPM(请参阅“Comparison of Linux Distributions”,它位于本文后面的 参考资料 中列出的 distrowatch.com 上)。即使某些通常不使用 RPM 的分发版,如 Debian,也有可用工具将 RPM 转换成它们自己的格式。在 Linux 上,对于除开发人员以外的任何人,RPM 也是用来打包软件的最佳选择。
不论您是自己开发软件,还是通过提供代码以从中创建 RPM 软件包向开放源码项目提供帮助,本文都会帮助您入门。顺便要说的是,本系列的后续文章会涉及下列主题:构建 RPM 软件包而未必是 root 用户,在构建软件之前为其打补丁,安装和卸载时运行脚本以及在安装或卸载 其它 软件包时运行脚本。
我将从简单的实例开始,主要使用 RPM 缺省值。然后,我会添加上几个可选特性。
RPM 软件包从源文件形式的程序开始,作好了编译准备。我不想创建一个没有实际意义的示例,而是选择使用 GNU Indent 程序(请参阅 参考资料 )。
在 Linux 下创建 Indent 非常容易。 indent-2.2.6.tar.gz 文件位于当前目录之中,所有您要做的就是:
$ tar xzf indent.2.2.6.tar.gz |
如果您已经构建过很多开放源码项目,那么这可能看起来很熟悉。 unpack;./configure;make;make install 序列是典型的使用 GNU 自动配置(autoconf)工具的软件。因为这太普通了,所以我在这里描述的关于 indent 的大部分东西,几乎不加改变就可以用于其它开放源码项目。
现在假设您正在使用 Red Hat 7.1。在本文的后面,我将给出一些 在其它 Linux 分发版上使用 RPM 的建议 。
在 Red Hat 7.1 上, 在继续以前,请确保您已安装了 rpm-build 软件包。 为检查是否安装,请运行 rpm -q rpm-build 。您应该看到一些类似于 rpm-build-4.0.2-8 的信息(版本可能会不同)。如果您看到的是 package rpm-build is not installed ,则将需要从 Red Hat 安装 CD 上安装它。
为了构建 RPM 软件包,您需要写一个名为 spec 文件的 RPM 输入文件,该文件告诉 RPM 如何构建和打包您的软件。编写 spec 文件您需要:
- 创建文件 indent-1.spec ,如下所示。您可以任意地给它命名并把它放到任何地方;RPM 对这些没有要求。
- 以 root 用户登录。
- 将 indent-2.2.6.tar.gz 文件复制到 /usr/src/redhat/SOURCES。
- 运行
rpm -ba indent-1.spec,将 indent-1.spec 改为您使用的名字。
Summary: GNU indent |
您应该看到 RPM 解包这个 tar 文件,编译并安装它。 在 Red Hat 7.1 上,工作目录将是 /usr/src/redhat/BUILD。
最后,RPM 将创建两个 RPM 文件。将在 /usr/src/redhat/SRPMS/indent-2.2.6-1.src.rpm 中创建一个源 RPM 文件,而在 /usr/src/redhat/RPMS/i386/indent-2.2.6-1.i386.rpm 中创建一个二进制 RPM 文件。
源 RPM 文件简单地捆绑了 spec 文件和构建软件包用到的所有源文件和补丁文件。如果您选择分发它,则其他人可以很容易地用它重建您的软件。二进制 RPM 文件仅包含已编译的软件和如何安装的信息。
下面总结了在您运行 rpm -ba filename.spec 时,RPM 都做些什么:
- 读取并解析 filename.spec 文件
- 运行
%prep部分来将源代码解包到一个临时目录,并应用所有的补丁程序。 - 运行
%build部分来编译代码。 - 运行
%install部分将代码安装到构建机器的目录中。 - 读取
%files部分的文件列表,收集文件并创建二进制和源 RPM 文件。 - 运行
%clean部分来除去临时构建目录。
spec 文件有几个部分。第一部分是未标记的;其它部分以 %prep 和 %build 这样的行开始。
头
第一部分(未标记)定义了多种信息,其格式类似电子邮件消息头。
Summary 是一行关于该软件包的描述。
Name 是该软件包的基名, Version 是该软件的版本号。 Release 是 RPM 本身的版本号 ― 如果修复了 spec 文件中的一个错误并发布了该软件同一版本的新 RPM,就应该增加发行版号。
License 应该给出一些许可术语(如:“GPL”、“Commercial”、“Shareware”)。
Group 标识软件类型;那些试图帮助人们管理 RPM 的程序通常按照组列出 RPM。您可以在 /usr/share/doc/rpm-4.0.2/GROUPS 文件看到一个 Red Hat 使用的组列表(假设您安装的 RPM 版本是 4.0.2)。但是您还可以使用那些组名以外的名称。
Source0 、 Source1 等等给这些源文件命名(通常为 tar.gz 文件)。 %{name} 和 %{version} 是 RPM 宏,它们扩展成为头中定义的 rpm 名称和版本。因此,在这个实例中, Source0 被设置为 indent-2.2.6.tar.gz 。
不要在 Source 语句中包含任何路径。缺省情况下,RPM 会在 /usr/src/redhat/SOURCES 中寻找文件。请将您的源文件复制或链接到那里。(要使 spec 文件尽量可移植的话,应当尽量避免嵌入自己开发机器上的假想路径。其他开发人员就可以指示 RPM 在别的目录下查找源文件,而不用修改您的 spec 文件。)
描述
接下来的部分从 %description 行开始。您应该在这里提供该软件更多的描述,这样任何人使用 rpm -qi 查询您的软件包时都可以看到它。您可以解释这个软件包做什么,描述任何警告或附加的配置指令,等等。
Shell 脚本
下面几部分是嵌入 spec 文件中的 shell 脚本。
%prep 负责对软件包解包。在最常见情况下,您只要用 %setup 宏即可,它会做适当的事情,在构建目录下解包源 tar 文件。加上 -q 项只是为了减少输出。
%build 应该编译软件包。该 shell 脚本从软件包的子目录下运行,在我们这个例子里是 indent-2.2.6 目录,因而这常常与运行 make 一样简单。
%install 在构建系统上安装软件包。这似乎和 make install 一样简单,但通常要复杂些。我将在下面解释这点。
文件列表
%files 列出应该捆绑到 RPM 中的文件,并能够可选地设置许可权和其它信息。
在 %files 中,您可以使用 一次 %defattr 来定义缺省的许可权、所有者和组;在这个示例中, %defattr(-,root,root) 会安装 root 用户拥有的所有文件,使用当 RPM 从构建系统捆绑它们时它们所具有的任何许可权。
可以用 %attr(permissions,user,group) 覆盖个别文件的所有者和许可权。
可以在 %files 中用一行包括多个文件。
可以通过在行中添加 %doc 或 %config 来标记文件。 %doc 告诉 RPM 这是一个文档文件,因此如果用户安装软件包时使用 --excludedocs ,将不安装该文件。您也可以在 %doc 下不带路径列出文件名,RPM 会在构建目录下查找这些文件并在 RPM 文件中包括它们,并把它们安装到 /usr/share/doc/%{name}-%{version} 。以 %doc 的形式包括 README 和 ChangeLog 这样的文件是个好主意。
%config 告诉 RPM 这是一个配置文件。在升级时,RPM 将会试图避免用 RPM 打包的缺省配置文件覆盖用户仔细修改过的配置。
警告: 如果在 %files 下列出一个目录名,RPM 会包括该目录下的所有文件。通常这不是您想要的,特别对于 /bin 这样的目录。
这个最基本的 spec 文件有几个问题。最大的问题之一就是您最后在构建系统上实际安装了该产品。而这可能只是一个软件测试版本,您也许并不想在构建系统中安装它。
RPM 用一个名为 构建根(build root) 的特性来处理这个问题。它的想法是设置您的 spec 文件,以将所有安装的文件复制到一个虚拟目录树(从构建根开始);然后 RPM 从那里得到文件。
但是,这需要一些软件包的支持。在包括 indent 在内的很多 GNU 软件包中,在 make install 的时候定义 DESTDIR 将会在所有安装路径之前添加 DESTDIR 值。
请注意 不 要使用 ./configure --prefix=$RPM_BUILD_ROOT 。这会在假设整个软件包文件的最终位置是构建根的情况下安装整个软件包。这对于 indent 可能没有关系,但任何需要在运行时找到其安装文件的程序都将失败,因为当 RPM 最终安装到用户系统后,这些文件就不再位于构建根之下 ― 那只是您构建系统上的一个临时目录。
请参阅更新的文件 indent-2.spec ,如下所示。
Summary: GNU indent |
首先,我们增加了版本的发行号。无论何时,当您编辑 spec 文件时,都不要忘了这么做。
我们在头中添加了 BuildRoot,以便告诉 RPM 这是在构建期间临时安装文件的地方。对于临时文件,我们这里使用了两个 RPM 宏,而不是假设某个特定位置。在 Red Hat 7.1 上, %{_builddir} 以类似于 /usr/src/redhat/BUILD 结束。
我们还需要告诉系统将 indent 安装在那里。RPM 帮助我们用构建根的值定义一个 shell 变量 RPM_BUILD_ROOT ,因此在 make install 时,我们只需将它作为 DESTDIR 值传入即可。
我们还在 %install 和 %clean 中添加了几行,以便在开始安装以前(为保险起见)和完成以后清除构建根。%clean 是一切都正常的情况下在 RPM 构建结束时运行的脚本,这样临时文件就不会一直保留。
最后,在 %files 中,请注意我们没有在此处的路径前包括 BuildRoot。我们使用了“真正”的路径;RPM 将在构建根下寻找这些文件,因为您已经包括了 BuildRoot 定义。
如果仔细观察您会发现,在 RPM 进行安装部分以前,一切工作照旧。然后,文件将不直接安装到 /usr/local/bin,而是安装在(比如说)/usr/src/redhat/BUILD/indent-root/usr/local/bin 中。
如果您检查最终的二进制 RPM 文件(用 rpm -qlp indent-2.2.6-2.i386.rpm ),您会看到构建根已被 RPM 除去。如果您安装 RPM,这些文件最终将安装在正确的目录,如 /usr/local/bin/indent 中。
如果您在使用不同的 Linux 分发版,RPM 可能会有不同的内置路径。例如,它几乎肯定不会在 /usr/src/redhat 查找源文件!要确定希望的 RPM 安装路径,请运行 rpm --showrc 并查看下列部分如何被定义:
-
_sourcedir
- RPM 在哪里查找源文件(tar 文件,等) _srcrpmdir
- RPM 在哪里放入新的源 RPM 文件 _rpmdir
- RPM 将把新的二进制 RPM 文件放在哪里(在特定于体系结构的子目录中)
其中一些根据其它变量定义;例如,当您看到 %{_topdir} ,查找 _topdir 的定义,等等。
我希望这篇用 RPM 打包软件的介绍会对您有所帮助。有关相关的阅读材料,请参阅下面的 参考资料 。在本系列的后续文章中,我们将讨论这些主题:
- 构建 RPM 软件包而不必是 root 用户
- 在创建软件之前为软件打补丁
- 在安装和卸载时运行脚本
- 在安装或卸载 其它 软件包时运行脚本
正如您在第 1 部分中看到的那样,构建 RPM 软件包通常要求您以 root 用户登录。 其原因如下:
- RPM 在打包过程中安装软件,并且通常只有 root 用户可以写到安装目录中。
- RPM 需要读写 /usr/src/redhat(一般用户不能修改它)下的目录。
我们在 第 1 部分 中探讨了通过用 RPM 构建根(build root)来解决第一个问题。
要解决第二个问题,可以通过更改 %_topdir 设置来告诉 RPM 查找和创建不同目录集中的文件。按照下面的方法在您的主目录下创建一个名为 .rpmmacros的文件:
%_topdir /home/your_userid/rpm
这个文件会告诉 RPM:它先前在 /usr/src/redhat 下查找的所有目录应该改为在 /home/your_userid/rpm 下查找。 现在,您应该创建这样一个完整的目录树:~/rpm ~/rpm/SOURCES ~/rpm/SPECS ~/rpm/BUILD ~/rpm/RPMS ~/rpm/RPMS/i386 ~/rpm/SRPMS
~/rpm
~/rpm/SOURCES
~/rpm/SPECS
~/rpm/BUILD
~/rpm/RPMS
~/rpm/RPMS/i386
~/rpm/SRPMS
(如果愿意,可以通过在 RPM 中重新定义其它宏,来将其中任何目录放在您想放的任何地方。您可能需要考虑更改的一些宏包括 %_sourcedir 、 %_specdir 、 %_srcrpmdir 、 %_builddir 和 %_rpmdir 。 有关这些宏的缺省值,请查看 /usr/lib/rpm/macros。 对于这个示例,我们仅仅将它们都放在 ~/rpm 下。)
现在,将 indent-2.2.6.tar.gz 文件(请参阅本文后面的 参考资料 )复制到 ~/rpm/SOURCES,这里 没有以 root 用户登录 ,运行 rpm -ba indent-2.spec (这些文件就是 第 1 部分 中的那些文件)。RPM 将 把 indent 构建在 ~/rpm/BUILD 目录下,并将二进制的 RPM 包放在 ~/rpm/RPMS/i386 中,将源代码包放在 ~/rpm/SRPMS 中。
与之相对照,在没有构建根的情况下,尝试使用 spec 文件 indent-1.spec 。RPM 在尝试将 indent 安装到 /usr/local/bin 中时会失败。
使用构建根和设置 RPM 的 i%_topdir 使您能在不作为 root 运行的情况下构建许多软件包,但这并不总是很容易。
首先,一些包并不象 indent 那样可以容易地安装到构建根目录中。对于那些任何未用 GNU autoconf 来开发的包,您必须要仔细查看一下,看是否有一种方法,可以将包安装到另一个目录中, 这也许可以修改 Makefile 来强制这样做。 在下一部分中,我将向您演示如何使用 RPM 来构建已修改的程序。
其次,只有相当少部分包将在其正常安装期间试图做一些只有 root 用户才可以做的事情,如:
- 创建特殊文件(管道、设备文件等等)
- 修改系统配置文件`
您必须逐个处理这些问题。通常,您可以在 post-install 脚本(在安装 RPM 之后运行的脚本)中做一些必要工作。 我将在以后的文章中讨论它们,但简而言之,可以将“%post”节添加到 spec 文件中, 并在该节中放置一些 Linux 命令,以便在安装 RPM 之后运行这些命令。
假设您有一些要打成 RPM 包的软件, 但如果不对它做一些更改,就不能在 Linux 上构建它。 然而,您又没有拥有该软件,所以不能正式地更改它。
您所需要做的就是对该软件的正式版本进行 打补丁 或做一些修改。 但是,对其他人的软件进行修改,然后再分发此修改过的版本通常被认为是不礼貌的,所以您希望您自己所做的更改对别人来说也是可用的。 这样,使用您的包的任何人都可以看到您做了哪些事情以及确定您所做的更改是否是可接受的。
这是常有的事,而且 RPM 也提供一些帮助。 您可以建立一个 RPM 包,以便二进制 RPM 文件包含您对程序所做的修改,并且源 RPM 不仅包含原始的源代码, 而且还包含您所做的更改以及有关如何应用和构建这些更改的所有详细信息。
这些步骤如下:
- 断定对源代码做哪些更改就可使软件工作。
- 创建一个 补丁 文件来捕获您所做的更改。
- 将该补丁添加到 RPM spec 文件。
通常,要做的第一件事是,在没有 RPM 的情况下编译并运行软件。明了必须要更改的那些文件。 如果有必要,可创建一些新文件或除去与原始源代码一起交付的一些文件。
对于这个示例,我将代码抽取到目录 indent-2.2.6-working 中。我修改了 indent.c, 以便在程序启动时打印一条表示友好的消息,然后验证该程序是否仍可以构建以及该程序是否仍能工作。
现在,您希望创建一个仅捕获您所做更改的补丁文件。 这里有一种可以实现这的方法。虽然这有点儿乏味,但能够确保您捕获所有更改。
- 将软件完全抽取到一个新目录中,然后复制您已对其做过更改的文件,使其覆盖刚抽取出的那些文件。 这样,在本来应该在您先前构建和测试软件时创建的目录中就不会有任何多余的文件。 类似地,复制您创建的任何新文件,并删除任何您先前删除过的文件。
对于这个示例,我已完全抽取到目录 indent-2.2.6-my,并覆盖文件 indent.c。
- 再一次将软件抽取到另一个目录。这样就提供了一个原始软件的副本来与您的软件进行比较。对于这个示例,我是将软件抽取到 indent-2.2.6 目录。
现在,已有三个目录:
-
indent-2.2.6-working
- 工作目录 indent-2.2.6-my
- 经过更改的软件,其中含有我所做的更改 indent-2.2.6
- 未更改的软件
- 从这三个目录的父目录中用类似于以下的命令生成补丁文件:
diff -uNr indent-2.2.6 indent-2.2.6-my >indent-2.2.6.patch
注意,使用 diff 时运用了选项 -uNr 。 -u 以 统一 格式创建补丁文件,这种格式比缺省格式更紧凑些。 -N 确保补丁文件将正确地处理已经创建或删除文件的情况。 -r 比较命令行上所给出的两个目录的所有子目录中的所有文件。
另外还要注意:只要您完全按上述来做,这些目录名是无关紧要的。 补丁文件中将有这些目录名,但我们将通知补丁程序忽略它们。
现在,检查一下补丁文件 indent-2.2.6.patch。下面是我的示例:
diff -uNr indent-2.2.6/indent.c indent-2.2.6-my/indent.c |
有时候,您会注意到 diff 检查出了您无意要做的更改。 这时,您可能需要回过去,清除您的代码并再次生成补丁,直到获得一个干净的、令您满意的补丁文件为止。
一旦按您所希望的那种方式完成补丁之后,最好添加注释以说明您所做的更改。 在不损害任何内容的情况下,在补丁文件的开始处或结束处添加文本。
Dan Poirier - 2001-09-26 - added a friendly greeting as indent starts. |
现在,该让 RPM 使用您的补丁了。将该补丁文件复制到您的 SOURCES 目录(如果您遵循了先前的建议,则或许是 ~/rpm/SOURCES),然后对 spec 文件做下列更改:
清单 3. indent-3.spec:使用 indent-2.2.6.patch
Summary: GNU indent |
现在,用 rpm -ba indent-3.spec 命令构建您的包。 如果您密切关注构建过程的话,会看到在构建期间 RPM 应用了您的补丁。
%Patch0: %{name}-2.2.6.patch 这一行告诉 RPM 第一个补丁文件名。 如果有必要,可以添加 %Patch1 、 %Patch2 等。
在 %prep 部分中的 %patch -p1 行是一个 RPM 宏, 它将在您系统的构建目录中运行补丁程序,其中把第一个补丁文件作为输入。 需要将 -p1 传递给补丁程序,告诉它从补丁文件中的路径中剥去一层目录,因为该补丁文件包含 indent-2.2.6 目录名,而 RPM 将在该目录内运行该补丁文件。
既然,您理解了有关如何构建 RPM 包的基础知识,则可以通过研究一些示例来学习更多的知识。 最好的源代码示例之一是您自己的 Linux 分发版。例如,RedHat 带有包含源 RPM 包的整张 CD。 以下是如何使用它们。
源 RPM 包包含:
- 一个 .spec 文件
- 一个或多个源文件
- 所有使用过的补丁文件
与安装二进制 RPM 包类似,可以使用 rpm -i filename.rpm 安装源 RPM 包。 安装完之后,.spec 文件将在您的 %_specdir 目录中,源文件和补丁文件将在您的 %_sourcedir 目录中。 如果创建了上面描述的 .rpmmacros 文件,那么这些目录为 ~/rpm/SPECS 和 ~/rpm/SOURCES。
现在,可以读取 Red Hat 自己分发的这些包的 .spec 文件。 可以尝试用 rpm -ba foo.spec 构建这些 .spec 文件,并观察所发生的事情,以及摆弄 spec 文件以尝试一些新的事物。
对于 GNU indent 程序,一个好的方法是从 Red Hat 的源 RPM 包开始。看一下您是否可以想出为什么它们的 .spec 文件不同于本文中的 .spec 文件。
不幸的是,二进制 RPM 包在可移植性方面不是很好。多数情况下,构建在某个 Linux 分发版上的 RPM 不能应用到另一个 Linux 分发版。 更不要说应用到同一个分发版的另一个版本上!
原因有很多,包括基本内核版本、库版本和目录结构方面的差异。
这很不幸,但象 Linux Standard Base(请参阅 参考资料 )这样的组织正在尝试达到分发版之间的一致, 以解决难以移植的问题。也许有一天,构建在一个主流 Linux 分发版上的任何 RPM 都可以安装和运行在相同的处理器之上的任何 其它主流 Linux 分发版上。
至于现在,您应该做好计划,有多少个 RPM 将要在其上运行的分发版,就可能构建有多少个 RPM,或者寻找志愿者来为您完成这件事。
为了使其他人在尽可能多的分发版上构建您的软件,就要使 .spec 文件和补丁文件成为可用的文件。
如果有必要,最好的方法是直接更改软件,所以该方法将在 Linux 上进行构建,并将 .spec 文件包含在分发版中。 如果 .spec 文件在带有源码的 tar 压缩包(.tar.gz 文件)中,那么用户只需运行:
rpm -tb foo.tar.gz |
并构建该包的二进制 RPM ― 甚至无需解压该 tar 文件!
如果无法使 .spec 文件包含在软件中,则可以分发一个源 RPM 包。 有了这,用户就可以运行:
rpm --rebuild foo.src.rpm |
并在他们的系统上构建二进制 RPM。
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 .
- 本文中描述的文件源代码
- RPM 网站 有指向很多有用资源的链接。RPM 电子邮件列表是提问题的好地方。
- 要知道哪些 Linux 分发版是基于 RPM 的,请在 distrowatch.com 上参阅 "Comparison of Linux Distributions" 。基于 RPM 的分发版有 Red Hat 、 SuSE 、 Mandrake 、 TurboLinux 和 Caldera 。
- 获得 GNU Indent 程序 。
- Maximum RPM 是一本关于使用 RPM 的书。它相当过时了,但现在正在更新中。
- RPM HOWTO 也正变得有些过时了。它讲述了一些和本文一样的基础知识。
- Eric S. Raymond 的 Software Release Practice HOWTO 文档 并不特定于 RPM 或 Linux。它在如何发布软件以便用户使用和程序员提供修补和完善方面,有很多好的技巧。
- 自由软件基金会(The Free Software Foundation) 是提供 GNU Indent 和很多其它有用的软件包的来源。
- 请在 developerWorks 上浏览 更多 Linux 参考资料 。
- 请在 developerWorks 上浏览 更多开放源码参考资料 。
本文详细介绍如何使用RPM在Red Hat Linux 7.1上打包软件,包括创建基本RPM包、使用构建根避免安装问题、非root用户构建RPM及为软件打补丁等内容。
3011

被折叠的 条评论
为什么被折叠?



