赞
踩
在您为 Fedora 创建 RPM 包之前,您需要安装一些必须的开发组件并且设置好即将使用的账户:
# yum install @development-tools # yum install fedora-packager
您可以新建一个临时用户以便创建 RPM 包。这样,如果有错误发生,构建程序不会破坏您的系统,比如造成文件损失或者您的私人文件/密钥被发送到互联网上。
新建一个叫做makerpm
的用户,添加至 'mock' 用户组,设置好密码并通过该用户登录:
# /usr/sbin/useradd makerpm # usermod -a -G mock makerpm # passwd makerpm
然后您可以通过这个临时用户开始执行打包操作。
一旦登录了 makerpm 用户,您可以使用一下命令在这个用户的家目录下创建一个标准的打包工作目录结构:
$ rpmdev-setuptree
rpmdev-setuptree
程序新建一个位置是 ~/rpmbuild
的目录。在 "rpmbuild" 目录下是一些预设好的子目录(比如 SPECS
和 BUILD
),它们将会在创建软件包的时候起作用。rpmdev-setuptree
也会创建一个位置是 ~/.rpmmacros
的文件。它是一个保存有关设置的文件。
打包指南推荐使用命令保存时间戳;当然,您在使用 wget
或者 curl
获取软件源代码的时候就会自动保存。如果您使用 wget
来获取源代码,确保在 ~/.wgetrc
文件加入一行 timestamping = on
。类似的,如果您使用 curl
,确保 ~/.curlrc
文件包含 "-R"。
一旦设置完毕,通常不需要再次设置。
若要构建一个标准的 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#Legal、Licensing:Main 和 Packaging: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/20/Everything/source/SRPMS 目录内(请把"20"换成您想要的 Fedora 版本),然后下载即可。通常源代码包以 .src.rpm 为后缀名。
一旦有了源代码包,请按照下面的步骤安装到 ~/rpmbuild
目录下:
$ rpm -ivh 源代码包名字.src.rpm
您也可以使用 rpm2cpio
把源代码包解压到任意目录:
$ mkdir 源代码包名字_src_rpm $ cd 源代码包名字E_src_rpm $ rpm2cpio ../源代码包名字.src.rpm | cpio -i
使用这些已经存在的信息有助于您更快打包。RPM Find 和 PKGS.org 将帮助您找到针对非 Fedora 的 RPM 包。您可以尝试安装它们。如果失败,请查看相应的源代码包(不是 .deb
) 结尾的 Ubuntu 或 Debian软件包(源代码包通常是标准的 tar 文件比并且内部包含一个叫做 "debian/
" 的子目录)。如果您在 FreeBSD ports 仓库 找到想要的文件, 请下载 ports 的源代码包 并查看是否包含相关信息。有些时候这些操作没什么实际帮助,因为不同的系统有不同的规定。
现在您需要新建一个 ".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
这是 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)
其他有用的介绍:
您也将需要按照这些规定来做:软件包命名规定,打包规定 和 软件包审核规定。
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 中修改它们,构建会自动抓去新的内容。
yy.mm[dd]
(例如 2008-05-01
可变为 8.05
)。1%{?dist}
。每次您制作新的包时,请递增该数字。当上游发布新版本时,请修改 Version 标签并重置 Release 的数字为 1
。具体请看打包规定中的 Release 标签部分。Dist tag 可能也会帮助您。less /usr/share/doc/rpm-*/GROUPS
" 来查看完整的组列表。使用组 "Documentation" 为所有包含文档的子软件包(例如 kernel-doc
)。注意这个标签从 Fedora 17 后已被废除。[文件参考手册] 有介绍GPLv2+
")且清楚的的描述(例如,使用 "GPLv2+
" 来注明 GPL version 2 及更高而不是 "GPL
" 或 "GPLv2
" 这种不准确的描述)。请见 Licensing 和 Licensing Guidelines。如果一个软件包包含多个协议,您可以使用 "and
" 和 "or
" (例如 "GPLv2 and BSD
")来描述。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).~/rpmbuild/SOURCES
directory. Patches should make only one logical change each, so it's quite possible to have multiple patch files.BuildArch: noarch
". The architecture for the binary RPM will then be "noarch
".%{_topdir}/BUILDROOT/
".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 auto-buildrequires
package may be helpful.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.%setup -q
"; a common variation is "%setup -q -n NAME
" if the source file unpacks into NAME
. See the %prep section below for more.make test
" or "make check
". This is separated from %build so that people can skip the self-test if they desire.BUILD
directory %{_builddir}
into the buildroot directory, %{buildroot}
. 具体请见下文的 %install 部分。rm -rf %{buildroot}
RPM also supports the creation of several packages (called subpackages) from a single SPEC file, such as name-libs
and name-devel
packages.
Do not create a "relocatable" package; they don't add value in Fedora and make things more complicated.
%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 机制的发行版中,这是无法识别的。
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 youare 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. |
"%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.
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 .
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.
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
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:
%{_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.%{buildsubdir}
, which is the subdirectory within %{_builddir}
that was created during %prep stage. This is usually something like ~/rpmbuild/BUILD/%{name}-%{version}
.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:
DESTDIR
. Create directories inside DESTDIR
where necessary and submit the patch upstream.%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.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
.%{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
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.
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.
如果满足下列条件,会有错误发生:
%{buildroot}
has not been listedIt 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.
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:
%install
step: %find_lang ${name}
BuildRequires: gettext
%files -f ${name}.lang
These prefixes are not valid in Fedora: %license
and %readme
.
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
.
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
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:
%pre
) or after (%post
) a package is installed%preun
) or after (%postun
) a package is uninstalled%pretrans
) or end (%posttrans
) of a transactionFor 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 | 发行版名称+版本号(例如 ".fc20 ") |
%{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:
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:
To manage different architectures, there are two tags:
ExcludeArch: ppc
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.
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
".
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 theApplication 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 onPackageMaintainers/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
查找 SPEC 文件的错误:
$ rpmlint program.spec
如果没什么异常,使用 "-i
" 参数查看长输出。
某些情况下 rpmlint
的报错不一定代表有问题,请查看 打包规定了解具体有哪些。
一旦 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
可用于检查 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 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.
源自:https://fedoraproject.org/wiki/How_to_create_an_RPM_package/zh-cn#RPM_.E5.9F.BA.E7.A1.80.E7.9F.A5.E8.AF.86
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。