From Fedora Project Wiki
(46 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{autolang}}
{{autolang}}


== 关于本指南==
== 关于本指南 ==


''翻译:[[User:Cicku| Christopher 'Cicku' Meng]]''
{{admon/tip|此页正在翻译,''翻译:[[User:Cicku| Christopher 'Cicku' Meng]]''|此页正进行由英语向中文的翻译,已完成 45%。由于源文档更新错乱,中间中文翻译有大量过时翻译,请他人暂时不要翻译本页!
您所看到的可能不是最终页面,请定期访问本页面以取得最新更新,如有发现问题请通知 [https://fedoraproject.org/wiki/User:Cicku Cicku]。}}


本指南详细讲述了如何针对 Fedora 系统制作 RPM (特别是如何写.spec配置文件),同时还给您许多实际的提示,帮助您减少不必要的时间损耗。
本指南讲述了如何为 Fedora 制作 RPM 包,特别是如何写 .spec 配置文件。不像其它文档,本文档会解释 Fedora 中特殊领域的打包(会有链接指向 Fedora 的特殊打包规定)。并且由于本文档通过 wiki 更新,因此会尽可能的保持最新。除了 Fedora,绝大部分内容也会适用其他基于 RPM 机制的发行版。如果您等不及了,您可以先看看[[How_to_create_a_GNU_Hello_RPM_package|如何创建一个 GNU Hello World 软件包]],这是一个创建 RPM 包的简短总结(但是没有很详细的信息)


但是,本指南并不是 Fedora 官方的打包指南(官方指南在此:[[Packaging:Guidelines|Fedora打包官方指南]]和[[Packaging:NamingGuidelines|软件包命名向导]])。尽管如此,本指南与前两者100%兼容,您不必担心内容是否不准确。
'''目前 Fedora 文档团队有一份草稿已经发布:


请您注意:本指南不会在某些方面作深入讨论,但是指南会引入相关链接以帮助您理解这些内容。而且,本指南特殊之处在于,不像有些 RPM 指南不解释详细。本文档会解释在 Fedora 中 RPM 的特殊之处(会有大量链接指向 Fedora 的特殊指南),并且尽可能的保持最新。
[http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/Packagers_Guide Packager 指南]'''


举个例子,本指南会提醒 [http://lists.autistici.org/message/20080709.212842.3f8877db.de.html RPM version 4.4.2.x版本] 的影响。由于本文档是主要针对 Fedora 编写,因此绝大部分内容也会适用其他基于 RPM 机制的发行版。如果您等不及了,您可以先看看[[How_to_create_a_GNU_Hello_RPM_package|如何创建一个GNU Hello World软件包]],这是一个创建 RPM 包的简短总结(但是没有很详细的信息)。
注意,本指南并不是 Fedora 官方的打包'''规定''',[[Packaging:Committee|打包委员会]] 制定的 Fedora 所有打包规定如下:
* [[Packaging:Guidelines|打包规定]]
* [[Packaging:LicensingGuidelines|软件许可协议规定]]
* [[Packaging:NamingGuidelines|软件包命名规定]]
* [[Packaging:DistTag|Dist 标签使用指南]]
* [[Packaging:ReviewGuidelines|软件包审核规定]]
* [[Packaging:ScriptletSnippets|SPEC 文件编写指南]]


如果您计划为 Fedora 的官方源创建一个 RPM 包,请按照 [[Join the package collection maintainers|如何参与维护软件包]] 页面的步骤一步步来。它包含了许多有关在 Fedora 中打包的指南。
'''[[Packaging:Guidelines|打包规定]] 和 [[Packaging:NamingGuidelines|软件包命名规定]] 是主要的两份规定,本指南与这两份规定100%兼容。'''


== 配置好您的系统和账户 ==
如果您计划为 Fedora 的官方源创建一个 RPM 包,请按照 [[Join the package collection maintainers|如何成为 Fedora 软件包仓库维护人员]] 页面的步骤一步步来。


在您为 Fedora 创建 RPM 包之前,您需要安装一些必须的开发组件并且设置好您即将使用的账户。请在<code>root</code>权限下执行(不要输入"#"):
== 前期准备 ==
 
在您为 Fedora 创建 RPM 包之前,您需要安装一些必须的开发组件并且设置好即将使用的账户:


   # yum install @development-tools
   # yum install @development-tools
Line 24: Line 33:
您可以新建一个临时用户以便创建 RPM 包。这样,如果有错误发生,构建程序不会破坏您的系统,比如造成文件损失或者您的私人文件/密钥被发送到互联网上。
您可以新建一个临时用户以便创建 RPM 包。这样,如果有错误发生,构建程序不会破坏您的系统,比如造成文件损失或者您的私人文件/密钥被发送到互联网上。


{{admon/caution|请切记!不要在<code>root</code>用户下执行打包操作!!!}}
{{admon/caution|切记!不要使用 <code>root</code> 用户来执行打包操作,因为这很危险,所有二进制文件都会在被打包前安装至系统中,因此您应该以普通用户身份打包以杜绝系统被破坏。}}


 
新建一个叫做<code>makerpm</code>的用户,添加至 'mock' 用户组,设置好密码并通过该用户登录:
您可以通过这条命令新建一个叫做<code>makerpm</code>的用户,同时请您为它设置一个密码:
   # /usr/sbin/useradd makerpm
   # /usr/sbin/useradd makerpm
  # usermod -a -G mock makerpm
   # passwd makerpm
   # passwd makerpm
然后您可以通过这个临时用户开始执行打包操作。
然后您可以通过这个临时用户开始执行打包操作。


一旦您登陆了要执行打包操作的用户,您可以使用一下命令在这个临时用户的主文件夹下创建一个标准的打包工作目录结构(不要输入"$"):
一旦登录了 makerpm 用户,您可以使用一下命令在这个用户的家目录下创建一个标准的打包工作目录结构:
   $ rpmdev-setuptree
   $ rpmdev-setuptree


<code>rpmdev-setuptree</code> 程序新建一个位置是 <code>~/rpmbuild</code> 的目录。在"rpmbuild"目录下是一些预设好的子目录(比如 <code>SPECS</code> 和 <code>BUILD</code>),它们将会在创建软件包的时候起作用。
<code>rpmdev-setuptree</code> 程序新建一个位置是 <code>~/rpmbuild</code> 的目录。在 "rpmbuild" 目录下是一些预设好的子目录(比如 <code>SPECS</code> 和 <code>BUILD</code>),它们将会在创建软件包的时候起作用。
<code>rpmdev-setuptree</code> 也会创建一个位置是 <code>~/.rpmmacros</code> 的文件。它是一个保存有关设置的文件。
<code>rpmdev-setuptree</code> 也会创建一个位置是 <code>~/.rpmmacros</code> 的文件。它是一个保存有关设置的文件。


Line 41: Line 50:
如果您使用 <code>wget</code> 来获取源代码,确保在 <code>~/.wgetrc</code> 文件加入一行 <code>timestamping = on</code> 。类似的,如果您使用 <code>curl</code> ,确保 <code>~/.curlrc</code> 文件包含 "-R"。
如果您使用 <code>wget</code> 来获取源代码,确保在 <code>~/.wgetrc</code> 文件加入一行 <code>timestamping = on</code> 。类似的,如果您使用 <code>curl</code> ,确保 <code>~/.curlrc</code> 文件包含 "-R"。


一旦您设置好了,通常不需要再次设置。
一旦设置完毕,通常不需要再次设置。


== 构建RPM包的基础知识 ==
== RPM 基础知识 ==


要想构建一个标准的 RPM 包,您需要新建一个 <code>.spec</code> 文本文档,里面包含即将被安装的软件的所有详细信息。然后您对这个文本文档在系统中执行 <code>rpmbuild</code> 命令,经过这一步,系统会按照步骤生成最终的 RPM 包。
若要构建一个标准的 RPM 包,您需要新建一个叫做 <code>.spec</code> 的文本文档,里面包含被打包软件的全部信息。然后您对这个文本文档在系统中执行 <code>rpmbuild</code> 命令,经过这一步,系统会按照步骤生成最终的 RPM 包。


按理说您应该把源代码包,比如从软件开发者释放出的那种以 <code>.tar.gz</code> 结尾的文件, 放入 <code>~/rpmbuild/SOURCES</code> 目录下。您应该把 <code>.spec</code> 文件放入 <code>~/rpmbuild/SPECS</code> 目录下,并且把它命名为 "''软件包名字''.spec" 。当然, ''软件包名字'' 就是最终 RPM 包的名字。为了创建所有软件包(包括预编译好的包(Binary RPM)和源代码包(SRPM)),您需要把终端切换至 <code>~/rpmbuild/SPECS</code> 目录然后执行:
按理说您应该把源代码包,比如从软件开发者释放出的那种以 <code>.tar.gz</code> 结尾的文件, 放入 <code>~/rpmbuild/SOURCES</code> 目录下。您应该把 <code>.spec</code> 文件放入 <code>~/rpmbuild/SPECS</code> 目录下,并且把它命名为 "''软件包名字''.spec" 。当然, ''软件包名字'' 就是最终 RPM 包的名字。为了创建所有软件包(包括预编译好的包(Binary RPM)和源代码包(SRPM)),您需要把终端切换至 <code>~/rpmbuild/SPECS</code> 目录然后执行:
Line 55: Line 64:
||阶段 || 读取的目录 || 写入的目录 || 具体动作
||阶段 || 读取的目录 || 写入的目录 || 具体动作
|-
|-
|<code>%prep</code>||<code>%_sourcedir</code>||<code>%_builddir</code>||这一步读取位于 <code>%_sourcedir</code> 目录(通常位于(~/rpmbuild/SOURCES)的源代码和patch 。随后会解压源代码到一个<code>%_builddir</code> 目录(通常位于~/rpmbuild/BUILD/)的子目录并应用所有 patch。
|<code>%prep</code>||<code>%_sourcedir</code>||<code>%_builddir</code>||本步读取位于 <code>%_sourcedir</code> 目录的源代码和 patch 。随后会解压源代码至 <code>%_builddir</code> 下的子目录并应用所有 patch。
|-
|-
|<code>%build</code>||<code>%_builddir</code>||<code>%_builddir</code>||这一步编译位于 <code>%_builddir</code> 目录(通常位于~/rpmbuild/BUILD/)下的所有文件。本步类似于 "./configure ; make" 命令。
|<code>%build</code>||<code>%_builddir</code>||<code>%_builddir</code>||本步编译位于 <code>%_builddir</code> 构建目录下的全部文件。本步类似于 "<code>./configure && make</code>" 命令。
|-
|-
|<code>%check</code>||<code>%_builddir</code>||<code>%_builddir</code>||这一步检查程序是否正常运行。本步类似于 "make test" 但是很多软件包都不需要这步。
|<code>%check</code>||<code>%_builddir</code>||<code>%_builddir</code>||本步检查软件是否正常运行。本步类似于 "<code>make test</code>" 命令。不过很多软件包都不需要这步。
|-
|-
|<code>%install</code>||<code>%_builddir</code>||<code>%_buildrootdir</code>||这一步读取位于编译目录 <code>%_builddir</code> 目录(通常位于~/rpmbuild/BUILD/)下的文件并把它们写入至 <code>%_buildrootdir</code> 最终安装目录(通常位于~/rpmbuild/BUILDROOT)。这些文件就是用户通过 RPM 方式安装后最终得到的文件。请注意一个奇怪的地方:  ''最终安装目录''' ''不是'''  ''构建目录'' !本部类似于 "make install"
|<code>%install</code>||<code>%_builddir</code>||<code>%_buildrootdir</code>||本步读取位于 <code>%_builddir</code> 构建目录下的文件并把它们写入至 <code>%_buildrootdir</code> 最终安装目录。这些文件就是用户安装 RPM 后最终得到的文件。请注意一个奇怪的地方:  ''最终安装目录'' '''不是'''  ''构建目录'' !本步类似于 "<code>make install</code>" 命令。
|-
|-
|bin||<code>%_buildrootdir</code>||<code>%_rpmdir</code>||这步读取位于 <code>%_buildrootdir</code> 最终安装目录(通常位于~/rpmbuild/BUILDROOT/) 下的文件,以便最终在 <code>%_rpmdir</code> 目录(通常位于~/rpmbuild/RPMS/)下创建 RPM 包。在 <code>%_rpmdir</code> 目录下,针对不同架构(例如x86,x86_64或者ppc)制作的 RPM 包会分目录放置,同时一个叫做 "noarch" 的目录放置针对所有架构均适用的 RPM 包。
|bin||<code>%_buildrootdir</code>||<code>%_rpmdir</code>||本步读取位于 <code>%_buildrootdir</code> 最终安装目录下的文件,以便最终在 <code>%_rpmdir</code> 目录下创建 RPM 包。在该目录下,针对不同架构制作的 RPM 包会分子目录放置,同时一个叫做 "noarch" 的目录放置针对所有架构均适用的 RPM 包。所有 RPM 就是用户最终安装的 RPM 包。
|-
|-
|src||<code>%_sourcedir</code>||<code>%_srcrpmdir</code>||这步创建源代码 RPM 包(简称SRPM,通常以.src.rpm作为后缀名)。然后这些SRPM会被放在 <code>%_srcrpmdir</code> 目录(通常位于~/rpmbuild/SRPMS)下。SRPM 包通常被用于审核和升级软件包。
|src||<code>%_sourcedir</code>||<code>%_srcrpmdir</code>||本步创建源代码 RPM 包(简称 SRPM,通常以<code>.src.rpm</code>作为后缀名)。然后这些 SRPM 会被放在 <code>%_srcrpmdir</code> 目录下。SRPM 包通常被用于审核和升级软件包。
|}
|}


<!-- Note: The words "in" and "underneath" in the table above have different meanings.  Given file /a/b/c, c is "underneath" but not "in" a. -->
<!-- Note: The words "in" and "underneath" in the table above have different meanings.  Given file /a/b/c, c is "underneath" but not "in" a. -->


As you can tell, certain directories have certain purposes in rpmbuild.  These are:
<code>rpmbuild</code> 中对上面表格中的每个宏代码有相应的目录对应:
{|border="1" cellspacing="0"  
{|border="1" cellspacing="0"  
||宏指令 || 名字 || 通常用途 || 目的
||宏代码 || 名称 || 默认位置 || 用途
|-
|-
|<code>%_specdir</code>||Specification directory||<code>~/rpmbuild/SPECS</code>|| RPM 包配置(.spec) 文件存放的目录
|<code>%_specdir</code>||Spec 文件目录||<code>~/rpmbuild/SPECS</code>|| RPM 包配置(.spec) 文件存放的目录
|-
|-
|<code>%_sourcedir</code>||源代码目录||<code>~/rpmbuild/SOURCES</code>||存放源代码包(比如 .tar包) 和所有 patch 的目录
|<code>%_sourcedir</code>||源代码目录||<code>~/rpmbuild/SOURCES</code>||存放源代码包(比如 .tar包) 和所有 patch 的目录
|-
|-
|<code>%_builddir</code>||构建目录||<code>~/rpmbuild/BUILD</code>||Source files are unpacked and compiled in a subdirectory underneath this.
|<code>%_builddir</code>||构建目录||<code>~/rpmbuild/BUILD</code>||源代码被解压,并在该目录下的子目录下被编译
|-
|-
|<code>%_buildrootdir</code>||最终安装目录||<code>~/rpmbuild/BUILDROOT</code>||Files are installed under here during the %install stage.
|<code>%_buildrootdir</code>||最终安装目录||<code>~/rpmbuild/BUILDROOT</code>||%install 阶段最终安装的文件
|-
|-
|<code>%_rpmdir</code>||标准 RPM 包目录||<code>~/rpmbuild/RPMS</code>||标准 RPM 包在这里生成并存放。
|<code>%_rpmdir</code>||标准 RPM 包目录||<code>~/rpmbuild/RPMS</code>||二进制 RPM 包在这里生成并存放。
|-
|-
|<code>%_srcrpmdir</code>||源代码 RPM 包目录||<code>~/rpmbuild/SRPMS</code>||源代码 RPM 包(SRPM)在这里生成并存放。
|<code>%_srcrpmdir</code>||源代码 RPM 包目录||<code>~/rpmbuild/SRPMS</code>||源代码 RPM 包(SRPM)在这里生成并存放。
|}
|}


Should a stage fail, you'll need to look at the output to see ''why'' it failed, and change the .spec file (or other input) as needed.
如果某一阶段失败,请查看输出以了解失败的 ''原因'',然后请按照问题修改 <code>.spec</code> 文件。


== 做好准备打包一个特殊程序 ==
== 做好准备打包一个特殊程序 ==
Line 93: Line 102:
如果这里有特殊的程序,它们需要被安装或者运行以便让您打包的普通程序正常工作,那么请先安装它们,然后记录下诸如软件包等相关信息。
如果这里有特殊的程序,它们需要被安装或者运行以便让您打包的普通程序正常工作,那么请先安装它们,然后记录下诸如软件包等相关信息。


如果想为 Fedora 源打包一个程序,您“务必”使用源代码来打包(一定包含patch补丁以及打包简介)。我们不建议您使用预编译好的代码来进行打包。Install the file with the original source (usually a .tar.gz file) in the
如果想为 Fedora 源打包一个程序,您必须使用源代码来打包,且包含 patch 以及打包简介。不'''可以'''使用预编译好的代码来进行打包。将源代码(通常是一个 .tar.gz 文件) 放入"<code>~/rpmbuild/SOURCES</code>" 目录(注意用户)
"~/rpmbuild/SOURCES" directory (of the rpm building user account).


Read through the manual installation instructions for your program;
仔细阅读该软件的安装说明。我们建议您先手工安装一次以了解具体情况。除了少许例外,所有程序的二进制文件和程序库都必须来源于源代码且基于其构建。
you're going to be automating this by editing a ".spec" file, so you have
to understand what you're supposed to do first.
It's probably best if you try a "dry run", going through its build and installation
procedure without trying to do it via RPM first
(that's especially true if you're not familiar with RPM).
With a few exceptions, all program binaries and program libraries included in Fedora packages must be built from the source code that is included in the source package.


=== 分离程序 ===
=== 分离程序 ===


应用程序的源代码会经常随着程序发布而被释放出来,但是其中也会掺杂着许多其他组件。
程序源代码通常会随着发布而被发布,但是其中也会掺杂着许多其它外部组件。[[Packaging:No_Bundled_Libraries|请不要将外部组件跟随主程序一起打包]],相反您需要对每个组件单独打包。


请参阅:[[Packaging:No_Bundled_Libraries|把绑入的外部组件分离成单独程序]] 以了解更多信息。请您把绑入的组件从主程序分离,制作成单独的包再发布。
=== 许可协议 ===


=== 软件许可证===
您只许打包'''允许您打包'''的软件。请查看 [[Packaging:Guidelines#Legal]][[Licensing:Main]] 和 [[Packaging:LicensingGuidelines]]。
 
您只可以打包'''允许您进行打包操作'''的软件。
 
就像在 [[Packaging/Guidelines#Legal|packaging guidelines' legal section]] 声明的那样,如果您打算把您的软件包放入 Fedora 源,请一定遵守[[Licensing:Main]] 和 [[Packaging:LicensingGuidelines]] 。
通常情况下,您只可以打包使用开源许可证(比如GNU GPL、GNU LGPL、BSD-new、MIT/X或者Apache 2.0 许可证)发放的开源软件(OSS)。
通常情况下,您只可以打包使用开源许可证(比如GNU GPL、GNU LGPL、BSD-new、MIT/X或者Apache 2.0 许可证)发放的开源软件(OSS)。
请仔细检查许可证是否名副其实,同时软件整体是否均基于开源协议发放。(比如抽查源代码开头的注释、README 文件等等)。
请仔细检查许可证是否名副其实,同时软件整体是否均基于开源协议发放。(比如抽查源代码开头的注释、README 文件等等)。
如果软件有附加组件被绑入,请确保这些组件也是开源软件。这步十分重要。
如果软件有外部组件被捆绑,请确保这些组件也是开源软件。这步十分重要。


=== 使用已有的 .spec 文件 ===
=== 使用已有的信息 ===


尽可能利用一切已有的信息!很明显,请您不要打包一些已经存在于源里面的程序!为了防止您犯这种错误,请查阅 [https://admin.fedoraproject.org/pkgdb/ Fedora 软件仓库信息数据库] 。同时建议您查阅 [[PackageMaintainers/InProgressReviewRequests | In Progress Review Requests]] (那些正在被审核的软件包)和 [[PackageMaintainers/RetiredPackages | Retired Packages]] (已退休的软件包)列表。
尽可能利用一切已有的信息!很明显,请您不要打包一些已经存在于源里面的程序!为了防止您犯这种错误,请查阅 [https://admin.fedoraproject.org/pkgdb/ Fedora 软件包数据库]。同时建议查阅 [[PackageMaintainers/InProgressReviewRequests |正在被审核的软件包]]和 [[PackageMaintainers/RetiredPackages |已停止使用的软件包]]列表。
如果以上都没有即将被您打包的程序的信息,请使用 Google 以 "您想打包的程序名 Fedora rpm" 或者类似的关键字进行搜索,您可以直接访问 [http://pkgs.fedoraproject.org/gitweb/ Fedora 软件仓库 Git 源] 来查看已存在于 Fedora 源中的 .spec 文件。
如果以上都没有即将被您打包的程序的信息,请使用 Google 以 "您想打包的程序名 Fedora rpm" 或者类似的关键字进行搜索,您可以直接访问 [http://pkgs.fedoraproject.org/cgit/ Fedora 软件仓库 Git 源] 来查看已存在于 Fedora 源中的 .spec 文件(以及 patch)。您还可以通过 <code>yum-utils</code> 工具包的一个工具,<code>yumdownloader</code>,来获取源代码 RPM 包(SRPM):
您还可以通过 <code>yum-utils</code> 工具包的一个工具,<code>yumdownloader</code>,来获得源代码 RPM 包(SRPM):
  $ yum -y install yum-utils
  $ yum -y install yum-utils
  $ yumdownloader --source 您想要获得的源代码包的名字
  $ yumdownloader --source 您想要获得的源代码包的名字


或者您可以通过浏览 [http://mirrors.fedoraproject.org/publiclist Fedora 镜像列表] 的 HTTP 或者 FTP 页面以获取 SRPM 包。select releases/{{FedoraVersion}}/Everything/source/SRPMS
或者您可以通过浏览 [http://mirrors.fedoraproject.org/publiclist Fedora 镜像列表] 的 HTTP 或者 FTP 页面以获取 SRPM 包。在 releases/{{FedoraVersion}}/Everything/source/SRPMS 目录内
(请把"{{FedoraVersion}}"换成您想要的 Fedora 版本),然后下载即可。通常源代码包以 .src.rpm 为后缀名。
(请把"{{FedoraVersion}}"换成您想要的 Fedora 版本),然后下载即可。通常源代码包以 .src.rpm 为后缀名。


一旦您有了源代码包,请按照下面的步骤安装到<code>~/rpmbuild</code>目录下:
一旦有了源代码包,请按照下面的步骤安装到 <code>~/rpmbuild</code> 目录下:
  $ rpm -ivh 您下载的源代码包名字.src.rpm
  $ rpm -ivh 源代码包名字.src.rpm


您也可以使用 <code>rpm2cpio</code> 把源代码包解压到任意目录:
您也可以使用 <code>rpm2cpio</code> 把源代码包解压到任意目录:
  $ mkdir 您下载的源代码包名字_src_rpm
  $ mkdir 源代码包名字_src_rpm
  $ cd 您下载的源代码包名字E_src_rpm
  $ cd 源代码包名字E_src_rpm
  $ rpm2cpio ../您下载的源代码包名字.src.rpm | cpio -i
  $ rpm2cpio ../源代码包名字.src.rpm | cpio -i


使用这些已经存在的信息有助于您更快打包。[http://rpmfind.net/ RPM Find] may help you find rpm's for non-Fedora systems.
使用这些已经存在的信息有助于您更快打包。[http://rpmfind.net/ RPM Find] 和 [http://pkgs.org PKGS.org] 将帮助您找到针对非 Fedora 的 RPM 包。您可以尝试安装它们。如果失败,请查看相应的源代码包(不是 <code>.deb</code>) 结尾的 [http://packages.ubuntu.com/ Ubuntu] [http://www.debian.org/distrib/packages Debian]软件包(源代码包通常是标准的 tar 文件比并且内部包含一个叫做 "<code>debian/</code>" 的子目录)。如果您在 [http://www.freebsd.org/ports/installing.html FreeBSD ports 仓库] 找到想要的文件, [ftp://ftp.freebsd.org/pub/FreeBSD/ports/ports/ports.tar.gz 请下载 ports 的源代码包] 并查看是否包含相关信息。有些时候这些操作没什么实际帮助,因为不同的系统有不同的规定。
(You can install source RPMs for other systems the same way as for Fedora).
Failing that, you might look at the source package files (not the <code>.deb</code> binary package files)
for [http://packages.ubuntu.com/ Ubuntu] or
[http://www.debian.org/distrib/packages Debian]
(source package files are standard tarballs with a <code>debian/</code> subdirectory, possibly
associated with patch files).
If the [http://www.freebsd.org/ports/installing.html FreeBSD ports collection] has it,
you could
[ftp://ftp.freebsd.org/pub/FreeBSD/ports/ports/ports.tar.gz download the FreeBSD ports tarball]
and see if their packaging information helps as a starting point.
'''However''', this is sometimes not helpful at all.
Different distributions have different rules, and what they do may be quite
inappropriate for Fedora.


== 创建一个SPEC文件 ==
== 新建一个 .spec 文件 ==


现在你需要在~/rpmbuild/SPECS目录中创建一个SPEC文件。SPEC文件通常用程序名来命名(也就是 "程序名.spec")。一般情况下程序名就是源码压缩包的名称或者该程序的开发者建议的名称,但是一定要确保SPEC文件的名称符合 [[Packaging/NamingGuidelines|Fedora社区软件包命名规范]]
现在您需要新建一个 ".spec" 文件,并让它位于 <code>~/rpmbuild/SPECS</code> 目录下。您应该把它命名为 "<code>程序名.spec</code>"。程序名根据原始软件包命名或通用命名来填写即可。但是,[[Packaging/NamingGuidelines|软件包命名规定]] 是您必须要遵守的。


=== 新建一个SPEC 文件 ===
=== 模板和实例 ===
 
==== 模板 ====
如果你创建一个新的SPEC文件,vim或者emacs(这是两个编辑器)会自动为你创建一个SPEC文件模板:
如果您第一次新建 .spec 文件,vim 或 emacs 会自动生成好一个模板:
   $ cd ~/rpmbuild/SPECS
   $ cd ~/rpmbuild/SPECS
   $ vi 您取的软件包名字.spec
   $ vim 程序名.spec


下面是一个例子,这个例子显示了SPEC文件包含的基本信息(注意:这个例子可能没有严格遵守Fedora社区RPM包编写规范):
示例(仅为参考):
  Name:
  Name:
  Version:
  Version:
Line 200: Line 184:




在SPEC文件中,你可以用$RPM_BUILD_ROOT代替%{buildroot},这两种方式都是正确的。但是规范起见,一个SPEC文件中最好只
您可以使用 <code>$RPM_BUILD_ROOT</code> 替代 <code>%{buildroot}</code>。两者都可以。
使用其中的一种方式。.


你可以使用 <code>rpmdev-newspec</code>命令创建一个SPEC文件。  <code>rpmdev-newspec 软件包的名称</code> 可以为新的软件包创建一个SPEC文件,根据软件包类型的不同,创建的SPEC文件中的内容会有差别,它会根据你填写的软件包名称选择一个最适合的SPEC文件模板。或者你也可以指定模板类型。在 <code>/etc/rpmdevtools/spectemplate-*.spec</code> 可以找到所有可用的模板类型。通过<code>rpmdev-newspec --help</code> 可以查看这条命令的详细信息。例如,为python模块创建一个新的SPEC文件:
您也可以使用 <code>rpmdev-newspec</code> 命令来创建新的 SPEC 文件。<code>rpmdev-newspec 软件包名</code> 可以创建一个初始的 SPEC 文件,该工具会从软件包名来判断何种模板适合您,您也可以自行指定。请看 <code>/etc/rpmdevtools/spectemplate-*.spec</code> 来找可用的模板,也可以通过 <code>rpmdev-newspec --help</code> 命令来了解。比如您创建一个 python 模块:


  cd ~/rpmbuild/SPECS
  cd ~/rpmbuild/SPECS
Line 209: Line 192:
  vi python-antigravity.spec
  vi python-antigravity.spec


=== SPEC文件例子 ===
==== 实例 ====
===== eject =====
这是 Fedora 16 的 <code>eject</code> 的 spec 文件:
 
<pre>
Summary:            A program that ejects removable media using software control
Name:              eject
Version:            2.1.5
Release:            21%{?dist}
License:            GPLv2+
Group:              System Environment/Base
Source:            %{name}-%{version}.tar.gz
Patch1:            eject-2.1.1-verbose.patch
Patch2:            eject-timeout.patch
Patch3:            eject-2.1.5-opendevice.patch
Patch4:            eject-2.1.5-spaces.patch
Patch5:            eject-2.1.5-lock.patch
Patch6:            eject-2.1.5-umount.patch
URL:                http://www.pobox.com/~tranter
ExcludeArch:        s390 s390x
BuildRequires:      gettext
BuildRequires:      libtool
 
%description
The eject program allows the user to eject removable media (typically
CD-ROMs, floppy disks or Iomega Jaz or Zip disks) using software
control. Eject can also control some multi-disk CD changers and even
some devices' auto-eject features.
 
Install eject if you'd like to eject removable media using software
control.
 
%prep
%setup -q -n %{name}
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
 
%build
%configure
make %{?_smp_mflags}


下面是Fedora16系统上软件包eject的SPEC文件的例子:
%install
make DESTDIR=%{buildroot} install


Summary: A program that ejects removable media using software control
install -m 755 -d %{buildroot}/%{_sbindir}
Name: eject
ln -s ../bin/eject %{buildroot}/%{_sbindir}
Version: 2.1.5
 
Release: 11%{dist}
%find_lang %{name}
License: GPL
 
Group: System Environment/Base
%files -f %{name}.lang
Source: http://metalab.unc.edu/pub/Linux/utils/disk-management/%{name}-%{version}.tar.gz
%doc README TODO COPYING ChangeLog
Source1: eject.pam
%{_bindir}/*
Patch1: eject-2.1.1-verbose.patch
%{_sbindir}/*
Patch2: eject-timeout.patch
%{_mandir}/man1/*
Patch3: eject-2.1.5-opendevice.patch
 
Patch4: eject-2.1.5-spaces.patch
%changelog
Patch5: eject-2.1.5-lock.patch
* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.5-21
Patch6: eject-2.1.5-umount.patch
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
 
URL: http://www.pobox.com/~tranter
* Fri Jul 02 2010 Kamil Dudka <kdudka@redhat.com> 2.1.5-20
ExcludeArch: s390 s390x
- handle multi-partition devices with spaces in mount points properly (#608502)
BuildRequires: gettext
</pre>
BuildRequires: automake
 
BuildRequires: autoconf
===== =====
BuildRequires: libtool
{{Anchor|Spec_file_pieces_explained}}
 
%description
== SPEC 文件综述 ==
The eject program allows the user to eject removable media (typically
CD-ROMs, floppy disks or Iomega Jaz or Zip disks) using software
control. Eject can also control some multi-disk CD changers and even
some devices' auto-eject features.
Install eject if you'd like to eject removable media using software
control.
%prep
%setup -q -n %{name}
%patch1 -p1 -b .versbose
%patch2 -p1 -b .timeout
%patch3 -p0 -b .opendevice
%patch4 -p0 -b .spaces
%patch5 -p0 -b .lock
%patch6 -p1 -b .umount
%build
%configure
make
%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install
# pam stuff
install -m 755 -d %{buildroot}/%{_sysconfdir}/pam.d
install -m 644 %{SOURCE1} %{buildroot}/%{_sysconfdir}/pam.d/%{name}
install -m 755 -d %{buildroot}/%{_sysconfdir}/security/console.apps/
echo "FALLBACK=true" > %{buildroot}/%{_sysconfdir}/security/console.apps/%{name}
install -m 755 -d %{buildroot}/%{_sbindir}
pushd %{buildroot}/%{_bindir}
mv eject ../sbin
ln -s consolehelper eject
popd
%find_lang %{name}
%clean
rm -rf %{buildroot}
%files -f %{name}.lang
%defattr(-,root,root)
%doc README TODO COPYING ChangeLog
%attr(644,root,root) %{_sysconfdir}/security/console.apps/*
%attr(644,root,root) %{_sysconfdir}/pam.d/*
%{_bindir}/*
%{_sbindir}/*
%{_mandir}/man1/*
%changelog
* Wed Apr 02 2008 Zdenek Prikryl &lt;zprikryl at, redhat.com&gt; 2.1.5-11
- Added check if device is hotpluggable
  - Resolves #438610


=== SPEC文件分析 ===
其他有用的介绍:
* [http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM 手册] 讲述了如何写 spec 文件。
*[http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM指南]介绍了SPEC文件的编写过程.
* IBM 的 "Packaging software with RPM" 系列 [http://www.ibm.com/developerworks/library/l-rpm1/ Part 1][http://www.ibm.com/developerworks/library/l-rpm2/ Part 2],和 [http://www.ibm.com/developerworks/library/l-rpm3/ Part 3]
*IBM系列文章 "用RPM形式发布软件包" [http://www.ibm.com/developerworks/library/l-rpm1/ 第一讲], [http://www.ibm.com/developerworks/library/l-rpm2/ 第二讲], 和 [http://www.ibm.com/developerworks/library/l-rpm3/ 第三讲]  
* [http://rpm.org/max-rpm-snapshot/ Maximum RPM] 有最多的信息,不过已经过时。
*[http://rpm.org/max-rpm-snapshot/ RPM全面讲解] 有关于RPM各方面信息的详细介绍,但是这本书讲解的内容有些过时了.


你需要遵守Fedora社区RPM包编写的规范,包括
您也将需要按照这些规定来做:[[Packaging/NamingGuidelines|软件包命名规定]][[Packaging/Guidelines|打包规定]] [[Packaging/ReviewGuidelines|软件包审核规定]]
[[Packaging/NamingGuidelines| 软件包命名规范]],
[[Packaging/Guidelines| 软件包规范]], and
[[Packaging/ReviewGuidelines|软件包检查要点]].


你可以在SPEC文件中插入注释,注释需要以 "<code>#</code>"开头,但是要避免rpm宏 (<code>%</code>开头的是宏)扩展到多行(宏定义会先被解析)。如果注释中包含宏定义,需要写两个百分号 (<code>%%</code>)。同样,避免在SPEC文件的脚本语句中插入注释语句。
Insert comments with a leading "<code>#</code>" character, but avoid macros (beginning with <code>%</code>) that are potentially multiline (as they are expanded first). If commenting out a line, double the percent signs (<code>%%</code>). Also avoid inline comments on the same line as a script command.


下面列举了SPEC文件中主要的标签。注意:宏 <code>%{name}</code>, <code>%{version}</code> 和 <code>%{release}</code> 分别用来表示软件包的名称、版本号和释放号。当你改变了这些标签的值时,这些宏的值会自动更新。
主要的标签都在下方介绍。注意 <code>%{name}</code><code>%{version}</code> 和 <code>%{release}</code> 代表 Name, Version 和 Release 这三个标签,在 SPEC 中修改它们,构建会自动抓去新的内容。
* '''Name''': 软件包(基本)的名称, 软件包的名称需要与SPEC文件的名称保持一致,并且需要遵守 [[Packaging/NamingGuidelines|Package Fedora社区RPM包命名规范] 。一般情况下,软件包的名称应该保持小写字母.
* '''Name''': 软件包名,应与 SPEC 文件名一致。命名必须符合 [[Packaging/NamingGuidelines|软件包命名规定]]
* '''Version''': 软件包的版本号. 参考Fedora社区RPM包规范中关于 [[Packaging/NamingGuidelines#Version_Tag|软件包版本号部分]]的介绍。如果软件包的版本号中包含非数字字符,你需要将这些非数字字符包含到软件包的释放号中. 如果发布者采用发布日期表示软件的版本,可以考虑采用<code>yy.mm[dd]</code>这样的格式表示版本号 (例如 如果版本号是<code>2008-05-01</code> 可以将软件包的版本号修改为 <code>8.05</code>)。
* '''Version''': 上游版本号。请查看 [[Packaging/NamingGuidelines#Version_Tag|版本标签规定]]。如果包含非数字字符,您可能需要将它们包含在 Release 标签中。如果上有采用日期区分版本号,请考虑这个格式:<code>yy.mm[dd]</code> (例如 <code>2008-05-01</code> 可变为 <code>8.05</code>)。
* '''Release''': 一般情况下,软件包的初始释放号设置为<code>1%{?dist}</code>。如果你在发布者发布的软件基础上做了细微的改动,你需要将释放号增加1,每改动一次增加一次。当发布者发布了新版本的软件时,你需要修改软件包的版本号同时将释放号复位成<code>1</code>。参见 Fedora社区RPM包规范中关于[[Packaging/NamingGuidelines#Release_Tag|软件包释放号部分]]的介绍。可选的标签 [[Packaging/DistTag|Dist tag]] 通常情况下是有用的。
* '''Release''': 初始值为 <code>1%{?dist}</code>。每次您制作新的包时,请递增该数字。当上游发布新版本时,请修改 Version 标签并重置 Release 的数字为 <code>1</code>。具体请看打包规定中的 [[Packaging/NamingGuidelines#Release_Tag|Release 标签部分]][[Packaging/DistTag|Dist tag]] 可能也会帮助您。
* '''Summary''': 关于软件包的简短介绍,长度在一行语句范围内。请使用美式英语,语句末尾'''''' 要有标点符号。
* '''Summary''': 一行简短的软件包介绍。请使用美式英语。'''请勿在结尾加上句号!'''
* '''Group''': 软件包属于的分组,必须是Fedora社区定义好的分组,像 "Applications/Engineering"; 通过 "<code>less /usr/share/doc/rpm-*/GROUPS</code>" 命令可以查看完整的分组列表。如果一个软件包包含子包,子包中保存了软件包的说明文档 (比如 <code>kernel-doc</code>),请将这类子包归到"Documentation"分组。
* '''Group''': 需要在一个一存在的组中,就像 "Applications/Engineering";执行 "<code>less /usr/share/doc/rpm-*/GROUPS</code>" 来查看完整的组列表。使用组 "Documentation" 为所有包含文档的子软件包(例如 <code>kernel-doc</code>)。'''''注意这个标签从 Fedora 17 后已被废除。[[http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/Packagers_Guide/chap-Packagers_Guide-Spec_File_Reference-Preamble.html|Spec 文件参考手册]] 有介绍'''''
* '''License''': 协议标签,软件包必须采用开源协议。 ''''要使用旧式的Copyright标签。请使用协议的标准缩写形式 ("<code>GPLv2+</code>")并且写明软件采用的确切协议 (例如,如果软件遵循GPL协议第二版以及更高的版本,请写明 "<code>GPLv2+</code>" 而不是单单写成 "<code>GPL</code>" 或者 "<code>GPLv2</code>").  参见  [[Licensing]] 以及[[Packaging/LicensingGuidelines|协议规范]]部分的介绍。如果一个软件包遵守多个协议,你可以用 "<code>and</code>" 或者 "<code>or</code>" 将各个协议连接起来(例如 "<code>GPLv2 and BSD</code>")
* '''License''': 必须是开源软件许可证。请''不要''使用 Copyright 标签来注明许可证。请使用一个标准(例如 "<code>GPLv2+</code>")且清楚的的描述(例如,使用 "<code>GPLv2+</code>" 来注明 GPL version 2 及更高而不是 "<code>GPL</code>" "<code>GPLv2</code>" 这种不准确的描述)。请见 [[Licensing]] [[Packaging/LicensingGuidelines|Licensing Guidelines]]。如果一个软件包包含多个协议,您可以使用 "<code>and</code>" "<code>or</code>" (例如 "<code>GPLv2 and BSD</code>")来描述。
* '''URL''': 记录这个软件更多信息的完整URL地址 (例如  这个软件的官方网站)'''''注意: URL记录的不是软件源代码的下载地址,记录软件源代码下载地址的标签是下面将要讲解的Source0标签'''''
* '''URL''': 有关该软件包的详细信息(例如项目主页)'''''注意:这不是源代码的来源地址,后者是下文将要讲述的 Source0。'''''
* '''Source0''': 软件源代码压缩包的完整URL地址,从这个URL地址可以下载压缩包。这里"<code>Source</code>""<code>Source0</code>"的代名词. 如果你给出了一个完整的URL(通常情况下应该如此),编包过程中会在<code>SOURCES</code>目录下查找URL中最末端给出的压缩包的名称。如果可能,尽量用<code>%{name}</code><code>%{version}</code>代替软件包的名称和版本号。这样,当软件包名称或者版本号发生编号时,Source0中的值会随之改变。下载源代码时请 [[Packaging:Guidelines#Timestamps|保留文件的时间戳]]。如果软件包中包含多个源代码文件,请用<code>Source1</code>, <code>Source2</code> 命名,以此类推。如果除了从软件的网站上下载的源代码外,你还需要自己编写新的源代码文件,请将自己编写的文件放到从网站中下载的原始文件的 ''''方。所有的源代码文件都需要包含在编译出的SRPM包中,除非有特殊情况。 参考 [[Packaging/SourceURL|源码URL]],这里对一些特殊情况进行了说明 (如 源代码采用了版本控制)
* '''Source0''': 软件源代码原始下载地址。"<code>Source</code>" is synonymous with "<code>Source0</code>". If you give a full URL (and you should), its basename will be used when looking in the <code>SOURCES</code> directory. If possible, embed <code>%{name}</code> and <code>%{version}</code>, so that changes to either will go to the right place. [[Packaging:Guidelines#Timestamps|Preserve timestamps]] when downloading source files. If there is more than one source, name them <code>Source1</code>, <code>Source2</code> and so on. If you're adding whole new files in addition to the pristine sources, list them as sources ''after'' the pristine sources. A copy of each of these sources will be included in any SRPM you create, unless you specifically direct otherwise.  See [[Packaging/SourceURL|Source URL]] for more information on special cases (e.g. revision control).
* '''Patch0''': 表示应用到源代码中的第一个补丁文件。如果你需要对源码包解压缩后得到的源代码文件进行序该,你应该编辑这些源代码文件,将修改的内容生成一个补丁文件,将补丁文件放到目录<code>~/rpmbuild/SOURCES</code>中。每个补丁文件应该只包含对源代码的一处修改信息。因此,如果你对源代码进行了多处修改,很可能你需要生成多个补丁文件。
* '''Patch0''': The name of the first patch to apply to the source code.  If you need to patch the files after they've been uncompressed, you should edit the files and save their differences as a "patch" file in your <code>~/rpmbuild/SOURCES</code> directory. Patches should make only one logical change each, so it's quite possible to have multiple patch files.
* '''BuildArch''': 如果源代码的执行过程与系统架构无关(例如shell脚本,或者单纯的数据文件),你需要在SPEC文件中增加"<code>BuildArch: noarch</code>"。这样,编译出的RPM包的架构为"<code>noarch</code>",这样的RPM包可以安装在任何架构的系统中。
* '''BuildArch''': If you're packaging files that are architecture-independent (e.g. shell scripts, data files), then add "<code>BuildArch: noarch</code>". The architecture for the binary RPM will then be "<code>noarch</code>".
* '''BuildRoot''': This is where files will be "installed" during the %install process (after the %build process). This is now redundant in Fedora and is only needed for EPEL5. By default, the build root is placed in "<code>%{_topdir}/BUILDROOT/</code>".
* '''BuildRoot''': This is where files will be "installed" during the %install process (after the %build process). This is now redundant in Fedora and is only needed for EPEL5. By default, the build root is placed in "<code>%{_topdir}/BUILDROOT/</code>".
* '''BuildRequires''': A comma-separated list of packages required for building (compiling) the program. This field can be (and is commonly) repeated on multiple lines. These dependencies are ''not'' automatically determined, so you need to include ''everything'' needed to build the program. [[Packaging/Guidelines#BuildRequires|Some common packages can be omitted]], such as <code>gcc</code>. You can specify a minimum version if necessary (e.g. "<code>ocaml >= 3.08</code>"). If you need the file <code>/EGGS</code>, determine the package that owns it by running "<code>rpm -qf /EGGS</code>". If you need the program <code>EGGS</code>, determine the package that owns it by running "<code>rpm -qf `which EGGS`</code>". Keep dependencies to a minimum (e.g. use <code>sed</code> instead of <code>perl</code> if you don't really need perl's abilities), but beware that some applications permanently disable functions if the associated dependency is not present; in those cases you may need to include the additional packages. The "<code>auto-br-rpmbuild</code>" command may be helpful.
* '''BuildRequires''': A comma-separated list of packages required for building (compiling) the program. This field can be (and is commonly) repeated on multiple lines. These dependencies are ''not'' automatically determined, so you need to include ''everything'' needed to build the program. [[Packaging/Guidelines#BuildRequires|Some common packages can be omitted]], such as <code>gcc</code>. You can specify a minimum version if necessary (e.g. "<code>ocaml >= 3.08</code>"). If you need the file <code>/EGGS</code>, determine the package that owns it by running "<code>rpm -qf /EGGS</code>". If you need the program <code>EGGS</code>, determine the package that owns it by running "<code>rpm -qf `which EGGS`</code>". Keep dependencies to a minimum (e.g. use <code>sed</code> instead of <code>perl</code> if you don't really need perl's abilities), but beware that some applications permanently disable functions if the associated dependency is not present; in those cases you may need to include the additional packages. The {{package|auto-buildrequires}} package may be helpful.
* '''Requires''': A comma-separate list of packages that are required when the program is installed. Note that the BuildRequires tag lists what is required to build the binary RPM, while the Requires tag lists what is required when installing/running the program; a package may be in one list or in both. In many cases, <code>rpmbuild</code> automatically detects dependencies so the Requires tag is not always necessary. However, you may wish to highlight some specific packages as being required, or they may not be automatically detected.
* '''Requires''': A comma-separate list of packages that are required when the program is installed. Note that the BuildRequires tag lists what is required to build the binary RPM, while the Requires tag lists what is required when installing/running the program; a package may be in one list or in both. In many cases, <code>rpmbuild</code> automatically detects dependencies so the Requires tag is not always necessary. However, you may wish to highlight some specific packages as being required, or they may not be automatically detected.
* '''%description''': A longer, multi-line description of the program.  Use American English. All lines must be 80 characters or less. Blank lines indicate a new paragraph. Some graphical user interface installation programs will reformat paragraphs; lines that start with whitespace will be treated as preformatted text and displayed as is, normally with a fixed-width font. See [http://docs.fedoraproject.org/drafts/rpm-guide-en/ch09s03.html RPM Guide].
* '''%description''':一个较长的/多行的软件介绍部分。请使用美式英语。All lines must be 80 characters or less. Blank lines indicate a new paragraph. Some graphical user interface installation programs will reformat paragraphs; lines that start with whitespace will be treated as preformatted text and displayed as is, normally with a fixed-width font. See [http://docs.fedoraproject.org/drafts/rpm-guide-en/ch09s03.html RPM Guide].
* '''%prep''': Script commands to "prepare" the program (e.g. to uncompress it) so that it will be ready for building.  Typically this is just "<code>%setup -q</code>"; a common variation is "<code>%setup -q -n NAME</code>" if the source file unpacks into <code>NAME</code>. See the %prep section below for more.
* '''%prep''': Script commands to "prepare" the program (e.g. to uncompress it) so that it will be ready for building.  Typically this is just "<code>%setup -q</code>"; a common variation is "<code>%setup -q -n NAME</code>" if the source file unpacks into <code>NAME</code>. See the %prep section below for more.
* '''%build''': Script commands to "build" the program (e.g. to compile it) and get it ready for installing. The program should come with instructions on how to do this.  See the %build section below for more.
* '''%build''': "构建" 程序并使其接下来能够被安装的命令(例如,编译)。具体请见下文的 %build 部分。
* '''%check''': Script commands to "test" the program. This is run between the %build and %install procedures, so place it there if you have this section. Often it simply contains "<code>make test</code>" or "<code>make check</code>". This is separated from %build so that people can skip the self-test if they desire.
* '''%check''': "测试" 程序的命令。 This is run between the %build and %install procedures, so place it there if you have this section. Often it simply contains "<code>make test</code>" or "<code>make check</code>". This is separated from %build so that people can skip the self-test if they desire.
* '''%install''': Script commands to "install" the program.  The commands should copy the files from the <code>BUILD</code> directory <code>%{_builddir}</code> into the buildroot directory, <code>%{buildroot}</code>. See the %install section below for more.
* '''%install''': "安装" 程序的命令。The commands should copy the files from the <code>BUILD</code> directory <code>%{_builddir}</code> into the buildroot directory, <code>%{buildroot}</code>. 具体请见下文的 %install 部分。
* '''%clean''': Instructions to clean out the build root. Note that this section is now redundant in Fedora and is only necessary for EPEL. Typically this contains only:
* '''%clean''': "清理" 安装目录的命令。注意这一步目前在 Fedora 中是多余的,仅针对 EPEL。基本上只包含一句:
  rm -rf %{buildroot}
  rm -rf %{buildroot}
* '''%files''': The list of files that will be installed. See the %files section below for more.
* '''%files''': 将要被安装的文件的列表。具体请见下文的 %files 部分。
* '''%changelog''': Changes in the package.  Use the format example above.
* '''%changelog''': 请按照上面 eject 的例子,使用这个标签列出 RPM 的变更日志。'''请注意不是软件本身的变更日志。'''
* '''ExcludeArch''': If the package does not successfully compile, build or work on a particular architecture, list those architectures under this tag.
* '''ExcludeArch''': 如果该软件包在某些架构上不能被正常编译/构建或工作,请通过该标签列出。
* You can add sections so that code will run when packages are installed or removed on the real system (as opposed to just running the %install script, which only does a pseudo-install to the build root).  These are called "scriptlets", and they are usually used to update the running system with information from the package.  See the "Scriptlets" section below for more.
* You can add sections so that code will run when packages are installed or removed on the real system (as opposed to just running the %install script, which only does a pseudo-install to the build root).  These are called "scriptlets", and they are usually used to update the running system with information from the package.  See the "Scriptlets" section below for more.


RPM also supports the creation of several packages (called [[How_to_create_an_RPM_package#Subpackages|subpackages]]) from a single SPEC file, such as <code>name-libs</code> and <code>name-devel</code> packages.
RPM also supports the creation of several packages (called [[How_to_create_an_RPM_package#Subpackages|subpackages]]) from a single SPEC file, such as <code>name-libs</code> and <code>name-devel</code> packages.


Do '''not''' use these tags:
{{admon/caution|请'''不要'''使用这些标签|
* Packager
* Packager
* Vendor
* Vendor
* Copyright
* Copyright}}


Do '''not''' create a "relocatable" package; they don't add value in Fedora and make things more complicated.
Do '''not''' create a "relocatable" package; they don't add value in Fedora and make things more complicated.
== SPEC 具体含义 ==


=== %prep 部分 ===
=== %prep 部分 ===
The "%prep" 部分 describes how to unpack the compressed packages so that they can be built.
Typically, this is a set of "%setup" and/or %patch commands, which reference the Source0:, Source1:, etc. lines above.
See the [http://rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html Maximum RPM 部分 on %setup and %patch] for more details.


'''Warning:''' In spec files, don't use in-line comments (a "#" comment on the same line after a command), and don't put macros (words beginning with "%") in a comment unless you quote the "%" as "%%". Macros can cause failures if they are in a comment, because they are always expanded (even when in a comment) and they can expand to multiple lines. This is true for %prep, %build, and so on.
%prep 部分描述了解压缩源代码的方法。一般来讲,其中包含了 "<code>%setup</code>" "<code>%patch</code>" 两个命令。具体请见 [http://rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html Maximum RPM section on %setup and %patch] 以了解更多。


The new RPM 4.4.2.x series adds two new macros, %{patches} and %{sources}, so you can do things like:
<code>%{patches}</code> 和 <code>%{sources}</code> 宏在 RPM 4.4.2 后已经可用。如果您的软件包包含了许多 patch 或 source,那么可以这么做:
  for p in %{patches}; do
  for p in %{patches}; do
...
    ...
  done
  done
These new macros can be very useful if you have a large list of patches or sources.
However, keep in mind that using these will make your spec
incompatible with the rpm used in Fedora 9 and earlier, RHEL, and
many other RPM-based distros.


==== %prep 部分: %setup command ====
不过,记住在 RHEL 和其它基于 RPM 机制的发行版中,这是无法识别的。


The "%setup" command unpacks a source package, and takes several switches.  Normally you should use "-q" (quiet) to prevent setup from babbling about every file it unpacks.  Here are a few switches besides -q:
==== %prep 部分:%setup 命令 ====
* -n ''name'': If the name of the rpm is something other than what the Source unpacks to, use this switch to state the ''name'' it unpacks to.  E.G., if the tarball unpacks into a directory MYNAME, use %setup -q -n MYNAME
* -c ''name'': If the tarball doesn't unpack into a single directory, this creates a directory named ''name'' and then unpacks into it.  Useful if you have one of those annoying tarballs that doesn't have a single common subdirectory embedded in it.


There are
The "<code>%setup</code>" command unpacks a source package. Switches include:
[http://rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html more %spec options if you are unpacking multiple files], which is primarily useful if you
* '''<code>-q</code>''' : Suppress unecessary output. This is commonly used.
* '''<code>-n</code> ''name''''' : If the Source tarball unpacks into a directory whose name is not the RPM name, this switch can be used to specify the correct directory name. For example, if the tarball unpacks into the directory FOO, use "<code>%setup -q -n FOO</code>".
* '''<code>-c</code> ''name''''' : If the Source tarball unpacks into multiple directories instead of a single directory, this switch can be used to create a directory named ''name'' and then unpack into it.
 
There are [http://rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html more %spec options if you are unpacking multiple files], which is primarily useful if you
are creating subpackages (see below).  The key ones are:
are creating subpackages (see below).  The key ones are:


{|
{|
|-
|-
| -a number || Only unpack the source directive of the given number, such as –a 0 for source0:, after changing to the directory.
| <code>-a number</code> || Only unpack the Source directive of the given number after changing directory (e.g. "<code>–a 0</code>" for Source0).
|-
|-
| -b number ||  Only unpack the source directive of the given number, such as –b 0 for source0:, before changing to the directory.
| <code>-b number</code> ||  Only unpack the Source directive of the given number before changing directory (e.g. "<code>–b 0</code>" for Source0).
|-
|-
| -D || Do not delete the directory before unpacking.
| <code>-D</code> || Do not delete the directory before unpacking.
|-
|-
| -T || Disable the automatic unpacking of the archives.
| <code>-T</code> || Disable the automatic unpacking of the archives.
|}
|}


==== %prep 部分: %patch commands ====
==== %prep 部分:%patch 命令 ====


The "%patch0" command applies patch 0 (similar for 1, 2, etc.).  Patches are the normal way to change to the source code if necessary to package it.  The normal "-pNUMBER" option applies, which simply passes that argument on to ''patch''.
"<code>%patch0</code>" 命令用来打补丁“Patch0” (%patch1 打 Patch1 以此类推)。Patches 是修改源代码的最佳方式。The usual "<code>-pNUMBER</code>" option applies, which passes that argument onto the program <code>patch</code>.


Patch file names often look like "telnet-0.17-env.patch", that is, ''%{name}''-''%{version}''-''patch_purpose''.patch (some people omit -''%{version}''). Patch files are typically the result of a "diff -u"; if you do this from the subdirectory of ~/rpmbuild/BUILD, you won't have to specify a -p level later.  You can use all the normal ways of creating a patch file.
Patch file names often look like "<code>telnet-0.17-env.patch</code>", which is the format <code>%{name} - %{version} - REASON.patch</code>" (though sometimes version is omitted). Patch files are typically the result of "<code>diff -u</code>"; if you do this from the subdirectory of <code>~/rpmbuild/BUILD</code> then you won't have to specify a <code>-p</code> level later.


If you're creating a patch file a single file FILENAME, a common way is to copy it to FILENAME.orig, modify it, and then save the results of "diff -u FILENAME.orig FILENAME".  If you change directory to "~/rpmbuild/BUILD/''NAME''", you could create a patch file to change a single file by doing:
简单的创建 patch 方法:
  cp X/Y.Z X/Y.Z.orig
  cp foo/bar foo/bar.orig
  vim X/Y.Z
  vim foo/bar
  diff -u X/Y.Z.orig X/Y.Z > ~/rpmbuild/SOURCES/PKGNAME.REASON.patch
  diff -u foo/bar.orig foo/bar > ~/rpmbuild/SOURCES/PKGNAME.REASON.patch


If you're going to edit many files, one easy method is to copy the whole subdirectory underneath BUILD, and then do subdirectory diffs; once you change directory to "~rpmbuild/BUILD/''NAME''", you can:
If editing many files, one easy method is to copy the whole subdirectory underneath <code>BUILD</code> and then do subdirectory diffs.  After you have changed directory to "<code>~rpmbuild/BUILD/NAME</code>", do the following:
  cp -pr ./ ../PACKAGENAME.orig/
  cp -pr ./ ../PACKAGENAME.orig/
  ... many edits ...
  ... many edits ...
  diff -u ../PACKAGENAME.orig . > ~/rpmbuild/SOURCES/''NAME''.''REASON''.patch
  diff -u ../PACKAGENAME.orig . > ~/rpmbuild/SOURCES/''NAME''.''REASON''.patch


If you edit many files in one patch, you can also copy the original files using some consistent ending such as ".orig" before editing them. Then, you can use "gendiff" (in the rpm package) to create a patch with the differences.  Do "man gendiff" for more information.
If you edit many files in one patch, you can also copy the original files using some consistent ending such as "<code>.orig</code>" before editing them. Then, you can use "<code>gendiff</code>" (in the <code>rpm-build</code> package) to create a patch with the differences.


Try to ensure that in your patch the "context" matches exactly.
Try to ensure that your patch match the context exactly. The default "fuzz" value is "<code>0</code>", requiring matches to be exact. You can work around this by adding "<code>%global _default_patch_fuzz 2</code>" to revert to the value found in older versions of RPM in Fedora, but it is generally recommended to avoid doing this.
In old versions of Fedora, the default "fuzz" value was 2, which meant that imprecise matches were acceptable.
However, the version of [http://lwn.net/Articles/289235/ RPM used by Fedora 10 and later] have a default fuzz to 0, requiring that matches be exact.
You can work around this by adding "%global _default_patch_fuzz 2", but it's better to not
have the problem by making the patch match the context exactly.


As explained in [[Packaging/PatchUpstreamStatus]], all patches in Fedora spec files SHOULD have a comment above them about their upstream status. This should document the upstream bug/email that includes it (including the date), or if it's Fedora-unique, why it is unique.
As explained in [[Packaging/PatchUpstreamStatus]], all patches should have a comment above them in the SPEC file about their upstream status. This should document the upstream bug/email that includes it (including the date). If it is unique to Fedora, you should mention why it is unique. The Fedora Project tries not to deviate from upstream; see [[PackageMaintainers/WhyUpstream]] for the importance of this.
The Fedora Project focuses, as much as possible, on not deviating from upstream in the software it includes in the repository - see [[PackageMaintainers/WhyUpstream|Staying close to upstream projects]] for more about why it's important to do this.


==== %prep 部分: Unmodified files ====
==== %prep 部分:Unmodified files ====


Sometimes, you'll package just a straight file that doesn't need to be uncompressed, e.g., a "Source1:" that is just a simple PDF file. These might not be from external sources, e.g., perhaps you've had to create a few additional files that weren't in the original sources so that the package cleanly installs in Fedora.  You can "prep" those into the build directory by doing this (replace "1" with whatever number it is):
Sometimes, one or more of the Source files do not need to be uncompressed. You can "prep" those into the build directory like this (where <code>SOURCE1</code> refers to the relevant Source file):
  cp -p %SOURCE1 .
cp -p %SOURCE1 .


=== %build 部分 ===
=== %build 部分 ===


The "%build" 部分 is sometimes complicated; here you configure and compile/build the files to be installed.
The "%build" section is sometimes complicated; here you configure and compile/build the files to be installed.


Many programs follow the GNU configure approach (or some variation). By default, they will install to a prefix of "/usr/local" (/usr/local/bin, /usr/local/lib, etc.), which is a reasonable default for unpackaged files. However, since you ''are'' packaging it, you will want to change the prefix to "/usr", since this is now a package maintained by the system itself. If there are any libraries, they'll need to be installed in the right directory, which is either /usr/lib or /usr/lib64 depending on the architecture (the actual value is in %{_libdir}).
Many programs follow the GNU <code>configure</code> approach (or some variation). By default, they will install to a prefix of "<code>/usr/local</code>", which is reasonable for unpackaged files. However, since you are packaging it, change the prefix to "<code>/usr</code>". Libraries should be installed to either <code>/usr/lib</code> or <code>/usr/lib64</code> depending on the architecture.


Since the GNU "configure" system is so common, rpm pre-defines a macro named "%configure", which invokes GNU configure with the right options (e.g., it changes --prefix to /usr). This means that some variation of this will often work as a build command:
Since GNU <code>configure</code> is so common, the macro "<code>%configure</code>" can be used to automatically invoke the correct options (e.g. change the prefix to <code>/usr</code>). Some variation of this often works:
   %configure
   %configure
   make %{?_smp_mflags}
   make %{?_smp_mflags}


Sometimes you'll want to override the variables of a makefile; you can easily do that by passing them as parameters to make, like this:
To override makefile variables, pass them as parameters to <code>make</code>:
  make %{?_smp_mflags} CFLAGS="%{optflags}" BINDIR=%{_bindir}
  make %{?_smp_mflags} CFLAGS="%{optflags}" BINDIR=%{_bindir}


If you need to do something complicated with GNU-generated configure, take a look at [http://sourceware.org/autobook/ "GNU autoconf, automake, and libtool"].  A good presentation on these as well as "make" is [http://www.suse.de/~sh/automake/automake.pdf "Open Source Development Tools: An Introduction to Make, Configure, Automake, Autoconf" by Stefan Hundhammer].
More more information, see [http://sourceware.org/autobook/ "GNU autoconf, automake, and libtool"] and [http://www.suse.de/~sh/automake/automake.pdf "Open Source Development Tools: An Introduction to Make, Configure, Automake, Autoconf" by Stefan Hundhammer].


Some programs use Cmake.  See [[Packaging/cmake]] for some suggestions.
Some programs use <code>cmake</code>.  See [[Packaging/cmake]].


If you include some self-tests (and that's a good idea), put them in a separate "%check" 部分 that immediately follows the "%build" area, instead of including them in %build.  That way, it will be easy for the system to skip unnecessary self-tests.
=== %check 部分 ===


=== %check 部分 ===
If self-tests are available, it is generally a good idea to include them. They should be placed in the %check section (which immediately follows the %build section) instead of within the %build section itself, so that they can be easily skipped when necessary.


"%check" 部分负责测试,与 "make test" 产生的效果一致。
Often, this section contains:
不过,绝大多数软件包并没有包含这步,因为 RPM 都会在严格的测试后放出。
make test


=== %install section ===
=== %install 部分 ===


The "%install" section is a set of script commands to "install" the program. The commands in this section should copy the files from a directory inside the "build directory" %{_builddir} (normally ~/rpmbuild/BUILD/''something'') into the build root directory, %{buildroot} (normally /var/tmp/''something''), creating the directories inside %{buildroot} as necessary.
This section involves script commands to "install" the program, copying the relevant files from <code>%{_builddir}</code> to <code>%{buildroot}</code> (which usually means from <code>~/rpmbuild/BUILD</code> to <code>~/rpmbuild/BUILDROOT</code>) and creating directories inside <code>%{buildroot}</code> as necessary.


'''Watch out''': Some of the terminology is very misleading:
Some of the terminology can be misleading:
* The ''build directory'' (under which compilations occur during %build) and the ''build root'' (where files are copied into during the %install process) are '''different'''.  The point of the %install process is to copy files, such as those under the build directory, to the right place in the build root. Perhaps "buildroot" should be called "installroot", but it's too late now, the terminology is entrenched.
* The "build directory", also known as <code>%{_builddir}</code> is not the same as the "build root", also known as <code>%{buildroot}</code>. Compilation occurs in the former directory, while files to be packaged are copied from the former to the latter.
* The build directory is normally ~/rpmbuild/BUILD, while the build root (where files get installed to during %install) is normally ~/rpmbuild/BUILDROOT.  The %prep stage will normally create a subdirectory underneath the build directory as part of %setup, and populate the build directory with files (based on the source information in %_sourcedir, which is typically in ~/rpmbuild/SOURCES). During %build, the current directory will actually start at %{buildsubdir}, that newly-created  subdirectory under the build directory.  Typically %{buildsubdir} is something like ~/rpmbuild/BUILD/%{name}-%{version}.
* During the %build section, the current directory will start at <code>%{buildsubdir}</code>, which is the subdirectory within <code>%{_builddir}</code> that was created during %prep stage. This is usually something like <code>~/rpmbuild/BUILD/%{name}-%{version}</code>.
* The "%install" script is ''not'' used when the binary rpm package is installed by the end-user!! The term "%install" is misleading, in fact, the script must ''not'' install the programs in the REAL final locations (e.g., in /usr/bin), but under the buildroot %{buildroot}.
* The %install section is '''not''' run when the binary RPM package is installed by the end-user, but is only run when creating a package.


Normally, the install script would first erase the %{buildroot} directory, and then do some variation of "make install" (ideally using DESTDIR=%{buildroot}, if the program supports it). Here's an example of an %install section:
Normally, some variation of "<code>make install</code>" is performed here:
  %install
  %install
  rm -rf %{buildroot}
  rm -rf %{buildroot}
  make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install
  make DESTDIR=%{buildroot} install
 
Removal of <code>%{buildroot}</code> is no longer necessary, except for EPEL 5.


Ideally, every program would have a "make install" command that supported the [http://www.gnu.org/prep/standards/html_node/DESTDIR.html ''DESTDIR'' convention].  If the program includes a "make install" that supports DESTDIR, where possible, ''use it''. The DESTDIR convention supports redirecting file installations to descend from a specific directory, which is exactly what we want during %install.
Ideally you should use [http://www.gnu.org/prep/standards/html_node/DESTDIR.html <code>DESTDIR=%{buildroot}</code>] if the program supports it, as it redirects file installations to the specified directory and is exactly what we want to happen during the %install section.


Installing a program that does not support DESTDIR can be much harder, and no option is as good as native DESTDIR support.  Consider these alternatives:
If the program does not support <code>DESTDIR</code> (and only if), you can workaround it in one of several (inferior) ways:
* Patch the makefile so that it ''does'' support DESTDIR. Create directories inside DESTDIR where necessary (feel free to use "mkdir -p", the "-p" option of mkdir is now standard and widely supported).  Be sure to submit the patch upstream.
* Patch the makefile so that is supports <code>DESTDIR</code>. Create directories inside <code>DESTDIR</code> where necessary and submit the patch upstream.
* Use "%makeinstall". Many older RPM documents suggest using "%makeinstall", which ''might'' work if "make install" doesn't support DESTDIR.  However, as noted in the Fedora guidelines, the %makeinstall macro "must NOT be used when make install DESTDIR=%{buildroot} works. %makeinstall is (merely) a kludge that can work with Makefiles that don't make use of the DESTDIR variable...".  Unfortunately, this sometimes has subtle failures, which is why %makeinstall should not be used if DESTDIR works.  The reason is based on how %makeinstall works. The "%makeinstall" macro expands to something like "<tt>make prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ... install</tt>".  Many programs will quietly recompile or change parts of the program when values like prefix are changed, resulting in an incorrect installation. See the Fedora guidelines if you want the details on why this approach can fail.  You will probably need to create appropriate directories inside %buildroot before calling %makeinstall (e.g., <tt>mkdir -p %{buildroot}%{_bindir}/</tt>).
* Use the "<code>%makeinstall</code>" macro. This method might work, but can lead to subtle failures. It expands to something like "<code>make prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ... install</code>", which can result in some programs failing to work properly. Create directories inside <code>%{buildroot}</code> where necessary.
* Consider using the auto-destdir package. This requires "BuildRequires: auto-destdir", and changing "make install" to "make-redir DESTDIR=%{buildroot} install". This only works well if the installation uses only certain common commands to install files, like cp and install; see "man make-redir" for details.
* Consider using the <code>auto-destdir</code> package. This requires "<code>BuildRequires: auto-destdir</code>", and changing "<code>make install</code>" to "<code>make-redir DESTDIR=%{buildroot} install</code>". This only works well if the installation uses only certain common commands to install files, like <code>cp</code> and <code>install</code>.
* Do the installation "by hand", that is, instead of invoking a build system, copy the files to the correct locations. Basically, this would be a sequence that would create directories that weren't already created by the "BuildRequires" packages (typically using install -d or mkdir -p), followed by copying of files from the current directory (inside the build directory) into the buildroot directory (typically using "cp -p" and/or "install -p"). Running "make -n install" may make it easy to determine what this sequence should be.  Be sure to create directories inside %buildroot where necessary. One serious problem with this approach is that it's easy to fail to install new or renamed files during an update&mdash;so if there's a better approach, use it instead.  If you ''do'' perform the installation "by hand", be ''especially'' careful with updates when using this approach. For example:
* Perform the installation by hand. This would involve creating the necessary directories under <code>%{buildroot}</code> and copying files from <code>%{_builddir}</code> to <code>%{buildroot}</code>. Be especially careful with updates, which often contain new or changed filenames. An example of this procedure:
  %install
  %install
  rm -rf %{buildroot}
  rm -rf %{buildroot}
Line 460: Line 421:
  cp -p mycommand %{buildroot}%{_bindir}/
  cp -p mycommand %{buildroot}%{_bindir}/


As noted in the [[Packaging:Guidelines#Timestamps|packaging guidelines' timestamp section]], "when adding file copying commands in the spec file, consider using a command that preserves the files' timestamps, eg. cp -p or install -p".  So, if the makefile lets you override the install command (typically named INSTALL), you might want something like INSTALL="install -p" CP="cp -p" as make parameters, like this:
As noted in [[Packaging:Guidelines#Timestamps]], try to preserve timestamps if the makefile lets you override commands:
  make INSTALL="install -p" CP="cp -p" DESTDIR=%{buildroot} install
  make INSTALL="install -p" CP="cp -p" DESTDIR=%{buildroot} install


=== %files section ===
=== %files 部分 ===
The %files section identifies what files and directories were added by the package - and thus, which files and directories are ''owned'' by the package.  Ownership is important - when you type "rpm -qif ''blah''",  you'll see who owns ''blah''.  This section is used when performing the ''bin'' stage, to determine which files are placed into each binary RPM file.
This section declares which files and directories are owned by the package, and thus which files and directories will be placed into the binary RPM.


==== %files Basics ====
==== %files basics ====


The %files section normally begins with a %defattr line which sets the default file permissions. The format of this is %defattr(<file permissions>, <user>, <group>, <directory permissions>), that is, one can specify the permissions to apply to files and directories in the %files section. The fourth parameter is often omitted. Usually one uses %defattr(-,root,root,-), where "-" means "use the default permissions".
The <code>%defattr</code> set the default file permissions, and is often found at the start of the <code>%files</code> section. Note that this is no longer necessary unless the permissions need to be altered. The format of this is:
%defattr(<file permissions>, <user>, <group>, <directory permissions>)
The fourth parameter is often omitted. Usually one uses <code>%defattr(-,root,root,-)</code>, where "<code>-</code>" uses the default permissions.


This is followed by names or patterns of the directories or files to be installed and owned by this package. You should use macros for directory names, e.g., use %{_bindir}/myfile instead of /usr/bin/myfile, and %{_sbindir}/killaccount instead of /usr/sbin/killaccount. If a name or pattern begins with "/" when expanded, then it is presumed to have been copied into the %{buildroot} followed by that pattern; when installed on the final system, it will be copied into that name ''without'' the buildroot prefix.  If you don't precede the pattern with "/", then it is presumed to be in the current directory (e.g., inside the build directory) - this is used for "documentation" files. So if your package just installs /usr/sbin/mycommand, then your %files section ''could'' simply say:
You should then list all the files and directories to be owned by the package. Use macros for directory names where possible, which can be viewed at [[Packaging:RPMMacros]] (e.g. use <code>%{_bindir}/mycommand</code> instead of <code>/usr/bin/mycommand</code>). If the pattern begins with a "<code>/</code>" (or when expanded from the macro) then it is taken from the <code>%{buildroot}</code> directory. Otherwise, the file is presumed to be in the current directory (e.g. inside <code>%{_builddir}</code>, such as documentation files that you wish to include). If your package only installs a single file <code>/usr/sbin/mycommand</code>, then the <code>%files</code> section can simply be:
  %files
  %files
%defattr(-,root,root,-)
  %{_sbindir}/mycommand
  %{_sbindir}/mycommand


Any file or directory identified in the %files section is ''owned'' by the defining package. You should make sure that you declare ownership of every new file or directory the package creates.  You can use wildcards (*) which match a set of files - this makes the package less sensitive to changes. For example, you can declare that all the files that were copied into %{buildroot}/usr/bin are owned by this package by declaring:
To make your package less sensitive to upstream changes, declare all files within a directory to be owned by the package with a pattern match:
  %{_bindir}/*
  %{_bindir}/*


Note that "%{_bindir}/*" does not claim that this package owns the /usr/bin directory - it claims that all the files that were installed inside the ''build root'' 's /usr/bin are owned by the package.
To include a single directory:
If you list a ''directory'' in the %files section, then you are claiming that this package owns that subdirectory and all files and directories in it, recursively (''all'' the way down) if they are present in the build root.  Do not list the "/usr/bin" or "%{_bindir}" directories directly in your %files list, because that would claim ownership of /usr/bin and everything inside it.  Claiming ownership of "%{_bindir}/*" is fine, though; that just claims ownership of the subdirectories and files you placed ''under'' %{buildroot}/%{_bindir}.  If you create a subdirectory such as %{_datadir}/%{name}, (/usr/share/NAME), you ''should'' include that directory in the %files list:
  %{_datadir}/%{name}/
  %{_datadir}/%{name}/


It's usually easier to use wildcards for filenames, and that's also better at coping with changes in upstream.  Older RPM documentation typically shows long lists under %files with individual names, such as /usr/bin/program1 followed by /usr/bin/program2. Because of the way Fedora now uses buildroots, that is no longer necessary.
Note that <code>%{_bindir}/*</code> does not claim that this package owns the <code>/usr/bin</code> directory, but only the files contained within. If you list a directory, then you are claiming that the package owns that directory and all files and subdirectories contained within. Thus, do '''not''' list <code>%{_bindir}</code> and be careful of directories that may be shared with other packages.


It's an error if ''no'' file matches the wildcard of a line, so only note the directories that actually matter.  Also, you can't identify the same file or directory more than once.  Finally, it's an error to have something in the buildroot and ''not'' listed under %files; the whole point of copying something into the buildroot is because you intend to have it installed in the final system.  If you don't intend that, remove those files during the %install process.
如果满足下列条件,会有错误发生:
* a pattern match does not match any file or directory
* a file or directory is listed or matched more than once
* a file or directory in the <code>%{buildroot}</code> has not been listed


It is also possible to exclude files from a previous match by using a %exclude glob. This can be useful for including "almost all" of the files that match a different glob. However, note that, like any other file glob, even a %exclude glob will fail if it matches nothing. (This might be considered counterintuitive, as the whole point is essentially to ensure that a certain file ISN'T there, so this rule is especially important to remember.)
It is also possible to exclude files from a previous match by using the <code>%exclude</code> glob. This can be useful for including almost all of the files included by a different pattern match, but note that it will also fail if it does not match anything.


==== %files prefixes ====
==== %files prefixes ====
You may need to add one or more prefixes to a %files entry (if more than one, use a space to separate them).
You may need to add one or more prefixes to lines in the <code>%files</code> section; seperate them with a space. See [http://www.rpm.org/max-rpm/s1-rpm-inside-files-list-directives.html Max RPM section on %files directives].


Typically there is a "%doc" entry with a list of documentation files that didn't get copied into the buildroot; usually there is at least a README and LICENSE file.  You ''must'' include the license file, if there is one. You may prefix some of these with %attr(mode, user, group) to set the file permission mode, user, or group.  You don't need to claim ownership of the /usr/share/doc/%{name} directory, that's automatic if there's a %doc entry.  Any %doc entry must not affect the runtime of the application (if it is in %doc, the program must run properly if it is not present).
Usually, "<code>%doc</code>" is used to list documentation files within <code>%{_builddir}</code> that were not copied to <code>%{buildroot}</code>. A <code>README</code> and <code>INSTALL</code> file is usually included. They will be placed in the directory <code>/usr/share/doc/%{name}-%{version}</code>, whose ownership does not need to be declared.


There is a potential 'gotcha' with %doc entries: if you have a %doc entry, then you can't use commands during %install to copy files into the documentation directory descending from %_defaultdocdir. That's because if there's a %doc entry, rpmbuild will automatically remove the docdir files created by %install before installing the files listed with %doc. This can hit you if, for example, you want an "examples" subdirectory in the documentation directory.  In this case, don't use "%doc" to mark documentation.  Instead, create the directories and copy the files into %{buildroot}%{_defaultdocdir}/%{name}-%{version}/ during %install, and make sure that %files includes an entry for "%{_defaultdocdir}/%{name}-%{version}/".  They will still be correctly marked as documentation.
'''Note:''' If specifying a <code>%doc</code> entry, then you can't copy files into the documentation directory during the <code>%install</code> section. If, for example, you want an "examples" subdirectory within the documentation directory, don't use <code>%doc</code>, but instead create the directories and copy files over manually into <code>%{buildroot}%{_defaultdocdir}/%{name}-%{version}</code> during the %install section. They will be correctly marked as documentation. Make sure you include <code>%{_defaultdocdir}/%{name}-%{version}/</code> as an entry in the %files section.


If you save configuration files (under /etc - don't put them under /usr), you should normally prefix them with %config(noreplace) unless this program version uses a non-backwards-compatible configuration format (in which case, prefix them with %config).
Configuration files should be placed in <code>/etc</code> and are normally specified like this (which makes sure user changes aren't overwritten on update):
%config(noreplace) %{_sysconfdir}/foo.conf
If the update uses a non-backwards-compatible configuration format, then specify them like this:
%config %{_sysconfdir}/foo.conf


Prefixing a %files entry with "%attr(mode, user, group)" lets you set the permissions for particular file(s), e.g., "%attr(0644, root, root)".  A "-" means "use the default".
"<code>%attr(mode, user, group)</code>" can be used for finer control over permissions, where a "<code>-</code>" means use the default:
%attr(0644, root, root) FOO.BAR


If a file is in particular natural language, use %lang to note that. E.G.:
If a file is in particular natural language, use <code>%lang</code> to note that:
  %lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*
  %lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*


Programs using Locale files should follow the
Programs using Locale files should follow the [[Packaging:Guidelines#Handling_Locale_Files|recommended method of handling i18n files]]:
[[Packaging:Guidelines#Handling_Locale_Files|recommended method of handling the i18n files]]:
 
* find the filenames in the <code>%install</code> step: <code> %find_lang ${name}</code>
* find the filenames in the <code>%install</code> step: <code> %find_lang ${name}</code>
* add the required build dependencies: <code>BuildRequires: gettext</code>
* add the required build dependencies: <code>BuildRequires: gettext</code>
* use the found filenames: <code>%files -f ${name}.lang</code>
* use the found filenames: <code>%files -f ${name}.lang</code>


Some documentation claims that %license and %readme are valid prefixes; they are ''not'' valid in Fedora.  Use %doc instead.
These prefixes are '''not''' valid in Fedora: <code>%license</code> and <code>%readme</code>.


==== %files and Filesystem Hierarchy Standard (FHS) ====
==== %files and Filesystem Hierarchy Standard (FHS) ====


You should follow the [http://www.pathname.com/fhs/ Filesystem Hierarchy Standard (FHS)], i.e., ordinary application executables go into /usr/bin, global configuration files go into /etc, ordinary libraries go into /usr/lib, and so on, with one exception: executables that should ''not'' normally be executed directly by users or administrators should go into a subdirectory of /usr/libexec; usually you'd refer to the necessary directory as "%{_libexecdir}/%{name}".
You should follow the [http://www.pathname.com/fhs/ Filesystem Hierarchy Standard (FHS)]. Executables go in <code>/usr/bin</code>, global configuration files go in <code>/etc</code>, libraries go into <code>/usr/lib</code> (or <code>/usr/lib64</code>) and so on. There is one exception: executables that should not normally be executed directly by users or administrators should go in a subdirectory of <code>/usr/libexec</code>, which is referred to as <code>%{_libexecdir}/%{name}</code>.


You shouldn't be installing files under /usr/local; that is where ''unpackaged'' files go.
Do '''not''' install files into <code>/opt</code> or <code>/usr/local</code>.
Typically there will be a "prefix" attribute that lets you set the prefix to be "/usr" instead of "/usr/local".


Unfortunately, many programs' "normal" installation routines do not follow the FHS.
Unfortunately, many programs do not follow the FHS by default. In particular, architecture-independent libraries get placed in <code>/usr/lib</code> instead of <code>/usr/share</code>. The former is for architecture-dependent libraries, while the latter is for architecture-independent libraries, which means that systems with different CPU architectures can share <code>/usr/share</code>. There are many exceptions in Fedora (such as Python and Perl), but Fedora applies this rule more strictly than some distributions. <code>rpmlint</code> will generally complain if you put anything other than ELF files into <code>/usr/lib</code>.
In particular, many programs normally place architecture-independent libraries under /usr/lib, instead of
under /usr/share as the FHS requires.
The [http://www.pathname.com/fhs/pub/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA FHS /usr/lib section] says that
/usr/lib is for architecture-''dependent'' data (e.g., ELF files like .so files), while
[http://www.pathname.com/fhs/pub/fhs-2.3.html#USRSHAREARCHITECTUREINDEPENDENTDATA /usr/share] is for
architecture-''independent'' data.  That way, systems with different CPUs can share /usr/share.
There are many exceptions to this rule in Fedora (e.g., Python and Perl), but Fedora applies this rule more
strictly than some distributions. Note, for example, that rpmlint will complain if you
put just about anything other than ELF files into /usr/lib.


==== %files example ====
==== %files 示例 ====


Here's a simple example of a %files section:
Here's a simple example of a %files section:
  %files
  %files
%defattr(-,root,root,-)
  %doc README LICENSE
  %doc README LICENSE
  %{_bindir}/*
  %{_bindir}/*
  %{_sbindir}/*
  %{_sbindir}/*
  %{_datadir}/%{name}/
  %{_datadir}/%{name}/
%config(noreplace) %{_sysconfdir}/*.conf


==== Finding duplicates ====
==== 找出重复内容 ====
 
The Fedora guidelines require that
"A Fedora package must not list a file more than once in the spec
file's %files listings."


You can list any duplicates of two binary packages by doing:
You can list any duplicates of two binary packages by doing:
Line 552: Line 504:


=== Scriptlets ===
=== Scriptlets ===
You can add sections so that code will run when packages are installed or removed on the real system (as opposed to just running the %install script, which only does a pseudo-install to the build root).  These are called "scriptlets", and they are usually used to update the running system with information from the package.


The scriptlets in %pre and %post are run before and after a package is installed (respectively). The scriptlets %preun and %postun are run before and after a package is uninstalled. The scriptlets %pretrans and %posttrans are run at start and end of a transaction.  See [[Packaging/ScriptletSnippets]] for more examples and details.  For example, every binary RPM package which stores shared library files (not just symlinks) in any of the dynamic linker's default paths, must call ldconfig in %post and %postun (post-install and post-uninstall). If the package has multiple subpackages with libraries, each subpackage should also have a %post/%postun section that calls /sbin/ldconfig. For example:
When an end-user installs the RPM, you may want some commands to be run. This can be achieved through scriptlets. See [[Packaging/ScriptletSnippets]].
 
Scriptlets can be run:
* before ('''<code>%pre</code>''') or after ('''<code>%post</code>''') a package is installed
* before ('''<code>%preun</code>''') or after ('''<code>%postun</code>''') a package is uninstalled
* at the start ('''<code>%pretrans</code>''') or end ('''<code>%posttrans</code>''') of a transaction
 
For example, every binary RPM package that stores shared library files in any of the dynamic linker's default paths, must call <code>ldconfig</code> in <code>%post</code> and <code>%postun</code>. If the package has multiple subpackages with libraries, each subpackage should also perform the same actions.
  %post -p /sbin/ldconfig
  %post -p /sbin/ldconfig
  %postun -p /sbin/ldconfig
  %postun -p /sbin/ldconfig


''Beware'': The "-p" option specifies what ''command processor'' to use for the commands on the following lines.
If only running a single command, then the "<code>-p</code>" option runs the adjacent command without invoking the shell. However, for several commands, omit this option and include the shell commands beneath.
If there are no following lines, then using /sbin/ldconfig as the "command processor" is a minor efficiency improvement compared to putting "/sbin/ldconfig" on the next line, and letting the shell invoke it.
That's because by using "-p",
the shell isn't invoked simply to invoke a single program.
But if you have multiple shell commands,
don't use "-p" or /sbin/ldconfig after it!  Instead, leave it blank, and include the shell commands under it.


If you are going to run programs in scriptlets, they must be installed before you run them.
If you run any programs within the scriptlets, then you must specify any requirements in the form "<code>Requires(CONTEXT)</code>" (e.g. <code>Requires(post)</code>).
You have to use special variants of the "Requires:" tag, so that
the program will be installed before you try to use it.  These are of the form "Requires(CONTEXT):", e.g., "Requires(post)".


Most scriptlets (%pre, %post, %preun, and %postun) provide an argument you can use,
<code>%pre</code>, <code>%post</code>, <code>%preun</code>, and <code>%postun</code> provide the argument <code>$1</code>, which is the number of packages of this name which will be left on the system when the action completes. Don't compare for equality with <code>2</code>, but instead check if they are greater than or equal to <code>2</code>. For <code>%pretrans</code> and <code>%posttrans</code>, <code>$1</code> is always <code>0</code>.
accessed via $1, which is the number of packages of this name which will be left on the system
when the action completes.
Don't compare for ''equality'' with 2; check if they are ''greater than or equal than'' 2, since
users can arrange to have multiple versions of a package installed simultaneously.
For %pretrans and %posttrans, $1 is always 0.
 
For example, after adding an info manual to the system the dir file
which indexes the info manuals should be updated.
Basically, after you install the info manual, you need to run the program install-info.  That's fine, except that install-info is part of package info, and there's no guarantee that info is installed unless we require it. Also, if "install-info" fails, we don't want to fail ''all'' processing. Here's one way to do that:


For example, if the package installs an info manual, then the info manual index must be updated with <code>install-info</code> from the <code>info</code> package. Firstly, there is no guarantee that the <code>info</code> package will be available unless we explicitly declare it as required, and secondly, we don't want to fail completely if <code>install-info</code> fails:
  Requires(post): info
  Requires(post): info
  Requires(preun): info
  Requires(preun): info
Line 590: Line 533:
  fi
  fi


There is another glitch related to installing info files. The <code>install-info</code> command will update
There is one other glitch related to installing info manuals. The <code>install-info</code> command will update the info directory, so we should delete the useless empty directory from the %{buildroot} during the <code>%install</code> section:
the info directory, but we have to prevent the install of a useless, empty directory file from the  
RPM_BUILD_ROOT environment, by deleting it in  the <code>%install</code> section:
  rm -f $RPM_BUILD_ROOT%{_infodir}/dir
  rm -f %{buildroot}%{_infodir}/dir


Another scriptlet-like abilility are ''triggers''.  You can define triggers for when ''other'' packages
Another scriptlet-like abilility are "triggers", which can be run for your package when other packages are installed or uninstalled. See [http://rpm.org/api/4.4.2.2/triggers.html RPM Triggers].
are installed or uninstalled. See ''Maximum RPM'' for more information about triggers.


=== Macros ===
=== ===


Spec files may contain "macro" references (text beginning with "%"), which are replaced with other values.
宏通常以 <code>%{string}</code> 的格式出现,下面介绍常见的宏:
You can follow % by a word, e.g., "%name", but just like shell variables you must bracket the name with {...}
if letters or digits immediately follow, e.g., "%{name}".
 
As noted in the
[[Packaging/Guidelines| Packaging Guidelines]],
There are two styles for referring some values such as the rpm Build Root and Optimization Flags:
* "macro style": %{buildroot}, %{optflags}
* "variable style": $RPM_BUILD_ROOT, $RPM_OPT_FLAGS
Pick a style and use it consistently throughout your packaging; this document uses "macro style".
 
Here are some typical macros:


{|
{|
! Macro !! Typical Expansion !! Meaning
! 名称 !! 通常含义 !! 解释
|-
|-
| %{_bindir} || /usr/bin || Binary directory (where executables are usually stored)
| <code>%{_bindir}</code> || <code>/usr/bin</code> || 二进制文件存储目录,通常可执行。
|-
|-
| %{_builddir} || ~/rpmbuild/BUILD || Build directory; files are compiled a subdirectory of the build directory.  See %buildsubdir.
| <code>%{_builddir}</code> || <code>~/rpmbuild/BUILD</code> || 构建目录:构建软件包的目录,具体请见 <code>%buildsubdir</code>。
|-
|-
| %{buildroot} || ~/rpmbuild/BUILDROOT || Build root, where files are "installed" during %install. The %install stage copies files from a subdirectory of %{_builddir} to a subdirectory of %{buildroot}. Historically %{buildroot} was in "/var/tmp/".
| <code>%{buildroot}</code> || <code>~/rpmbuild/BUILDROOT</code> || Build root: where files are "installed" during the <code>%install</code> stage, which copies files from a subdirectory of <code>%{_builddir}</code> to a subdirectory of <code>%{buildroot}</code>. (Historically, <code>%{buildroot}</code> was in "/var/tmp/".)
|-
|-
| %{buildsubdir} || %{_builddir}/%{name} || Build subdirectory, where files are compiled during %build. It's under %{_builddir}, set after %setup.
| <code>%{buildsubdir}</code> || <code>%{_builddir}/%{name}</code> || Build subdirectory: a subdirectory within <code>%{_builddir}</code> where files are compiled during the <code>%build</code> stage. It is set after <code>%setup</code>.
|-
|-
| %{_datadir} || /usr/share || Share directory.
| <code>%{_datadir}</code> || <code>/usr/share</code> || 系统共享目录
|-
|-
| %{_defaultdocdir} || /usr/share/doc || Default documentation directory.
| <code>%{_defaultdocdir}</code> || <code>/usr/share/doc</code> || 默认文档目录
|-
|-
| %{dist} || .fc''NUMBER'' || Distribution+version short name (e.g., ".fc9")
| <code>%{dist}</code> || <code>.fc''NUMBER''</code> || 发行版名称+版本号(例如 "<code>.fc{{FedoraVersion}}</code>")
|-
|-
| %{fedora} || ''NUMBER'' || Number of fedora release (e.g., 9)
| <code>%{fedora}</code> || <code>''NUMBER''</code> || 发行版版本号(例如 "<code>9</code>")
|-
|-
| %{_includedir} || /usr/include
| <code>%{_includedir}</code> || <code>/usr/include</code>
|-
|-
| %{_infodir} || /usr/share/info
| <code>%{_infodir}</code> || <code>/usr/share/info</code>
|-
|-
| %{_initrddir} || /etc/rc.d/init.d
| <code>%{_initrddir}</code> || <code>/etc/rc.d/init.d</code>
|-
|-
| %{_libdir} || /usr/lib
| <code>%{_libdir}</code> || <code>/usr/lib</code>
|-
|-
| %{_libexecdir} || /usr/libexec
| <code>%{_libexecdir}</code> || <code>/usr/libexec</code>
|-
|-
| %{_localstatedir} || /var
| <code>%{_localstatedir}</code> || <code>/var</code>
|-
|-
| %{_mandir} || /usr/share/man
| <code>%{_mandir}</code> || <code>/usr/share/man</code>
|-
|-
| %{name} || || Name of package, set by Name: tag
| <code>%{name}</code> || || 软件包名称。set by Name: tag
|-
|-
| %{_sbindir} || /usr/sbin
| <code>%{_sbindir}</code> || <code>/usr/sbin</code>
|-
|-
| %{_sharedstatedir} || /var/lib
| <code>%{_sharedstatedir}</code> || <code>/var/lib</code>
|-
|-
| %{_sysconfdir} || /etc
| <code>%{_sysconfdir}</code> || <code>/etc</code>
|-
|-
| %{version} || || Version of package, set by Version: tag
| <code>%{version}</code> || || 软件包版本。set by Version: tag
|}
|}


To see more about macros you
Learn more about macros by looking in <code>/etc/rpm/*</code> and <code>/usr/lib/rpm</code>, especially <code>/usr/lib/rpm/macros</code>. Also use <code>rpm --showrc</code> to show values that RPM will use for macros (altered by <code>rpmrc</code> and macro configuration files).
can look in /etc/rpm/* and the "macros" files under "/usr/lib/rpm/",
especially /usr/lib/rpm/macros.
You can also use "rpm --showrc" to show the values rpm will use for all of the options
currently set in rpmrc and macro configuration files.


You can set your own macro values using %global; be sure to define them before you use them. Macro definitions
You can set your own macro values using %global, but be sure to define them before you use them. (Macro definitions can also refer to other macros.) For example:
can refer to other macros.  For example:
  %global date 2012-02-08
  %global myvalue 50


You can use rpmbuild to find the value of some macro, using its "-E" (--eval) option. For example, to find the current expansion of %{_bindir} in myfile.spec, you can run:
Use the "<code>-E</code>" option of <code>rpmbuild</code> to find the value of a macro in a SPEC file:
  rpmbuild -E '%{_bindir}' myfile.spec
  rpmbuild -E '%{_bindir}' myfile.spec


[[Packaging/RPMMacros]] has more information on macros, as does
Also see [[Packaging/RPMMacros]] and [https://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch09s07.html RPM Guide chapter 9].
[http://docs.fedoraproject.org/drafts/rpm-guide-en/ch09s07.html RPM Guide chapter 9].


=== Other tags ===
=== 其它标签 ===


We noted the "Requires" and "BuildRequires" tags earlier.
In addition to Requires and BuildRequires tags, you can also use these for controlling dependencies:
There are a few other tags for controlling dependencies:
* '''Provides''': list virtual package names that this package provides. For example, there might be a package "<code>foo</code>" that demands a particular functionality "bar" from another program. If there are several packages that can satisfy that demand, those packages can specify "<code>Provides: bar</code>" and the "<code>foo</code>" package can specify "<code>Requires: bar</code>". You could also use the [http://dailypackage.fedorabook.com/index.php?/archives/6-Wednesday-Why-The-Alternatives-System.html "alternatives" system], but avoid if multiple users on the same system might want different default, as these settings are system-wide. Use "<code>rpm -q --provides PACKAGENAME</code>" to see what a given package provides. Some examples of virtual packages in Fedora:
Provides, Obsoletes, Conflicts, and BuildConflicts.
** MTA: Used for mail transport agents, such as sendmail.
* "Provides:" lets you list ''virtual'' package names that this package provides. Sometimes there are several different packages that can provide a function, and using packages won't care which one.  In that case, each of the packages that provide the function should "provide" a virtual package, and then using packages can list the virtual package name under "Requires:".  For example, several different packages might provide "latex"; if you depend on the virtual package "tex(latex)", then users can choose which package to get "latex" from. If you provide virtual packages, you might also want to use the [http://dailypackage.fedorabook.com/index.php?/archives/6-Wednesday-Why-The-Alternatives-System.html "alternatives" system], but be careful: "alternatives" settings are ''system-wide'', so if multiple users on the same system might want different defaults, don't use the alternatives system. You can find out what a given package provides (both virtual and non-virtual names) by querying "rpm -q --provides PACKAGENAME". Some virtual packages in Fedora are:
** tex(latex): Used for latex
** ''MTA'' : Used for mail transport agents, such as sendmail.
* '''Obsoletes''': remove another named package(s) when this package is installed. Use when the package name changes or when it totally replaces a different package.
** ''tex(latex)'' : Used for latex
* '''Conflicts''': state what other packages cannot be installed simultaneously to this one. Avoid this if you can. See [[Packaging/Conflicts]].
* "Obsoletes:" lets you state that installing this package should (normally) cause the removal of the other named package(s). This is useful when a package's name changes, or when a package wholly replaces a different package.
* '''BuildConflicts''': state what packages cannot be installed when building this package. Avoid this if you can.
* "Conflicts:" lets you state what packages cannot be installed simultaneously this one. Obviously, try to avoid this if you can; see [[Packaging/Conflicts]] if you think you need to use it.
* "BuildConflicts:" lets you state what packages cannot be installed when building this package. Obviously, try to avoid this if you can.


You can control which architectures a package builds (or doesn't build). For example, if your package can't compile on ppc, you can do this:
To manage different architectures, there are two tags:
* '''ExcludeArch''': to exclude an architecture on which the package doesn't build. For example:
  ExcludeArch: ppc
  ExcludeArch: ppc
There's also an "ExclusiveArch" tag. The valid architectures one can specify in these tags are listed in the [[Architectures]] section.
* '''ExclusiveArch''': to include only the specified architecture. Avoid this unless absolutely correct.
Valid architectures are listed at [[Architectures]].


=== Subpackages ===
=== 子软件包 ===
A spec file can define more than one binary package, e.g., client and server,
or runtime and developer packages.
If there's a large amount of documentation, it may be split into a NAME-doc subpackage.
You will always have one spec file and one source RPM (SRPM), even if there are
multiple binary RPMs that they generate.
A spec file that produces multiple binary packages still has only
one creation process, so there is only one
%prep, %build, %check, and %install section that creates all the files
for all the packages.


In a spec file, use the %package directive to start defining a subpackage:
A SPEC file can define several binary package. In other words, one SRPM with one SPEC file can result in several RPMS. Note that there is still only one creation (%prep, %build, %install etc.) process. <code>name-doc</code> and <code>name-devel</code> subpackages are common for documentation and development files respectively.
%package sub_package_name


By default, the subpackage name is PACKAGE_NAME, "-", SUBPACKAGE_NAME; you can
Use the <code>%package</code> directive to start defining a subpackage:
use "-n" to override this and make a new name:
  %package subpackage_name
  %package -n new_sub_package_name
 
After each <code>%package</code> directive, list the tags for the subpackage. This should at least include the Summary and Group tags, as well as the <code>%description subpackage_name</code> and <code>%files subpackage_name</code> directives:


After the %package directive, list the tags for the subpackage.
This should include at least the "Summary:" and "Group:" tags and directives
"%description SUBPACKAGE_NAME" and "%files SUBPACKAGE_NAME".
Anything not specified by the subpackage will be inherited from its parent.
Anything not specified by the subpackage will be inherited from its parent.
For the directives, if you used "-n" with %package,
 
you'll need it again for these directives.
By default, if the package name is "<code>foo</code>" and the subpackage name is "<code>bar</code>", then the resulting subpackage will be "<code>foo-bar</code>". You can override it with the "<code>-n</code>" option (but you'll need to use it in all other directives too if you specify it here):
You need to specify the name for the other directives, e.g., %pre and %post,
%package -n new_subpackage_name
if you use them in the subpackage.


[http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch10s04.html See the RPM Guide section on subpackages] for more information.
[http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch10s04.html See the RPM Guide section on subpackages] for more information.
Line 721: Line 631:
=== Conditionals ===
=== Conditionals ===


You can insert conditional statements.
You can insert conditional statements, for example to test if you are creating a binary for a certain architecture:
E.G., you can test if you are creating a binary for a certain architecture
with:
  %ifarch ARCHITECTURE_NAME
  %ifarch ARCHITECTURE_NAME
the negated version with:
the negated version with:
Line 730: Line 638:
  %if TRUE_OR_FALSE
  %if TRUE_OR_FALSE


There is an optional "%else" section; all of these are closed with "%endif".
There is an optional "<code>%else</code>" section; all of these are closed with "<code>%endif</code>".


=== Application Specific Guidelines ===
=== Application Specific Guidelines ===
Line 745: Line 653:
* [http://fedoraproject.org/wiki/Special:PrefixIndex/Packaging Wiki pages prefixed with 'Packaging']
* [http://fedoraproject.org/wiki/Special:PrefixIndex/Packaging Wiki pages prefixed with 'Packaging']


=== Miscellaneous hints ===
=== 小提示 ===
 
[[Packaging/FrequentlyMadeMistakes]] has information on frequently-made mistakes. There are also some recommendations and controversial tricks on
[[PackageMaintainers/Packaging Tricks]].


Try to write your scripts so that when upstream makes changes, the packaging is likely to work when you change the version number and reload the source file(s). For example, if it contains *.txt files with execute bits, instead of doing:
Try to write your SPEC files so that it is likely to work when a new release is made upstream, without any changes aside from bumping the version number and refreshing the source files. For example, if it contains *.txt files with execute bits, instead of doing
   chmod a-x Filename1.txt Filename2.txt Filename3.txt
   chmod a-x Filename1.txt Filename2.txt Filename3.txt
consider doing this, which will handle new filenames that use the same file naming convention:
consider doing this, which will handle new filenames that use the same file naming convention:
Line 754: Line 665:
If you want to see lots of examples of scriptlets, you can show all the scriptlets on installed programs using:
If you want to see lots of examples of scriptlets, you can show all the scriptlets on installed programs using:
   rpm -qa --queryformat "\n\nPACKAGE: %{name}\n" --scripts | less
   rpm -qa --queryformat "\n\nPACKAGE: %{name}\n" --scripts | less
[[Packaging/FrequentlyMadeMistakes]] has information on frequently-made mistakes.


Don't try to interact with the user; RPM is designed to support batch installs.  If an application needs to show a EULA, that needs to be part of its initial execution, not its installation.
Don't try to interact with the user; RPM is designed to support batch installs.  If an application needs to show a EULA, that needs to be part of its initial execution, not its installation.


You might not want to start services, because in a big install that could slow things down. If you install an init script, consider using chkconfig to arrange for the service to be started and stopped on the next reboot.  Before ''uninstalling'' you should normally try to stop its services if it's running.
You might not want to start services, because in a big install that could slow things down. If you install an init or systemd script, consider using <code>chkconfig</code> or <code>systemctl</code> to arrange for the service to be started/stopped on the next reboot.  Before uninstalling, you should normally try to stop its services if they are running.


Uninstall should reverse most changes made during installation, but don't remove any user-created files.
Uninstalling should reverse most changes made during installation, but don't remove any user-created files.


Normally, if there are binary executables, a separate "debug" package is created with the symbols, and the symbols are stripped from the normal binary packages. If this shouldn't happen, you can disable the package-creation and stripping with:
Normally, if there are binary executables, then debugging symbols are stripped from the normal binary packages and placed into a <code>name-debug</code> subpackage. If this shouldn't happen, you can disable the stripping and creation of this subpackage by putting this at the top of your SPEC:
  %global _enable_debug_package 0
  %global _enable_debug_package 0
  %global debug_package %{nil}
  %global debug_package %{nil}
  %global __os_install_post /usr/lib/rpm/brp-compress %{nil}
  %global __os_install_post /usr/lib/rpm/brp-compress %{nil}


To prevent stripping you may also need to do this in the %install section:
To prevent stripping you may also need to do this in the <code>%install</code> section:
  export DONT_STRIP=1
  export DONT_STRIP=1


A way to check for the version of Fedora in a spec file for conditional builds is:
A way to check for the version of Fedora in a SPEC file for conditional builds is:
  %if 0%{?fedora} <= <version>
  %if 0%{?fedora} <= <version>
(The ? causes the macro to evaluate to blank if %fedora is not defined, and this causes the end result to be "0", which is a number and thus ok, while not interfering with the result if there is actually a value for %fedora.)
The <code>?</code> causes the macro to evaluate to evaluate to blank if <code>%fedora</code> is not defined. This causes the end result to be the <code>0</code> (which is a number and thus fine), while not interfering with the result if there is actually a value for <code>%fedora</code>. (Note that this trick does not work in Koji "scratch" builds, where <code>%fedora</code> is set during the creation of a SRPM.)
 
Note that the previous trick DOES NOT work in Koji "scratch" builds - %fedora is set during the creation of a source RPM. (Thus, this trick does work in actual Koji builds as the system extracts sources from the source RPM and rebuilds the source RPM with the appropriate %fedora value.)
 
There are also some recommendations and controversial tricks on
[[PackageMaintainers/Packaging Tricks]].


GUI programs ''must'' have a desktop entry (so that people can invoke it from a graphical menu). The
GUI programs must have a desktop entry so that people can invoke it from the graphical desktop menu. For <code>.desktop</code> files, see [[Packaging/Guidelines#Desktop_files|Fedora packaging guidelines for desktop files]] and [http://standards.freedesktop.org/desktop-entry-spec/latest/ desktop entry spec]. For icons within <code>/usr/share/icons</code>, see [http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html icon theme spec].
[http://fedoraproject.org/wiki/Packaging/Guidelines#Desktop_files Fedora packaging guidelines discuss desktop files].  See also the [http://standards.freedesktop.org/desktop-entry-spec/latest/ desktop entry spec] (for .desktop files) and
[http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html icon theme spec] (for icon-related materials such as those in /usr/share/icon).


=== Older RPM documents ===
== 构建 ==
Some older documents about RPM have the most information, but some older documents make claims that are no longer true:
* rpm files are no longer placed in a shared /usr/src/redhat directory.  This is an obsolete way of using rpm and ''not'' recommended; modern systems set a %{_topdir} instead like ~/rpmbuild.
* the %install process does not install files in their final location.  Instead, it "installs" files to the buildroot.
* The "rpm" command no longer creates packages (e.g., "rpm -ba" was once legal). Use the separate "rpmbuild" program instead.
* Many historical specs use the "%define" command to define macros.  However, "%define" creates a locally defined submacro within other macro definitions; this is very rarely needed, and using %define incorrectly can cause subtle bugs.  For nearly all uses, use "%global" instead.  (See [[PackagingDrafts/global_preferred_over_define]].)
* The "BuildRoot:" value is now ignored.


== Quick test with rpmlint ==
=== 使用 rpmlint 测试 ===


Before trying to build anything from it, you should run ''rpmlint'' on the spec file:
请先使用 <code>rpmlint</code> 查找 SPEC 文件的错误:
  rpmlint program.spec
  $ rpmlint program.spec
This will catch many errors early. If the reported error doesn't make sense,
如果没什么异常,使用 "<code>-i</code>" 参数查看长输出。
run it again with the "-i" option (this gives longer messages).


Generally, you should not have errors from rpmlint, but sometimes
某些情况下 <code>rpmlint</code> 的报错不一定代表有问题,请查看 [[Packaging/Guidelines#Use_rpmlint|打包规定]]
rpmlint is excessively noisy.
了解具体有哪些。
The
[http://fedoraproject.org/wiki/Packaging/Guidelines#Use_rpmlint Fedora packaging guidelines]
explain which ones to ignore, e.g., ignore "no-packager-tag" and "no-signature" errors.


== Creating RPMs from the spec file ==
=== 从 SPEC 构建 RPM ===


Once you've create a spec file, say "program.spec", you can create
一旦 SPEC 编写完毕,请通过 rpmbuild 来构建:
source and binary RPMs by simply running this:
$ rpmbuild -ba program.spec
  $ rpmbuild -ba program.spec


If this works, then your binary RPM files will be created underneath ~/rpmbuild/RPMS/ and the source RPM will be in ~/rpmbuild/SRPMS.
成功的话,RPM 会保存至 <code>~/rpmbuild/RPMS</code>,SRPM 会保存至 <code>~/rpmbuild/SRPMS</code>。


When things go wrong, you can "cd" into the appropriate directory and see what's left over.
If it fails, go to the appropriate directory and see what is left over. To help debug, you can skip earlier stages that succeeded with the "<code>--short-circuit</code> option. For example, to restart at the <code>%install</code> stage (skipping earlier stages), do this:
If you want to skip earlier stages, use the "--short-circuit" option; this is handy if you had a successful build, but have an error in the %install section. For example, to restart at the %install stage (skipping earlier stages), do this:
$ rpmbuild -bi --short-circuit program.spec
  $ rpmbuild -bi --short-circuit program.spec


If you just want to create a source RPM (.src.rpm), do this in the SPECS directory:
如果只想创建 SRPM(也就是不需要执行 <code>%prep</code> 或 <code>%build</code> 或其他阶段),请运行:
  rpmbuild -bs program.spec
  rpmbuild -bs program.spec
This will create the source RPM in ~/rpmbuild/SRPMS.  Creating ''only'' a source rpm (.src.rpm) is quite quick, because rpm simply needs to copy the .spec file and associated SOURCES files into a .src.rpm file.  Creating a binary rpm typically takes ''much'' longer, because this requires running the %prep, %build, and %install scripts.


== Testing RPMs you've built (including rpmlint) ==
=== 使用 rpmlint 测试已构建的 RPM ===


Run rpmlint on the .spec files, generated ''binary'' RPM, and generated source RPM. Rpmlint works on .spec files, binary RPMs, and source RPMs, finding different things in each.  You need to eliminate or justify rpmlint warnings before posting a package. If you are in the SPECS directory, do this:
<code>rpmlint</code> 可用于检查 SPEC/RPM/SRPM 的错误。You need to eliminate or justify warnings before posting a package. If you are in the SPECS directory, do this:
  $ rpmlint ''NAME''.spec ../RPMS/*/''NAME''*.rpm ../SRPMS/''NAME''*.rpm
  $ rpmlint ''NAME''.spec ../RPMS/*/''NAME''*.rpm ../SRPMS/''NAME''*.rpm


Normally rpmbuild will build a binary RPM with debugging information - this will handle that.
进入 <code>~/rpmbuild/RPMS</code> 目录下的特定架构目录,您会发现有许多二进制 RPM 包。Quickly see their files and permissions (to check whether they are correct) by doing:
$ rpmls *.rpm


If you "cd" to the "~/rpmbuild/RPMS" directory, and then cd to the architecture subdirectory,
如果看上去正常,以 root 权限安装它们:
you'll find some binary rpms. You can quickly see their files and their permissions by using rpmls
# rpm -ivp package1.rpm package2.rpm package3.rpm ...
(check to see that they are what you expect):
$ rpmls *.rpm


If those look okay, you can become root and try to install them:
Test the programs in a few different ways to see if everything works correctly. If it is a GUI tool, make sure it shows up in the desktop menu, otherwise the <code>.desktop</code> entry is wrong.
# rpm -ivp XYZ1.rpm XYZ2.rpm XYZ3.rpm ...


Then, you can test them out. Use it a few different ways and see if it works correctly.  If it's a GUI tool, make sure it shows up in the menu (if it doesn't, something is wrong with your .desktop entry).
最后删除:
  # rpm -e package1 package2 package3


You can uninstall packages later using:
== Mock 和 Koji ==
# rpm -e XYZ1 XYZ2 XYZ3


If that works, you can use Mock to do a more rigorous test that you have accurate build dependencies.  Basically, mock will create a nearly-empty environment and try to rebuild the package; if it fails, then you forgot to list something in a "BuildRequires:" statement. See [[Using Mock to test package builds]] for more information about how to use Mock; once your account is a member of the "mock" group, you can run commands like this to do local testing:
[[Projects/Mock|Mock]] is a powerful tool that uses the SRPM you have created to build binary packages within a nearly empty environment. This can reveal if you have accurate build dependencies. If it fails, then you forgot to list something in BuildRequires. See [[Using Mock to test package builds]]. Once your account is a member of the "<code>mock</code>" group, you can run commands like this to do local testing:
  $ mock -r fedora-9-i386 rebuild path_to_source_RPM
  $ mock -r fedora-9-i386 rebuild path_to_source_RPM


If a mock build fails, or the resulting program doesn't work correctly, then you almost certainly have one or more missing BuildRequires packages.
You can use Koji (which uses <code>mock</code>) to do builds on many different systems, some of which you may not have. [[PackageMaintainers/Join]] and [[PackageMaintainers/UsingKoji]] have more information about Koji. Once it's set up, you can test your SRPM on a variety of platforms by running commands like:
 
Once Mock works on your system, you can use Koji (which uses Mock) to do builds on
many different systems, some of which you may not have.
[[PackageMaintainers/Join]] and [[PackageMaintainers/UsingKoji]] have more information about Koji.
Once it's set up, you can test your source RPM
on a variety of platforms by running commands like:
  $ koji build --scratch dist-f9 path_to_source_RPM
  $ koji build --scratch dist-f9 path_to_source_RPM


You can replace dist-f9 with dist-f8, dist-f10, etc., to try other releases. Don't use "dist-rawhide", that's not really rawhide. Remember, the values of %fedora, %fc9, etc., will not be correct for a scratch build, so this won't work if your spec file does something different based on those values.
Replace <code>dist-f9</code> with any later release of Fedora, but don't use <code>dist-rawhide</code>. Remember, the values of <code>%fedora</code>, <code>%fc9</code> and so on will not be correct for a scratch build, so this won't work if your SPEC file does something different based on those values.


Your koji builds can only depend on packages that are actually in the TARGET distribution repository.  Thus, you can't use koji to build for released distributions if your package depends on other new packages that Bodhi hasn't released yet. You ''can'' use koji to build for rawhide (the next unreleased version), even if it depends on other new packages, as long as the other packages were built in the CVS "devel" section as described below.
Your Koji builds can only depend on packages that are actually in the TARGET distribution repository.  Thus, you can't use Koji to build for released distributions if your package depends on other new packages that Bodhi hasn't released yet. If you need to build against a package that is not yet a stable released update, you can file a ticket with rel-eng at: https://fedorahosted.org/rel-eng/newticket and request that that package be added as a buildroot override.
If you need to build against a package that is not yet a stable released update, you can file a ticket with rel-eng at: https://fedorahosted.org/rel-eng/newticket and request that that package be added as a buildroot override.


== Helpful tools ==
== 有帮助的工具 ==


The "rpmdevtools" package has a number of helpful tools; "rpm -qil rpmdevtools" will show you what it installs.
<code>rpmdevtools</code> 软件包包含大量有用的工具;"<code>rpm -qil rpmdevtools</code>" 将会显示所有可用命令。
One particularly useful tool is rpmdev-bumpspec, which has this form:
* <code>rpmdev-bumpspec</code> : bump the release tag in the spec file and add a changelog comment with the right date and version 格式:
  rpmdev-bumpspec --comment=COMMENT --userstring=NAME+EMAIL_STRING SPECFILES
  rpmdev-bumpspec --comment=COMMENT --userstring=NAME+EMAIL_STRING SPECFILES
rpmdev-bumpspec will bump the release tag in the spec file(s), and add a changelog comment with the right datetime and version format.  COMMENT should typically start with "- ".


Similarly, "yum-utils" has a number of yum-specific tools.  "yumdownloader" is especially helpful; you can download the source RPM of a package by simply running "yumdownloader --source PACKAGENAME".  You can then use "rpm -U SOURCEPACKAGENAME" to install the source filesE.G., "yumdownloader --source glib; rpm -Uvh glib*.src.rpm".
The <code>yum-utils</code> package also has some useful tools:
* <code>yumdownloader</code> : download the SRPM of the package by running:
yumdownloader --source PACKAGENAME
 
The <code>auto-buildrequires</code> package has a pair of nice tools for helping to figure out the proper BuildRequires entriesAfter installing this package, replace "<code>rpmbuild</code>" with "<code>auto-br-rpmbuild</code>" and you'll see an automatically generated BuildRequires list.


The auto-buildrequires package has a pair of nice tools for helping to figure out the proper BuildRequires entries. After installing this package, replace "rpmbuild" with "auto-br-rpmbuild" and you'll see an automatically-generated buildrequires list.
You might find [http://rust.sourceforge.net/ RUST] useful (GPL), though it does not create SPEC files of suitable quality for Fedora packages. [http://kitenet.net/~joey/code/alien/ Alien] converts between package formats. It won't produce clean SRPMS, but converting an existing package might provide helpful information.


You might find [http://rust.sourceforge.net/ RUST] useful (GPL).
== 相关规定 ==
It is "a drag &amp; drop RPM creation GUI and a 'sandboxing' toolkit that allows you to do software installations within a chrooted environment and automatically generate RPMs from arbitrary source code, without ever seeing a spec file."
If you're creating spec files, it can help you determine the %files.
Note, however, that it does not create .spec files, nor does it create packages of adequate quality for the Fedora repository; it is primarily a tool for making quick-and-dirty binary RPM packages.
(Note: it is no longer at "rusthq.com".)


[http://kitenet.net/~joey/code/alien/ Alien] converts between package formats.
在您创建软件包的时候,请遵守下列规定:
It won't produce clean source RPMs, but converting an existing package
* [[Join the package collection maintainers|如何成为 Fedora 软件包仓库维护人员]] - 描述成为 packager 的流程。
might provide helpful information.
* [[Packaging:Guidelines |打包规定]]
* [[Packaging:NamingGuidelines|软件包命名规定]]
* [[Packaging:LicensingGuidelines|软件包许可协议规定]]
* [[Packaging:DistTag|Dist 标签使用指南]]
* [[Packaging:ReviewGuidelines|软件包审核规定]]


== Guidelines and rules ==
这里也有许多针对特殊环境打包的规定(Java 程序,OCaml 程序,GNOME 程序等等);您也可以从 [[SIGs]] 获取许多有价值的帮助。[[:Category:Package Maintainers|软件包维护人员]] 分类是所有部分的总结页面。


When you create your packages, you'll need to follow the following rules and guidelines:
[https://fedoraproject.org/wiki/Special:Prefixindex/Packaging 这里还有一份所有有关打包的页面列表]
* [[Join the package collection maintainers| How to join the Fedora Package Collection Maintainers]] - describes the process for becoming a Fedora package maintainer
* [[Packaging:Guidelines | Packaging Guidelines]]
* [[Packaging:NamingGuidelines| Package Naming Guidelines]]
* [[Packaging:DistTag| Dist Tag Guidelines]]
* [[Packaging:ReviewGuidelines| Package Review Guidelines]]


There are many official guidelines that will help you with specific circumstances
除了这些,还有许多非官方的指南帮助,比如
(Java programs, OCaml programs, GNOME programs, etc.); the
[https://fedoraproject.org/wiki/Special:Search?ns0=1&search=PackagingDrafts%2F&searchx=Search 打包规定草稿][https://fedoraproject.org/wiki/PackagingDrafts 今后需要制定的打包规定]
[[Packaging:Guidelines|Packaging Guidelines]] include cross-references to those guidelines.
You can also learn more from the [[SIGs]] and
[[:Category:Package Maintainers|Package Maintainers]] sections.
[https://fedoraproject.org/wiki/Special:Prefixindex/Packaging You can also see the list of all Wiki pages about Packaging] to see if any apply.


Failing that, you might find some useful recommendations in the unofficial
还有其它地方也可供参考,比如 [http://en.opensuse.org/Packaging SuSE 的打包规定]
[https://fedoraproject.org/wiki/Special:Search?ns0=1&search=PackagingDrafts%2F&searchx=Search Packaging Drafts] and [https://fedoraproject.org/wiki/PackagingDrafts Packaging Drafts To Do].
[http://www.debian.org/doc/debian-policy/ Debian 的打包规定],但是 [http://www.mail-archive.com/distributions@lists.freedesktop.org/msg00156.html 每个发行版都有不一样的地方],所以不要直接生搬硬套。
These are unofficial, obviously.
You might find ideas from [http://en.opensuse.org/Packaging SuSE],
[http://www.debian.org/doc/debian-policy/ Debian], but
[http://www.mail-archive.com/distributions@lists.freedesktop.org/msg00156.html distributions differ in their rules], so do not presume they can be used directly.


The .spec files that you create must be open source software, as noted in the
'''请注意所有 spec 文件必须是有关开源的软件,就像[[Legal:Fedora_Project_Contributor_Agreement|FPCA]] 声明所描述的一样。'''
[http://fedoraproject.org/wiki/Legal/Licenses/CLA CLA].


== 维护软件包 ==
== 维护软件包 ==
Line 925: Line 794:


* [http://www.g-loaded.eu/2006/04/05/how-to-build-rpm-packages-on-fedora/ 如何在 Fedora 系统中制作RPM包]——很简单的贯通介绍
* [http://www.g-loaded.eu/2006/04/05/how-to-build-rpm-packages-on-fedora/ 如何在 Fedora 系统中制作RPM包]——很简单的贯通介绍
* 使用 RPM 为软件打包(developerWorks): [http://www.ibm.com/developerworks/library/l-rpm1/ 第一部分], [http://www.ibm.com/developerworks/library/l-rpm2/ 第二部分], and [http://www.ibm.com/developerworks/library/l-rpm3.html 第三部分]
* 使用 RPM 为软件打包(developerWorks): [http://www.ibm.com/developerworks/library/l-rpm1/ 第一章], [http://www.ibm.com/developerworks/library/l-rpm2/ 第二章], and [http://www.ibm.com/developerworks/library/l-rpm3 第三章]
* Fedora Classroom had a IRC session on packaging and you can refer to the logs at https://fedoraproject.org/wiki/Building_RPM_packages_%2820090405%29
* Fedora Classroom had a IRC session on packaging and you can refer to the logs at https://fedoraproject.org/wiki/Building_RPM_packages_%2820090405%29
* [http://koti.welho.com/vskytta/packagers-handbook/packagers-handbook.html Fedora 打包者手册]
* [http://koti.welho.com/vskytta/packagers-handbook/packagers-handbook.html Fedora 打包者手册]
* [http://www.redhatmagazine.com/2008/02/28/when-sally-met-eddie-the-fedora-package-story/ 当 Sally 遇见 Eddie]——一个较详细的 RPM 故事
* [http://www.redhatmagazine.com/2008/02/28/when-sally-met-eddie-the-fedora-package-story/ 当 Sally 遇见 Eddie]------一个较详细的 RPM 故事
* [http://rpm.org/max-rpm-snapshot/ Maximum RPM Book]——一个内容虽然最丰富,可惜早已过时的 RPM 教程 (由 Red Hat 公司撰写)
* [http://rpm.org/max-rpm-snapshot/ Maximum RPM Book]——一个内容虽然最丰富,可惜早已过时的 RPM 教程 (由 Red Hat 公司撰写)
* [http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM 指南创建 RPM 部分]——虽然只是一份草稿,但是内容很新
* [http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM 指南创建 RPM 部分]——虽然只是一份草稿,但是内容很新
Line 936: Line 805:
* [http://genetikayos.com/code/repos/rpm-tutorial/trunk/rpm-tutorial.html RPM Tutorial (Fullhart)]
* [http://genetikayos.com/code/repos/rpm-tutorial/trunk/rpm-tutorial.html RPM Tutorial (Fullhart)]
* [http://www-uxsup.csx.cam.ac.uk/talks/rpmbuild/rpmbuild.pdf Cambridge RPM tutorial] is a presentation on creating basic RPMs
* [http://www-uxsup.csx.cam.ac.uk/talks/rpmbuild/rpmbuild.pdf Cambridge RPM tutorial] is a presentation on creating basic RPMs
* [http://en.tldp.org/HOWTO/RPM-HOWTO/index.html RPM HOWTO: RPM at Idle by Donnie Barnes]
* [http://en.tldp.org/HOWTO/RPM-HOWTO/index.html Donnie Barnes 撰写的 RPM 指南]
* [http://home.fnal.gov/~dawson/rpms/howto/index.html RPM HowTo] by Dawson
* [http://home.fnal.gov/~dawson/rpms/howto/index.html 由 DawsonRPM 撰写的 RPM 指南]
* [http://en.opensuse.org/SUSE_Build_Tutorial SuSE 构建向导]SuSE 系统的 RPM打包教程,不是针对 Fedora的;[http://en.opensuse.org/Build_Service/cross_distribution_package_how_to Cross-distribution package HOWTO] 倒是有很多针对不同发行版制作 RPM 包的指导。
* [http://en.opensuse.org/SUSE_Build_Tutorial SuSE 构建向导]SuSE 系统的 RPM 打包教程,不是针对 Fedora 的但是可以参考;[http://en.opensuse.org/Build_Service/cross_distribution_package_how_to Cross-distribution package HOWTO] 倒是有很多针对不同发行版制作 RPM 包的指导。
* [http://wiki.mandriva.com/en/Development/Howto/RPM Mandriva RPM 指南] ([http://www.mandrivaclub.com/xwiki/bin/view/KB/MandrivaRpmHowTo alt]) Mandriva 系统的 RPM 打包指南。注意: 在 Fedora 中, ''万万不可''重新压缩软件源代码,正如 Mandriva 官方提示,这样会导致软件无法完成自身校验。
* [http://wiki.mandriva.com/en/Development/Howto/RPM Mandriva RPM 指南] ([http://www.mandrivaclub.com/xwiki/bin/view/KB/MandrivaRpmHowTo alt]) Mandriva 系统的 RPM 打包指南。注意: 在 Fedora 中, ''万万不可''重新压缩软件源代码,正如 Mandriva 官方提示,这样会导致软件无法完成自身校验。
* [http://linuxshellaccount.blogspot.com/2008/03/creating-your-own-linux-rpms-initial.html Creating Your Own Linux RPM's - The Initial Software Build] is another brief intro, but it makes the point that "The process of building RPM's is much simpler than creating packages for Solaris... Fewer steps, and the ability to add all of your software information into one specification file, makes for a much tighter (and easier to modify or reproduce) software packaging system."
* [http://linuxshellaccount.blogspot.com/2008/03/creating-your-own-linux-rpms-initial.html Creating Your Own Linux RPM's - The Initial Software Build] is another brief intro, but it makes the point that "The process of building RPM's is much simpler than creating packages for Solaris... Fewer steps, and the ability to add all of your software information into one specification file, makes for a much tighter (and easier to modify or reproduce) software packaging system."
* [http://fedoranews.org/alex/tutorial/rpm/ All you need to know about RPM] (more about installing packages than creating them)
* [http://fedoranews.org/alex/tutorial/rpm/ All you need to know about RPM] (more about installing packages than creating them)
* The [http://wiki.rpm.org/ rpm.org Wiki]一样含有大量有用的信息,比如[http://wiki.rpm.org/Problems 已知的一些有关 RPM 机制的问题]
* [http://wiki.rpm.org/ rpm.org的维基页面] 也含有大量对您有用的信息,比如 [http://wiki.rpm.org/Problems 已知的一些有关 RPM 机制的问题]


注意: [http://rpm5.org/ rpm5.org] 也有一些文档,但是请不要过度依赖它们。这个网站只是由 Jeff Johnson 维护的一个5.x分支 RPM 官网。事实上RPM 5.x 版本并不适用于 Fedora 系统!和 Novell/SuSE一样,Fedora采用的版本基于 [http://www.rpm.org rpm.org]
注意: [http://rpm5.org/ rpm5.org] 也有一些文档,但是请不要过度依赖这个网站的内容。这个网站是由 Jeff Johnson 维护的一个 RPM 5.x 版本的网站。事实上RPM 5.x 版本并不适用于 Fedora 系统!和 Novell/SuSE 系统一样,Fedora 采用的 RPM 安装器基于 [http://www.rpm.org rpm.org] 维护的版本。
[http://lwn.net/Articles/236029/ lwn.net 有一个关于这两者的简短区别介绍]
[http://lwn.net/Articles/236029/ lwn.net] 有一个关于这两者的简短区别介绍。


[[Category:Package Maintainers]]
[[Category:Package Maintainers]]
[[Category:How to]]
[[Category:How to]]

Revision as of 04:16, 24 May 2013

关于本指南

Idea.png
此页正在翻译,翻译: Christopher 'Cicku' Meng
此页正进行由英语向中文的翻译,已完成 45%。由于源文档更新错乱,中间中文翻译有大量过时翻译,请他人暂时不要翻译本页! 您所看到的可能不是最终页面,请定期访问本页面以取得最新更新,如有发现问题请通知 Cicku

本指南讲述了如何为 Fedora 制作 RPM 包,特别是如何写 .spec 配置文件。不像其它文档,本文档会解释 Fedora 中特殊领域的打包(会有链接指向 Fedora 的特殊打包规定)。并且由于本文档通过 wiki 更新,因此会尽可能的保持最新。除了 Fedora,绝大部分内容也会适用其他基于 RPM 机制的发行版。如果您等不及了,您可以先看看如何创建一个 GNU Hello World 软件包,这是一个创建 RPM 包的简短总结(但是没有很详细的信息)。

目前 Fedora 文档团队有一份草稿已经发布:

Packager 指南

注意,本指南并不是 Fedora 官方的打包规定打包委员会 制定的 Fedora 所有打包规定如下:

打包规定软件包命名规定 是主要的两份规定,本指南与这两份规定100%兼容。

如果您计划为 Fedora 的官方源创建一个 RPM 包,请按照 如何成为 Fedora 软件包仓库维护人员 页面的步骤一步步来。

前期准备

在您为 Fedora 创建 RPM 包之前,您需要安装一些必须的开发组件并且设置好即将使用的账户:

 # yum install @development-tools
 # yum install fedora-packager

您可以新建一个临时用户以便创建 RPM 包。这样,如果有错误发生,构建程序不会破坏您的系统,比如造成文件损失或者您的私人文件/密钥被发送到互联网上。

Stop (medium size).png
切记!不要使用 root 用户来执行打包操作,因为这很危险,所有二进制文件都会在被打包前安装至系统中,因此您应该以普通用户身份打包以杜绝系统被破坏。

新建一个叫做makerpm的用户,添加至 'mock' 用户组,设置好密码并通过该用户登录:

 # /usr/sbin/useradd makerpm
 # usermod -a -G mock makerpm
 # passwd makerpm

然后您可以通过这个临时用户开始执行打包操作。

一旦登录了 makerpm 用户,您可以使用一下命令在这个用户的家目录下创建一个标准的打包工作目录结构:

 $ rpmdev-setuptree

rpmdev-setuptree 程序新建一个位置是 ~/rpmbuild 的目录。在 "rpmbuild" 目录下是一些预设好的子目录(比如 SPECSBUILD),它们将会在创建软件包的时候起作用。 rpmdev-setuptree 也会创建一个位置是 ~/.rpmmacros 的文件。它是一个保存有关设置的文件。

打包指南推荐使用命令保存时间戳;当然,您在使用 wget 或者 curl 获取软件源代码的时候就会自动保存。 如果您使用 wget 来获取源代码,确保在 ~/.wgetrc 文件加入一行 timestamping = on 。类似的,如果您使用 curl ,确保 ~/.curlrc 文件包含 "-R"。

一旦设置完毕,通常不需要再次设置。

RPM 基础知识

若要构建一个标准的 RPM 包,您需要新建一个叫做 .spec 的文本文档,里面包含被打包软件的全部信息。然后您对这个文本文档在系统中执行 rpmbuild 命令,经过这一步,系统会按照步骤生成最终的 RPM 包。

按理说您应该把源代码包,比如从软件开发者释放出的那种以 .tar.gz 结尾的文件, 放入 ~/rpmbuild/SOURCES 目录下。您应该把 .spec 文件放入 ~/rpmbuild/SPECS 目录下,并且把它命名为 "软件包名字.spec" 。当然, 软件包名字 就是最终 RPM 包的名字。为了创建所有软件包(包括预编译好的包(Binary RPM)和源代码包(SRPM)),您需要把终端切换至 ~/rpmbuild/SPECS 目录然后执行:

 $ rpmbuild -ba NAME.spec

当您执行这一条命令时,rpmbuild 会自动读取 .spec 文件并尝试按照其中所设定的步骤完成构建。(以下表格中,以 % 开头的短语都是宏,每一个宏起到的作用已经详细列出):

阶段 读取的目录 写入的目录 具体动作
%prep %_sourcedir %_builddir 本步读取位于 %_sourcedir 目录的源代码和 patch 。随后会解压源代码至 %_builddir 下的子目录并应用所有 patch。
%build %_builddir %_builddir 本步编译位于 %_builddir 构建目录下的全部文件。本步类似于 "./configure && make" 命令。
%check %_builddir %_builddir 本步检查软件是否正常运行。本步类似于 "make test" 命令。不过很多软件包都不需要这步。
%install %_builddir %_buildrootdir 本步读取位于 %_builddir 构建目录下的文件并把它们写入至 %_buildrootdir 最终安装目录。这些文件就是用户安装 RPM 后最终得到的文件。请注意一个奇怪的地方: 最终安装目录 不是 构建目录 !本步类似于 "make install" 命令。
bin %_buildrootdir %_rpmdir 本步读取位于 %_buildrootdir 最终安装目录下的文件,以便最终在 %_rpmdir 目录下创建 RPM 包。在该目录下,针对不同架构制作的 RPM 包会分子目录放置,同时一个叫做 "noarch" 的目录放置针对所有架构均适用的 RPM 包。所有 RPM 就是用户最终安装的 RPM 包。
src %_sourcedir %_srcrpmdir 本步创建源代码 RPM 包(简称 SRPM,通常以.src.rpm作为后缀名)。然后这些 SRPM 会被放在 %_srcrpmdir 目录下。SRPM 包通常被用于审核和升级软件包。


rpmbuild 中对上面表格中的每个宏代码有相应的目录对应:

宏代码 名称 默认位置 用途
%_specdir Spec 文件目录 ~/rpmbuild/SPECS RPM 包配置(.spec) 文件存放的目录
%_sourcedir 源代码目录 ~/rpmbuild/SOURCES 存放源代码包(比如 .tar包) 和所有 patch 的目录
%_builddir 构建目录 ~/rpmbuild/BUILD 源代码被解压,并在该目录下的子目录下被编译
%_buildrootdir 最终安装目录 ~/rpmbuild/BUILDROOT %install 阶段最终安装的文件
%_rpmdir 标准 RPM 包目录 ~/rpmbuild/RPMS 二进制 RPM 包在这里生成并存放。
%_srcrpmdir 源代码 RPM 包目录 ~/rpmbuild/SRPMS 源代码 RPM 包(SRPM)在这里生成并存放。

如果某一阶段失败,请查看输出以了解失败的 原因,然后请按照问题修改 .spec 文件。

做好准备打包一个特殊程序

如果这里有特殊的程序,它们需要被安装或者运行以便让您打包的普通程序正常工作,那么请先安装它们,然后记录下诸如软件包等相关信息。

如果想为 Fedora 源打包一个程序,您必须使用源代码来打包,且包含 patch 以及打包简介。不可以使用预编译好的代码来进行打包。将源代码(通常是一个 .tar.gz 文件) 放入"~/rpmbuild/SOURCES" 目录(注意用户)。

仔细阅读该软件的安装说明。我们建议您先手工安装一次以了解具体情况。除了少许例外,所有程序的二进制文件和程序库都必须来源于源代码且基于其构建。

分离程序

程序源代码通常会随着发布而被发布,但是其中也会掺杂着许多其它外部组件。请不要将外部组件跟随主程序一起打包,相反您需要对每个组件单独打包。

许可协议

您只许打包允许您打包的软件。请查看 Packaging:Guidelines#LegalLicensing:MainPackaging:LicensingGuidelines。 通常情况下,您只可以打包使用开源许可证(比如GNU GPL、GNU LGPL、BSD-new、MIT/X或者Apache 2.0 许可证)发放的开源软件(OSS)。 请仔细检查许可证是否名副其实,同时软件整体是否均基于开源协议发放。(比如抽查源代码开头的注释、README 文件等等)。 如果软件有外部组件被捆绑,请确保这些组件也是开源软件。这步十分重要。

使用已有的信息

尽可能利用一切已有的信息!很明显,请您不要打包一些已经存在于源里面的程序!为了防止您犯这种错误,请查阅 Fedora 软件包数据库。同时建议查阅 正在被审核的软件包已停止使用的软件包列表。 如果以上都没有即将被您打包的程序的信息,请使用 Google 以 "您想打包的程序名 Fedora rpm" 或者类似的关键字进行搜索,您可以直接访问 Fedora 软件仓库 Git 源 来查看已存在于 Fedora 源中的 .spec 文件(以及 patch)。您还可以通过 yum-utils 工具包的一个工具,yumdownloader,来获取源代码 RPM 包(SRPM):

$ yum -y install yum-utils
$ yumdownloader --source 您想要获得的源代码包的名字

或者您可以通过浏览 Fedora 镜像列表 的 HTTP 或者 FTP 页面以获取 SRPM 包。在 releases/40/Everything/source/SRPMS 目录内 (请把"40"换成您想要的 Fedora 版本),然后下载即可。通常源代码包以 .src.rpm 为后缀名。

一旦有了源代码包,请按照下面的步骤安装到 ~/rpmbuild 目录下:

$ rpm -ivh 源代码包名字.src.rpm

您也可以使用 rpm2cpio 把源代码包解压到任意目录:

$ mkdir 源代码包名字_src_rpm
$ cd 源代码包名字E_src_rpm
$ rpm2cpio ../源代码包名字.src.rpm | cpio -i

使用这些已经存在的信息有助于您更快打包。RPM FindPKGS.org 将帮助您找到针对非 Fedora 的 RPM 包。您可以尝试安装它们。如果失败,请查看相应的源代码包(不是 .deb) 结尾的 UbuntuDebian软件包(源代码包通常是标准的 tar 文件比并且内部包含一个叫做 "debian/" 的子目录)。如果您在 FreeBSD ports 仓库 找到想要的文件, 请下载 ports 的源代码包 并查看是否包含相关信息。有些时候这些操作没什么实际帮助,因为不同的系统有不同的规定。

新建一个 .spec 文件

现在您需要新建一个 ".spec" 文件,并让它位于 ~/rpmbuild/SPECS 目录下。您应该把它命名为 "程序名.spec"。程序名根据原始软件包命名或通用命名来填写即可。但是,软件包命名规定 是您必须要遵守的。

模板和实例

模板

如果您第一次新建 .spec 文件,vim 或 emacs 会自动生成好一个模板:

 $ cd ~/rpmbuild/SPECS
 $ vim 程序名.spec

示例(仅为参考):

Name:		
Version:	
Release:	1%{?dist}
Summary:	
Group:		
License:	
URL:		
Source0:	
BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

BuildRequires:	
Requires:	

%description

%prep
%setup -q

%build
%configure
make %{?_smp_mflags}

%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
%doc

%changelog


您可以使用 $RPM_BUILD_ROOT 替代 %{buildroot}。两者都可以。

您也可以使用 rpmdev-newspec 命令来创建新的 SPEC 文件。rpmdev-newspec 软件包名 可以创建一个初始的 SPEC 文件,该工具会从软件包名来判断何种模板适合您,您也可以自行指定。请看 /etc/rpmdevtools/spectemplate-*.spec 来找可用的模板,也可以通过 rpmdev-newspec --help 命令来了解。比如您创建一个 python 模块:

cd ~/rpmbuild/SPECS
rpmdev-newspec python-antigravity
vi python-antigravity.spec

实例

eject

这是 Fedora 16 的 eject 的 spec 文件:

Summary:            A program that ejects removable media using software control
Name:               eject
Version:            2.1.5
Release:            21%{?dist}
License:            GPLv2+
Group:              System Environment/Base
Source:             %{name}-%{version}.tar.gz
Patch1:             eject-2.1.1-verbose.patch
Patch2:             eject-timeout.patch
Patch3:             eject-2.1.5-opendevice.patch
Patch4:             eject-2.1.5-spaces.patch
Patch5:             eject-2.1.5-lock.patch
Patch6:             eject-2.1.5-umount.patch
URL:                http://www.pobox.com/~tranter
ExcludeArch:        s390 s390x
BuildRequires:      gettext
BuildRequires:      libtool

%description
The eject program allows the user to eject removable media (typically
CD-ROMs, floppy disks or Iomega Jaz or Zip disks) using software
control. Eject can also control some multi-disk CD changers and even
some devices' auto-eject features.

Install eject if you'd like to eject removable media using software
control.

%prep
%setup -q -n %{name}
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1

%build
%configure
make %{?_smp_mflags}

%install
make DESTDIR=%{buildroot} install

install -m 755 -d %{buildroot}/%{_sbindir}
ln -s ../bin/eject %{buildroot}/%{_sbindir}

%find_lang %{name}

%files -f %{name}.lang
%doc README TODO COPYING ChangeLog
%{_bindir}/*
%{_sbindir}/*
%{_mandir}/man1/*

%changelog
* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.5-21
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild

* Fri Jul 02 2010 Kamil Dudka <kdudka@redhat.com> 2.1.5-20
- handle multi-partition devices with spaces in mount points properly (#608502)

SPEC 文件综述

其他有用的介绍:

您也将需要按照这些规定来做:软件包命名规定打包规定软件包审核规定

Insert comments with a leading "#" character, but avoid macros (beginning with %) that are potentially multiline (as they are expanded first). If commenting out a line, double the percent signs (%%). Also avoid inline comments on the same line as a script command.

主要的标签都在下方介绍。注意 %{name}%{version}%{release} 代表 Name, Version 和 Release 这三个标签,在 SPEC 中修改它们,构建会自动抓去新的内容。

  • Name: 软件包名,应与 SPEC 文件名一致。命名必须符合 软件包命名规定
  • Version: 上游版本号。请查看 版本标签规定。如果包含非数字字符,您可能需要将它们包含在 Release 标签中。如果上有采用日期区分版本号,请考虑这个格式:yy.mm[dd] (例如 2008-05-01 可变为 8.05)。
  • Release: 初始值为 1%{?dist}。每次您制作新的包时,请递增该数字。当上游发布新版本时,请修改 Version 标签并重置 Release 的数字为 1。具体请看打包规定中的 Release 标签部分Dist tag 可能也会帮助您。
  • Summary: 一行简短的软件包介绍。请使用美式英语。请勿在结尾加上句号!
  • Group: 需要在一个一存在的组中,就像 "Applications/Engineering";执行 "less /usr/share/doc/rpm-*/GROUPS" 来查看完整的组列表。使用组 "Documentation" 为所有包含文档的子软件包(例如 kernel-doc)。注意这个标签从 Fedora 17 后已被废除。[文件参考手册] 有介绍
  • License: 必须是开源软件许可证。请不要使用 Copyright 标签来注明许可证。请使用一个标准(例如 "GPLv2+")且清楚的的描述(例如,使用 "GPLv2+" 来注明 GPL version 2 及更高而不是 "GPL" 或 "GPLv2" 这种不准确的描述)。请见 LicensingLicensing Guidelines。如果一个软件包包含多个协议,您可以使用 "and" 和 "or" (例如 "GPLv2 and BSD")来描述。
  • URL: 有关该软件包的详细信息(例如项目主页)。注意:这不是源代码的来源地址,后者是下文将要讲述的 Source0。
  • Source0: 软件源代码原始下载地址。"Source" is synonymous with "Source0". If you give a full URL (and you should), its basename will be used when looking in the SOURCES directory. If possible, embed %{name} and %{version}, so that changes to either will go to the right place. Preserve timestamps when downloading source files. If there is more than one source, name them Source1, Source2 and so on. If you're adding whole new files in addition to the pristine sources, list them as sources after the pristine sources. A copy of each of these sources will be included in any SRPM you create, unless you specifically direct otherwise. See Source URL for more information on special cases (e.g. revision control).
  • Patch0: The name of the first patch to apply to the source code. If you need to patch the files after they've been uncompressed, you should edit the files and save their differences as a "patch" file in your ~/rpmbuild/SOURCES directory. Patches should make only one logical change each, so it's quite possible to have multiple patch files.
  • BuildArch: If you're packaging files that are architecture-independent (e.g. shell scripts, data files), then add "BuildArch: noarch". The architecture for the binary RPM will then be "noarch".
  • BuildRoot: This is where files will be "installed" during the %install process (after the %build process). This is now redundant in Fedora and is only needed for EPEL5. By default, the build root is placed in "%{_topdir}/BUILDROOT/".
  • BuildRequires: A comma-separated list of packages required for building (compiling) the program. This field can be (and is commonly) repeated on multiple lines. These dependencies are not automatically determined, so you need to include everything needed to build the program. Some common packages can be omitted, such as gcc. You can specify a minimum version if necessary (e.g. "ocaml >= 3.08"). If you need the file /EGGS, determine the package that owns it by running "rpm -qf /EGGS". If you need the program EGGS, determine the package that owns it by running "rpm -qf which EGGS". Keep dependencies to a minimum (e.g. use sed instead of perl if you don't really need perl's abilities), but beware that some applications permanently disable functions if the associated dependency is not present; in those cases you may need to include the additional packages. The Package-x-generic-16.pngauto-buildrequires package may be helpful.
  • Requires: A comma-separate list of packages that are required when the program is installed. Note that the BuildRequires tag lists what is required to build the binary RPM, while the Requires tag lists what is required when installing/running the program; a package may be in one list or in both. In many cases, rpmbuild automatically detects dependencies so the Requires tag is not always necessary. However, you may wish to highlight some specific packages as being required, or they may not be automatically detected.
  • %description:一个较长的/多行的软件介绍部分。请使用美式英语。All lines must be 80 characters or less. Blank lines indicate a new paragraph. Some graphical user interface installation programs will reformat paragraphs; lines that start with whitespace will be treated as preformatted text and displayed as is, normally with a fixed-width font. See RPM Guide.
  • %prep: Script commands to "prepare" the program (e.g. to uncompress it) so that it will be ready for building. Typically this is just "%setup -q"; a common variation is "%setup -q -n NAME" if the source file unpacks into NAME. See the %prep section below for more.
  • %build: "构建" 程序并使其接下来能够被安装的命令(例如,编译)。具体请见下文的 %build 部分。
  • %check: "测试" 程序的命令。 This is run between the %build and %install procedures, so place it there if you have this section. Often it simply contains "make test" or "make check". This is separated from %build so that people can skip the self-test if they desire.
  • %install: "安装" 程序的命令。The commands should copy the files from the BUILD directory %{_builddir} into the buildroot directory, %{buildroot}. 具体请见下文的 %install 部分。
  • %clean: "清理" 安装目录的命令。注意这一步目前在 Fedora 中是多余的,仅针对 EPEL。基本上只包含一句:
rm -rf %{buildroot}
  • %files: 将要被安装的文件的列表。具体请见下文的 %files 部分。
  • %changelog: 请按照上面 eject 的例子,使用这个标签列出 RPM 的变更日志。请注意不是软件本身的变更日志。
  • ExcludeArch: 如果该软件包在某些架构上不能被正常编译/构建或工作,请通过该标签列出。
  • You can add sections so that code will run when packages are installed or removed on the real system (as opposed to just running the %install script, which only does a pseudo-install to the build root). These are called "scriptlets", and they are usually used to update the running system with information from the package. See the "Scriptlets" section below for more.

RPM also supports the creation of several packages (called subpackages) from a single SPEC file, such as name-libs and name-devel packages.

Stop (medium size).png
不要使用这些标签
  • Packager
  • Vendor
  • Copyright

Do not create a "relocatable" package; they don't add value in Fedora and make things more complicated.

SPEC 具体含义

%prep 部分

%prep 部分描述了解压缩源代码的方法。一般来讲,其中包含了 "%setup" 和 "%patch" 两个命令。具体请见 Maximum RPM section on %setup and %patch 以了解更多。

%{patches}%{sources} 宏在 RPM 4.4.2 后已经可用。如果您的软件包包含了许多 patch 或 source,那么可以这么做:

for p in %{patches}; do
    ...
done

不过,记住在 RHEL 和其它基于 RPM 机制的发行版中,这是无法识别的。

%prep 部分:%setup 命令

The "%setup" command unpacks a source package. Switches include:

  • -q : Suppress unecessary output. This is commonly used.
  • -n name : If the Source tarball unpacks into a directory whose name is not the RPM name, this switch can be used to specify the correct directory name. For example, if the tarball unpacks into the directory FOO, use "%setup -q -n FOO".
  • -c name : If the Source tarball unpacks into multiple directories instead of a single directory, this switch can be used to create a directory named name and then unpack into it.

There are more %spec options if you are unpacking multiple files, which is primarily useful if you are creating subpackages (see below). The key ones are:

-a number Only unpack the Source directive of the given number after changing directory (e.g. "–a 0" for Source0).
-b number Only unpack the Source directive of the given number before changing directory (e.g. "–b 0" for Source0).
-D Do not delete the directory before unpacking.
-T Disable the automatic unpacking of the archives.

%prep 部分:%patch 命令

"%patch0" 命令用来打补丁“Patch0” (%patch1 打 Patch1 以此类推)。Patches 是修改源代码的最佳方式。The usual "-pNUMBER" option applies, which passes that argument onto the program patch.

Patch file names often look like "telnet-0.17-env.patch", which is the format %{name} - %{version} - REASON.patch" (though sometimes version is omitted). Patch files are typically the result of "diff -u"; if you do this from the subdirectory of ~/rpmbuild/BUILD then you won't have to specify a -p level later.

简单的创建 patch 方法:

cp foo/bar foo/bar.orig
vim foo/bar
diff -u foo/bar.orig foo/bar > ~/rpmbuild/SOURCES/PKGNAME.REASON.patch

If editing many files, one easy method is to copy the whole subdirectory underneath BUILD and then do subdirectory diffs. After you have changed directory to "~rpmbuild/BUILD/NAME", do the following:

cp -pr ./ ../PACKAGENAME.orig/
... many edits ...
diff -u ../PACKAGENAME.orig . > ~/rpmbuild/SOURCES/NAME.REASON.patch

If you edit many files in one patch, you can also copy the original files using some consistent ending such as ".orig" before editing them. Then, you can use "gendiff" (in the rpm-build package) to create a patch with the differences.

Try to ensure that your patch match the context exactly. The default "fuzz" value is "0", requiring matches to be exact. You can work around this by adding "%global _default_patch_fuzz 2" to revert to the value found in older versions of RPM in Fedora, but it is generally recommended to avoid doing this.

As explained in Packaging/PatchUpstreamStatus, all patches should have a comment above them in the SPEC file about their upstream status. This should document the upstream bug/email that includes it (including the date). If it is unique to Fedora, you should mention why it is unique. The Fedora Project tries not to deviate from upstream; see PackageMaintainers/WhyUpstream for the importance of this.

%prep 部分:Unmodified files

Sometimes, one or more of the Source files do not need to be uncompressed. You can "prep" those into the build directory like this (where SOURCE1 refers to the relevant Source file):

cp -p %SOURCE1 .

%build 部分

The "%build" section is sometimes complicated; here you configure and compile/build the files to be installed.

Many programs follow the GNU configure approach (or some variation). By default, they will install to a prefix of "/usr/local", which is reasonable for unpackaged files. However, since you are packaging it, change the prefix to "/usr". Libraries should be installed to either /usr/lib or /usr/lib64 depending on the architecture.

Since GNU configure is so common, the macro "%configure" can be used to automatically invoke the correct options (e.g. change the prefix to /usr). Some variation of this often works:

 %configure
 make %{?_smp_mflags}

To override makefile variables, pass them as parameters to make:

make %{?_smp_mflags} CFLAGS="%{optflags}" BINDIR=%{_bindir}

More more information, see "GNU autoconf, automake, and libtool" and "Open Source Development Tools: An Introduction to Make, Configure, Automake, Autoconf" by Stefan Hundhammer.

Some programs use cmake. See Packaging/cmake.

%check 部分

If self-tests are available, it is generally a good idea to include them. They should be placed in the %check section (which immediately follows the %build section) instead of within the %build section itself, so that they can be easily skipped when necessary.

Often, this section contains:

make test

%install 部分

This section involves script commands to "install" the program, copying the relevant files from %{_builddir} to %{buildroot} (which usually means from ~/rpmbuild/BUILD to ~/rpmbuild/BUILDROOT) and creating directories inside %{buildroot} as necessary.

Some of the terminology can be misleading:

  • The "build directory", also known as %{_builddir} is not the same as the "build root", also known as %{buildroot}. Compilation occurs in the former directory, while files to be packaged are copied from the former to the latter.
  • During the %build section, the current directory will start at %{buildsubdir}, which is the subdirectory within %{_builddir} that was created during %prep stage. This is usually something like ~/rpmbuild/BUILD/%{name}-%{version}.
  • The %install section is not run when the binary RPM package is installed by the end-user, but is only run when creating a package.

Normally, some variation of "make install" is performed here:

%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install

Removal of %{buildroot} is no longer necessary, except for EPEL 5.

Ideally you should use DESTDIR=%{buildroot} if the program supports it, as it redirects file installations to the specified directory and is exactly what we want to happen during the %install section.

If the program does not support DESTDIR (and only if), you can workaround it in one of several (inferior) ways:

  • Patch the makefile so that is supports DESTDIR. Create directories inside DESTDIR where necessary and submit the patch upstream.
  • Use the "%makeinstall" macro. This method might work, but can lead to subtle failures. It expands to something like "make prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ... install", which can result in some programs failing to work properly. Create directories inside %{buildroot} where necessary.
  • Consider using the auto-destdir package. This requires "BuildRequires: auto-destdir", and changing "make install" to "make-redir DESTDIR=%{buildroot} install". This only works well if the installation uses only certain common commands to install files, like cp and install.
  • Perform the installation by hand. This would involve creating the necessary directories under %{buildroot} and copying files from %{_builddir} to %{buildroot}. Be especially careful with updates, which often contain new or changed filenames. An example of this procedure:
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}%{_bindir}/
cp -p mycommand %{buildroot}%{_bindir}/

As noted in Packaging:Guidelines#Timestamps, try to preserve timestamps if the makefile lets you override commands:

make INSTALL="install -p" CP="cp -p" DESTDIR=%{buildroot} install

%files 部分

This section declares which files and directories are owned by the package, and thus which files and directories will be placed into the binary RPM.

%files basics

The %defattr set the default file permissions, and is often found at the start of the %files section. Note that this is no longer necessary unless the permissions need to be altered. The format of this is:

%defattr(<file permissions>, <user>, <group>, <directory permissions>)

The fourth parameter is often omitted. Usually one uses %defattr(-,root,root,-), where "-" uses the default permissions.

You should then list all the files and directories to be owned by the package. Use macros for directory names where possible, which can be viewed at Packaging:RPMMacros (e.g. use %{_bindir}/mycommand instead of /usr/bin/mycommand). If the pattern begins with a "/" (or when expanded from the macro) then it is taken from the %{buildroot} directory. Otherwise, the file is presumed to be in the current directory (e.g. inside %{_builddir}, such as documentation files that you wish to include). If your package only installs a single file /usr/sbin/mycommand, then the %files section can simply be:

%files
%{_sbindir}/mycommand

To make your package less sensitive to upstream changes, declare all files within a directory to be owned by the package with a pattern match:

%{_bindir}/*

To include a single directory:

%{_datadir}/%{name}/

Note that %{_bindir}/* does not claim that this package owns the /usr/bin directory, but only the files contained within. If you list a directory, then you are claiming that the package owns that directory and all files and subdirectories contained within. Thus, do not list %{_bindir} and be careful of directories that may be shared with other packages.

如果满足下列条件,会有错误发生:

  • a pattern match does not match any file or directory
  • a file or directory is listed or matched more than once
  • a file or directory in the %{buildroot} has not been listed

It is also possible to exclude files from a previous match by using the %exclude glob. This can be useful for including almost all of the files included by a different pattern match, but note that it will also fail if it does not match anything.

%files prefixes

You may need to add one or more prefixes to lines in the %files section; seperate them with a space. See Max RPM section on %files directives.

Usually, "%doc" is used to list documentation files within %{_builddir} that were not copied to %{buildroot}. A README and INSTALL file is usually included. They will be placed in the directory /usr/share/doc/%{name}-%{version}, whose ownership does not need to be declared.

Note: If specifying a %doc entry, then you can't copy files into the documentation directory during the %install section. If, for example, you want an "examples" subdirectory within the documentation directory, don't use %doc, but instead create the directories and copy files over manually into %{buildroot}%{_defaultdocdir}/%{name}-%{version} during the %install section. They will be correctly marked as documentation. Make sure you include %{_defaultdocdir}/%{name}-%{version}/ as an entry in the %files section.

Configuration files should be placed in /etc and are normally specified like this (which makes sure user changes aren't overwritten on update):

%config(noreplace) %{_sysconfdir}/foo.conf

If the update uses a non-backwards-compatible configuration format, then specify them like this:

%config %{_sysconfdir}/foo.conf

"%attr(mode, user, group)" can be used for finer control over permissions, where a "-" means use the default:

%attr(0644, root, root) FOO.BAR

If a file is in particular natural language, use %lang to note that:

%lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*

Programs using Locale files should follow the recommended method of handling i18n files:

  • find the filenames in the %install step: %find_lang ${name}
  • add the required build dependencies: BuildRequires: gettext
  • use the found filenames: %files -f ${name}.lang

These prefixes are not valid in Fedora: %license and %readme.

%files and Filesystem Hierarchy Standard (FHS)

You should follow the Filesystem Hierarchy Standard (FHS). Executables go in /usr/bin, global configuration files go in /etc, libraries go into /usr/lib (or /usr/lib64) and so on. There is one exception: executables that should not normally be executed directly by users or administrators should go in a subdirectory of /usr/libexec, which is referred to as %{_libexecdir}/%{name}.

Do not install files into /opt or /usr/local.

Unfortunately, many programs do not follow the FHS by default. In particular, architecture-independent libraries get placed in /usr/lib instead of /usr/share. The former is for architecture-dependent libraries, while the latter is for architecture-independent libraries, which means that systems with different CPU architectures can share /usr/share. There are many exceptions in Fedora (such as Python and Perl), but Fedora applies this rule more strictly than some distributions. rpmlint will generally complain if you put anything other than ELF files into /usr/lib.

%files 示例

Here's a simple example of a %files section:

%files
%doc README LICENSE
%{_bindir}/*
%{_sbindir}/*
%{_datadir}/%{name}/
%config(noreplace) %{_sysconfdir}/*.conf

找出重复内容

You can list any duplicates of two binary packages by doing:

cd ~/rpmbuild/RPMS/ARCH # Substitute "ARCH" for your architecture
rpm -qlp PACKAGE1.*.rpm | sort > ,1
rpm -qlp PACKAGE2.*.rpm | sort > ,2
comm -12 ,1 ,2

Scriptlets

When an end-user installs the RPM, you may want some commands to be run. This can be achieved through scriptlets. See Packaging/ScriptletSnippets.

Scriptlets can be run:

  • before (%pre) or after (%post) a package is installed
  • before (%preun) or after (%postun) a package is uninstalled
  • at the start (%pretrans) or end (%posttrans) of a transaction

For example, every binary RPM package that stores shared library files in any of the dynamic linker's default paths, must call ldconfig in %post and %postun. If the package has multiple subpackages with libraries, each subpackage should also perform the same actions.

%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig

If only running a single command, then the "-p" option runs the adjacent command without invoking the shell. However, for several commands, omit this option and include the shell commands beneath.

If you run any programs within the scriptlets, then you must specify any requirements in the form "Requires(CONTEXT)" (e.g. Requires(post)).

%pre, %post, %preun, and %postun provide the argument $1, which is the number of packages of this name which will be left on the system when the action completes. Don't compare for equality with 2, but instead check if they are greater than or equal to 2. For %pretrans and %posttrans, $1 is always 0.

For example, if the package installs an info manual, then the info manual index must be updated with install-info from the info package. Firstly, there is no guarantee that the info package will be available unless we explicitly declare it as required, and secondly, we don't want to fail completely if install-info fails:

Requires(post): info
Requires(preun): info
...
%post
/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :
%preun
if [ $1 = 0 ] ; then
/sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
fi

There is one other glitch related to installing info manuals. The install-info command will update the info directory, so we should delete the useless empty directory from the %{buildroot} during the %install section:

rm -f %{buildroot}%{_infodir}/dir

Another scriptlet-like abilility are "triggers", which can be run for your package when other packages are installed or uninstalled. See RPM Triggers.

宏通常以 %{string} 的格式出现,下面介绍常见的宏:

名称 通常含义 解释
%{_bindir} /usr/bin 二进制文件存储目录,通常可执行。
%{_builddir} ~/rpmbuild/BUILD 构建目录:构建软件包的目录,具体请见 %buildsubdir
%{buildroot} ~/rpmbuild/BUILDROOT Build root: where files are "installed" during the %install stage, which copies files from a subdirectory of %{_builddir} to a subdirectory of %{buildroot}. (Historically, %{buildroot} was in "/var/tmp/".)
%{buildsubdir} %{_builddir}/%{name} Build subdirectory: a subdirectory within %{_builddir} where files are compiled during the %build stage. It is set after %setup.
%{_datadir} /usr/share 系统共享目录
%{_defaultdocdir} /usr/share/doc 默认文档目录
%{dist} .fcNUMBER 发行版名称+版本号(例如 ".fc40")
%{fedora} NUMBER 发行版版本号(例如 "9")
%{_includedir} /usr/include
%{_infodir} /usr/share/info
%{_initrddir} /etc/rc.d/init.d
%{_libdir} /usr/lib
%{_libexecdir} /usr/libexec
%{_localstatedir} /var
%{_mandir} /usr/share/man
%{name} 软件包名称。set by Name: tag
%{_sbindir} /usr/sbin
%{_sharedstatedir} /var/lib
%{_sysconfdir} /etc
%{version} 软件包版本。set by Version: tag

Learn more about macros by looking in /etc/rpm/* and /usr/lib/rpm, especially /usr/lib/rpm/macros. Also use rpm --showrc to show values that RPM will use for macros (altered by rpmrc and macro configuration files).

You can set your own macro values using %global, but be sure to define them before you use them. (Macro definitions can also refer to other macros.) For example:

%global date 2012-02-08

Use the "-E" option of rpmbuild to find the value of a macro in a SPEC file:

rpmbuild -E '%{_bindir}' myfile.spec

Also see Packaging/RPMMacros and RPM Guide chapter 9.

其它标签

In addition to Requires and BuildRequires tags, you can also use these for controlling dependencies:

  • Provides: list virtual package names that this package provides. For example, there might be a package "foo" that demands a particular functionality "bar" from another program. If there are several packages that can satisfy that demand, those packages can specify "Provides: bar" and the "foo" package can specify "Requires: bar". You could also use the "alternatives" system, but avoid if multiple users on the same system might want different default, as these settings are system-wide. Use "rpm -q --provides PACKAGENAME" to see what a given package provides. Some examples of virtual packages in Fedora:
    • MTA: Used for mail transport agents, such as sendmail.
    • tex(latex): Used for latex
  • Obsoletes: remove another named package(s) when this package is installed. Use when the package name changes or when it totally replaces a different package.
  • Conflicts: state what other packages cannot be installed simultaneously to this one. Avoid this if you can. See Packaging/Conflicts.
  • BuildConflicts: state what packages cannot be installed when building this package. Avoid this if you can.

To manage different architectures, there are two tags:

  • ExcludeArch: to exclude an architecture on which the package doesn't build. For example:
ExcludeArch: ppc
  • ExclusiveArch: to include only the specified architecture. Avoid this unless absolutely correct.

Valid architectures are listed at Architectures.

子软件包

A SPEC file can define several binary package. In other words, one SRPM with one SPEC file can result in several RPMS. Note that there is still only one creation (%prep, %build, %install etc.) process. name-doc and name-devel subpackages are common for documentation and development files respectively.

Use the %package directive to start defining a subpackage:

%package subpackage_name

After each %package directive, list the tags for the subpackage. This should at least include the Summary and Group tags, as well as the %description subpackage_name and %files subpackage_name directives:

Anything not specified by the subpackage will be inherited from its parent.

By default, if the package name is "foo" and the subpackage name is "bar", then the resulting subpackage will be "foo-bar". You can override it with the "-n" option (but you'll need to use it in all other directives too if you specify it here):

%package -n new_subpackage_name

See the RPM Guide section on subpackages for more information.

Conditionals

You can insert conditional statements, for example to test if you are creating a binary for a certain architecture:

%ifarch ARCHITECTURE_NAME

the negated version with:

%ifnarch ARCHITECTURE_NAME

or the more general conditional:

%if TRUE_OR_FALSE

There is an optional "%else" section; all of these are closed with "%endif".

Application Specific Guidelines

There are many application-specific guidelines that can help you (e.g., for specific programming languages, applications, libraries, and build systems). Many of them are listed as part of the Application Specific Guidelines of Packaging/Guidelines. Examples of application-specific guidelines are those for:

Failing that, some other ways of finding application-specific help are:

小提示

Packaging/FrequentlyMadeMistakes has information on frequently-made mistakes. There are also some recommendations and controversial tricks on PackageMaintainers/Packaging Tricks.

Try to write your SPEC files so that it is likely to work when a new release is made upstream, without any changes aside from bumping the version number and refreshing the source files. For example, if it contains *.txt files with execute bits, instead of doing

 chmod a-x Filename1.txt Filename2.txt Filename3.txt

consider doing this, which will handle new filenames that use the same file naming convention:

 chmod a-x *.txt

If you want to see lots of examples of scriptlets, you can show all the scriptlets on installed programs using:

 rpm -qa --queryformat "\n\nPACKAGE: %{name}\n" --scripts | less

Don't try to interact with the user; RPM is designed to support batch installs. If an application needs to show a EULA, that needs to be part of its initial execution, not its installation.

You might not want to start services, because in a big install that could slow things down. If you install an init or systemd script, consider using chkconfig or systemctl to arrange for the service to be started/stopped on the next reboot. Before uninstalling, you should normally try to stop its services if they are running.

Uninstalling should reverse most changes made during installation, but don't remove any user-created files.

Normally, if there are binary executables, then debugging symbols are stripped from the normal binary packages and placed into a name-debug subpackage. If this shouldn't happen, you can disable the stripping and creation of this subpackage by putting this at the top of your SPEC:

%global _enable_debug_package 0
%global debug_package %{nil}
%global __os_install_post /usr/lib/rpm/brp-compress %{nil}

To prevent stripping you may also need to do this in the %install section:

export DONT_STRIP=1

A way to check for the version of Fedora in a SPEC file for conditional builds is:

%if 0%{?fedora} <= <version>

The ? causes the macro to evaluate to evaluate to blank if %fedora is not defined. This causes the end result to be the 0 (which is a number and thus fine), while not interfering with the result if there is actually a value for %fedora. (Note that this trick does not work in Koji "scratch" builds, where %fedora is set during the creation of a SRPM.)

GUI programs must have a desktop entry so that people can invoke it from the graphical desktop menu. For .desktop files, see Fedora packaging guidelines for desktop files and desktop entry spec. For icons within /usr/share/icons, see icon theme spec.

构建

使用 rpmlint 测试

请先使用 rpmlint 查找 SPEC 文件的错误:

$ rpmlint program.spec

如果没什么异常,使用 "-i" 参数查看长输出。

某些情况下 rpmlint 的报错不一定代表有问题,请查看 打包规定 了解具体有哪些。

从 SPEC 构建 RPM

一旦 SPEC 编写完毕,请通过 rpmbuild 来构建:

$ rpmbuild -ba program.spec

成功的话,RPM 会保存至 ~/rpmbuild/RPMS,SRPM 会保存至 ~/rpmbuild/SRPMS

If it fails, go to the appropriate directory and see what is left over. To help debug, you can skip earlier stages that succeeded with the "--short-circuit option. For example, to restart at the %install stage (skipping earlier stages), do this:

$ rpmbuild -bi --short-circuit program.spec

如果只想创建 SRPM(也就是不需要执行 %prep%build 或其他阶段),请运行:

rpmbuild -bs program.spec

使用 rpmlint 测试已构建的 RPM

rpmlint 可用于检查 SPEC/RPM/SRPM 的错误。You need to eliminate or justify warnings before posting a package. If you are in the SPECS directory, do this:

$ rpmlint NAME.spec ../RPMS/*/NAME*.rpm ../SRPMS/NAME*.rpm

进入 ~/rpmbuild/RPMS 目录下的特定架构目录,您会发现有许多二进制 RPM 包。Quickly see their files and permissions (to check whether they are correct) by doing:

$ rpmls *.rpm

如果看上去正常,以 root 权限安装它们:

# rpm -ivp package1.rpm package2.rpm package3.rpm ...

Test the programs in a few different ways to see if everything works correctly. If it is a GUI tool, make sure it shows up in the desktop menu, otherwise the .desktop entry is wrong.

最后删除:

# rpm -e package1 package2 package3

Mock 和 Koji

Mock is a powerful tool that uses the SRPM you have created to build binary packages within a nearly empty environment. This can reveal if you have accurate build dependencies. If it fails, then you forgot to list something in BuildRequires. See Using Mock to test package builds. Once your account is a member of the "mock" group, you can run commands like this to do local testing:

$ mock -r fedora-9-i386 rebuild path_to_source_RPM

You can use Koji (which uses mock) to do builds on many different systems, some of which you may not have. PackageMaintainers/Join and PackageMaintainers/UsingKoji have more information about Koji. Once it's set up, you can test your SRPM on a variety of platforms by running commands like:

$ koji build --scratch dist-f9 path_to_source_RPM

Replace dist-f9 with any later release of Fedora, but don't use dist-rawhide. Remember, the values of %fedora, %fc9 and so on will not be correct for a scratch build, so this won't work if your SPEC file does something different based on those values.

Your Koji builds can only depend on packages that are actually in the TARGET distribution repository. Thus, you can't use Koji to build for released distributions if your package depends on other new packages that Bodhi hasn't released yet. If you need to build against a package that is not yet a stable released update, you can file a ticket with rel-eng at: https://fedorahosted.org/rel-eng/newticket and request that that package be added as a buildroot override.

有帮助的工具

rpmdevtools 软件包包含大量有用的工具;"rpm -qil rpmdevtools" 将会显示所有可用命令。

  • rpmdev-bumpspec : bump the release tag in the spec file and add a changelog comment with the right date and version 格式:
rpmdev-bumpspec --comment=COMMENT --userstring=NAME+EMAIL_STRING SPECFILES

The yum-utils package also has some useful tools:

  • yumdownloader : download the SRPM of the package by running:
yumdownloader --source PACKAGENAME

The auto-buildrequires package has a pair of nice tools for helping to figure out the proper BuildRequires entries. After installing this package, replace "rpmbuild" with "auto-br-rpmbuild" and you'll see an automatically generated BuildRequires list.

You might find RUST useful (GPL), though it does not create SPEC files of suitable quality for Fedora packages. Alien converts between package formats. It won't produce clean SRPMS, but converting an existing package might provide helpful information.

相关规定

在您创建软件包的时候,请遵守下列规定:

这里也有许多针对特殊环境打包的规定(Java 程序,OCaml 程序,GNOME 程序等等);您也可以从 SIGs 获取许多有价值的帮助。软件包维护人员 分类是所有部分的总结页面。

这里还有一份所有有关打包的页面列表

除了这些,还有许多非官方的指南帮助,比如 打包规定草稿今后需要制定的打包规定

还有其它地方也可供参考,比如 SuSE 的打包规定Debian 的打包规定,但是 每个发行版都有不一样的地方,所以不要直接生搬硬套。

请注意所有 spec 文件必须是有关开源的软件,就像FPCA 声明所描述的一样。

维护软件包

一旦您的软件包被批准放入官方软件源,您需要维护或者协助维护它。 请见 Package update HOWTOPackage update guidelines 以便了解更多。 如果您为多个不同的 Fedora 版本维护软件包,有空一定要为之前的 Fedora 版本也制作一个。

Encourage the upstream developers to use standard source code release conventions. Using standard conventions makes packaging much easier. For more information, see:

更多信息

软件包维护人员 页面加入了许多有用页面的链接,您不妨去看看。如何升级您维护的软件包 页面描述了如何升级您维护的在 Fedora 源里面的软件包。

更多在维基之外的页面,请见以下:

注意: rpm5.org 也有一些文档,但是请不要过度依赖这个网站的内容。这个网站是由 Jeff Johnson 维护的一个 RPM 5.x 版本的网站。事实上RPM 5.x 版本并不适用于 Fedora 系统!和 Novell/SuSE 系统一样,Fedora 采用的 RPM 安装器基于 rpm.org 维护的版本。 在 lwn.net 有一个关于这两者的简短区别介绍。