`
netcome
  • 浏览: 467181 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用 RPM 打包软件,第 1 部分: 构建和分发包

rpm 
阅读更多

顾名思义,开源软件的主要优势就是允许了解应用程序的内部工作原理。有了源代码,您可以研究应用程序的工作原理,更改、改进和扩展其操作,(在应用程序许可允许下)借鉴代码并将其用于其他用途,以及将应用程序移植到新平台上。

然而,这种自由访问并不总是我们所需要的。例如,用户可能不希望从源代码进行构建。相反,他或她可能只想像传统 “紧凑包装” 的应用程序一样安装该软件:插入媒体、运行安装程序、回答一系列提示,然后运行应用程序。确实,对于大部分计算机用户来说,这种预构建的软件是他们最希望得到的。预构建代码对系统特性不那么敏感,因此更统一且可预测。

通常,预构建的开源应用程序称为,捆绑了运行应用程序所需的所有二进制文件、数据和配置文件。包还包括将应用程序部署到系统上所需的所有步骤,这些步骤通常以脚本形式提供。脚本可以生成数据,启动和停止系统服务,或者操作文件和目录。脚本还可以执行操作来将现有软件升级到新版本。

由于每个操作系统都具有自己的独特特性,所以包通常仅适用于特定系统。而且,每个操作系统提供了自己的包管理器,一个用于在系统中添加和删除包的特殊实用程序。例如,基于 Debian Linux® 的系统使用 Advanced Package Tool (APT),而 Fedora Linux 系统使用 RPM Package Manager。包管理器通过添加和删除包中的各个文件来来预防不完整和错误的安装,以及 “卸载” 应用程序。包管理器还维护着系统上安装的所有包的清单,可以预先检查前提条件和辅助条件是否满足。

如果您是一名软件开发人员或系统管理员,以包的形式提供应用程序可以使安装、升级和维护更加轻松。在本文中,您将了解到如何使用流行的 RPM Package Manager 捆绑实用程序。作为演示,您将捆绑网络实用程序 wget,该程序用于从 Internet 下载文件。wget 实用程序很有用,但在标准的系统分发版中很难找到它。(而类似的 curl 通常包含在系统分发版中。)您将发现,您可以使用 RPM 分发几乎所有内容(脚本、文档和数据),以及执行几乎所有维护任务。

手动构建 wget

wget 实用程序,与其他许多开源应用程序一样,可以手动构建。要将 wget 捆绑在一个包中,首先需要了解构建过程。根据一般约定,构建 wget 需要 4 个步骤:

  1. 下载并解压源代码。
  2. 配置构建版本。
  3. 编译代码。
  4. 安装软件。

您可以从 ftp.gnu.org 下载 wget 源代码的最新版本(参见 参考资料 获取链接,截至 2009 年 9 月末,wget 的最新版本为 1.12)。其余步骤需要在命令行操作,如 清单 1 所示。


清单 1. 安装 wget
				
$ tar xzf wget-latest.tar.gz
$ cd wget-1.12
$ ./configure
configure: configuring for GNU Wget 1.12
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... build-aux/install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
...
$ make
$ sudo make install

./configure 查询系统并设置适合于所选硬件和软件的编辑选项。make 编译代码,sudo make install 在系统目录中安装代码。默认情况下,安装的根目录为 /usr/local,但您可以对 ./configure 使用 --prefix=/some/full/path/name 选项来更改根目录。

要将此过程转换为 RPM,将源代码放在存储库中,编写一个配置文件来说明可在哪里找到要编译的源代码以及如何编译和安装代码。配置文件称为 spec 文件,是实用程序 rpmbuild 的输入。spec 文件和二进制文件被 rpmbuild 打包到一个 RPM 中。当其他用户下载您的 RPM 时,rpm 实用程序读取 spec 文件并根据预先编写的指令安装包。

构建您的第一个 RPM

在继续之前,需要注意一点。在过去,包只能由根用户和超级用户构建,因为只有根用户才能访问系统源代码库。但是,此方法具有一定的冒险性。因为根用户可以更改系统上的任何文件,它可以在临时构建 RPM 期间随意添加外部文件或删除重要文件,从而更改正在运行的系统。最近,RPM 系统经过了更改,允许任何用户在主目录中构建 RPM。不需要根用户特权就能构建 RPM,这可以阻止更改核心系统文件。下面介绍了这种更加现代的方法。

要构建 RPM,必须:

  • 依照 rpmbuild 规范设定一个目录结构。
  • 将源代码和附带文件放在目录中合适的位置。
  • 创建 spec 文件。
  • 编译 RPM。可以选择编译源 RPM,以与其他人共享您的源代码。

首先,构建目录。在主目录下的一个子目录中,假设为 $HOME/mywget,创建 5 个子目录:

  • BUILD。BUILD 用作实际编译软件的暂存空间。
  • RPMS。RPMS 包含 rpmbuild 所编译的二进制 RPM。
  • SOURCES。SOURCES 存储源代码。
  • SPECS。SPECS 包含您的 spec 文件,您想要构建的一个 RPM 对应一个 spec 文件。
  • SRPMS。SRPMS 包含在这个过程中构建的源 RPM。

您至少需要 SOURCES 中的源代码和 SPEC 中的一个 spec 文件。

将源代码(理想情况下应捆绑为一个 tarball 压缩文件)复制到 SOURCES 目录,如 清单 2 所示。如果有必要,重命名 tarball 压缩文件,以包含应用程序的版本号,便于与其他文件区分开。约定的命名格式为包-版本.tar.gz。对于 wget,您可以使用:


清单 2. 复制源代码
				
$ cd ~
$ mkdir mywget
$ cd mywget 
$ mkdir BUILD RPMS SOURCES SPECS SRPMS
$ cd SOURCES
$ cp wget-latest.tar.gz .
$ mv wget-latest.tar.gz wget-1.12.tar.gz
$ cd ..

接下来,创建 spec 文件。spec 文件只是一个具有特殊语法的文本文件。清单 3 给出了一个 spec 文件的例子。


清单 3. 示例 spec 文件
				
# This is a sample spec file for wget

%define _topdir	 	/home/strike/mywget
%define name			wget 
%define release		1
%define version 	1.12
%define buildroot %{_topdir}/%{name}-%{version}-root

BuildRoot:	%{buildroot}
Summary: 		GNU wget
License: 		GPL
Name: 			%{name}
Version: 		%{version}
Release: 		%{release}
Source: 		%{name}-%{version}.tar.gz
Prefix: 		/usr
Group: 			Development/Tools

%description
The GNU wget program downloads files from the Internet using the command-line.

%prep
%setup -q

%build
./configure
make

%install
make install prefix=$RPM_BUILD_ROOT/usr

%files
%defattr(-,root,root)
/usr/local/bin/wget

%doc %attr(0444,root,root) /usr/local/share/man/man1/wget.1

我们从头到尾分析一下这个 spec 文件。第 1-5 行定义在文件其余部分中使用的快捷变量。第 7-15 行使用 参数: 值 的形式设置若干个必需的参数。在第 7 行或其他地方可以看到,变量可以进行计算和组合,以生成某个设置的值。

大部分参数的名称都不言自明,但需要对 BuildRoot 稍作说明,以将其与已创建的 BUILD 目录路区分开。BuildRoot 代表最终的安装目录。换言之,如果 wget 最终安装在 /usr/local/bin/wget 和 /usr/local 中的其他子目录下,比如文档安装在 /usr/local/man 下,那么在 RPM 构建过程中 BuildRoot 代表 /usr/local。一旦设定了 BuildRoot,就可以使用 RPM_BUILD_ROOT 环境变量访问其值。应该始终在 spec 文件中设置 BuildRoot 并检查该目录的内容,确认包即将安装的内容。

下面有一些技巧:

  • 不要使用 ./configure --prefix=$RPM_BUILD_ROOT。此命令构建整个包,假定文件的最终位置为构建根目录。这可能导致需要在运行时定位其已安装文件的程序发生故障,因为当 RPM 最终安装在用户系统上时,安装的文件不再位于构建根目录下,该目录只是您的构建系统上的一个临时目录。
  • 不要在 Source 的定义中包含路径。
  • 主版本和次版本很重要。每次更改应用程序的代码或数据,以及构建好一个新 RPM 时,一定要增加主版本和次版本的值,以分别反映主要和次要的更改。您会发现每次构建一个 RPM 时就增加版本编号对于将每次修改尝试都分开很有用,即使是供您自己使用。

下一节代码首先是一个 %description。您应该在这里简单明了地描述软件。这一行将在用户运行 rpm -qi 来查询 RPM 数据库时显示。您可以说明包的用途,描述任何警告或额外的配置说明等。

接下来依次是 %prep%build 和 %install 节。每一节生成一个 shell 脚本,该脚本嵌入到 RPM 中,随后作为安装的一部分运行。%prep 准备源代码,比如解压 tarball 压缩文件。在这里,%setup -q 是一个 %prep 宏,用于自动解压 Source 中的特定 tarball 压缩文件。

您应该熟悉 %build 节中的指令。它们相当于用于手动配置和启动构建过程的步骤。%install 节也是如此。但是,尽管手动构建的目标目录是系统上的 /usr/local 目录,但 %install 指令的目标目录为 ~/mywget/BUILD。

%files 列出应该捆绑到 RPM 中的文件,还可以设置权限和其他信息。在 %files 内,您可以使用 %defattr 宏定义默认权限、所有者和 RPM 中的文件分组。在本例中,%defattr(-,root,root) 安装根用户拥有的所有文件,使用 RPM 从构建系统捆绑这些文件时找到的权限。

在 %files 中,可以在一行中包含多个文件。可以将 %doc 或 %config 添加到该行,以标记文件。%doc 告诉 RPM 该文件为一个文档文件,所以如果用户使用 --excludedocs 安装包,将不会安装该文件。%config 告诉 RPM 这是一个配置文件。在升级期间,RPM 将尝试避免使用 RPM 打包的默认配置文件覆盖用户小心修改的配置。

请注意,如果在 %files 下列出一个目录名称,RPM 将包含该目录下的每个文件。

构建 RPM

现在您的文件已经就绪,spec 文件也已经定义了,接下来就可以构建实际的 RPM 文件了。要构建它,使用适当命名的 rpmbuild 实用程序:

$ rpmbuild -v -bb --clean SPECS/wget.spec

此命令使用指定的 spec 文件构建一个二进制包(-bb 表示 “构建二进制包”),还会生成详细的输出(-v)。构建实用程序在生成包之后删除构建树(--clean)。如果还希望构建源 RPM,指定 -ba(“构建所有包”)来代替 -bb。(查看 rpmbuild 清单页面,了解完整的选项列表。)

rpmbuild 执行以下步骤:

  • 读取并解析 wget.spec 文件。
  • 运行 %prep 节,将源代码解压到临时目录。在这里,临时目录为 BUILD。
  • 运行 %build 节,编译代码。
  • 运行 %install 节,将代码安装到构建机器上的目录中。
  • 从 %files 节读取文件列表,将它们收集到一起,然后创建一个二进制 RPM(和源 RPM 文件,如果已选择)。

如果查看 $HOME/mywget 目录,应该找到一个名为 wget-1.12-root 的新目录,此目录表示目标目录。还应该找到一个名为 RPMS/i386 的新目录,而且它应该包含您的 RPM,名为 wget-1.12-1.i386.rpm。RPM 的名称表明这是针对 i386 处理器的 wgetversion 1.12。

要验证 RPM 是否包含合适的文件,可以使用 rpm 命令,如 清单 4 所示。


清单 4. 验证 RPM 内容
				
$ rpm -Vp RPMS/i386/wget-1.12-1.i386.rpm
missing     /usr/local/bin/wget
.M....G.    /usr/local/etc
missing   c /usr/local/etc/wgetrc
.M....G.    /usr/local/share
missing     /usr/local/share/info
missing   d /usr/local/share/info/wget.info
missing     /usr/local/share/locale
missing     /usr/local/share/locale/be
missing     /usr/local/share/locale/be/LC_MESSAGES
missing   d /usr/local/share/locale/be/LC_MESSAGES/wget.mo
.
.
.

命令 rpm -Vp RPMS/i386/wget-1.12-1.i386.rpm 验证包是否包含系统中的文件。尽管似乎存在很多错误,但每个错误都暗示了 RPM 文件的内容是正确的。如果您希望安装某个文件,而该文件未出现在输出中,则说明它未包含在包中。在这种情况下,请查看 spec 文件,确保该文件已在 %files 节中列出。

验证了 RPM 之后,可以将文件分发给同事。同事收到文件之后,应该可以运行 rpm 来在其自己的系统上安装 wget

$ sudo rpm -i wget-1.12-1.i386.rpm

RPM 的其他用途

这篇简短介绍文章只触及了 RPM 的用途的表面。尽管它最常用于安装软件和附带文件,但您几乎可以打包任何内容,从系统脚本到源代码到文档。在本系列第二期中您将会看到,还可以使用 RPM 修补源代码,以及重新构建和重新安装软件。RPM 分发格式可以在许多 Linux 系统上找到,是在 Red Hat 和 Fedora 等系统中安装二进制软件的首选方法。

如果您使用 RPM 构建和打包软件,那么也将能够体验到 RPM 的这些其他用途。

分享到:
评论
1 楼 okay456okay 2012-06-28  
不错的文章。其中IBM Developer上也有几篇RPM打包的文章,但是我觉得你写的更新。但是我还是建议系统的学习下RPM开发比较好,推荐Maximum RPM(http://www.jsxubar.info/maximum-rpm-introduction.html)这本书,由Redhat内部人员编写,相当不错。
因为真正要进行打包时,比如我的软件很简单,就一个执行文件和配置文件,没有任何安装操作,其实这个RPM包的功能就是将文件复制上去,就这么一个简单的操作,如果没有真正理解spec文件每个部分的作用,那在实际操作中还是不会。

相关推荐

Global site tag (gtag.js) - Google Analytics