From Fedora Project Wiki
No edit summary
Line 249: Line 249:


===== =====
===== =====
{{Anchor|Spec檔區段詳解}}
{{Anchor|Spec_檔區段詳解}}


== SPEC 檔概覽 ==
== SPEC 檔概覽 ==

Revision as of 14:18, 7 February 2015

翻譯: Caius 'kaio' ChanceCheng-Chia Tseng

簡介

本頁旨在詳細解說製作 RPM 軟體包的方法,特別是指製作 SPEC 檔的方法。不像其他的 RPM 教學指引,本頁有針對 Fedora 的規格作解說,並附上 Fedora 專用的規約 (guideline) 連結。由於本頁內容是以 Fedora Wiki 系統作維護,比起其他教學指引可能資訊還新一些。除了專注於 Fedora 的部份之外,文件中的大部份內容都能用於其他採用 RPM 作為軟體包管理系統的 Linux 散布版。如果你覺得按耐不住了,你可以改看較簡短的 如何製作 RPM 軟體包

目前 Fedora 文件已發行一份給打包者遵守的草擬規約,請見 Packagers Guide

請注意本篇內文並非 Fedora 官方軟體包的規約 打包委員會 才是處理 Fedora 中軟體打包守則與規約的組織。其中最重要的是:

Packaging GuidelinesPackage Naming Guidelines 皆是 Fedora 打包的主要規約。本頁的內容應與規約相容。

若你打算為 Fedora 軟體庫製作個 RPM 軟體包,請遵循 Join the package collection maintainers 中的步驟來做。

準備系統

在你為 Fedora 建立 RPM 軟體包之前,你需要安裝一些核心開發工具,並設置你會用到的帳號:

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

你可以特別為 RPM 軟體包的製作建立個傻瓜使用者 (dummy user),以避免建置程序出錯摧毀你的檔案,或將私人金鑰傳給全世界。

Stop (medium size).png
你「永遠」都不該以 root 使用者的身份製作 RPM 軟體包。用 root 帳號建置 RPM 非常危險,因為軟體在打包之前就會將二進位檔安裝在系統之中,所以你必須總是使用一般使用者來建置,以免意外污染你的系統。

建立一位名為 makerpm 的傻瓜使用者,將使用者加入 'mock' 群組中,設定個密碼,並以該位使用者身份登入:

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

一旦你以建置用假使用者登入後,在你的家屋目錄中執行以下指令來建立需要的目錄結構:

$ rpmdev-setuptree

rpmdev-setuptree 程式會建立 ~/rpmbuild 目錄與一組子目錄 (例:SPECSBUILD),你將利用它們製作軟體包。同時也會建立 ~/.rpmacros 檔,可用來設定許多選項。

打包規約建議保留檔案的時間戳記;如果你使用 wgetcurl 下載源碼檔案的話,你可以讓程式自動保留時間戳記。如你使用 wget 下載源碼檔案,將「timestamping = on」加入 ~/.wgetrc 組態中。如你使用 curl 的話,則將「-R」加入 ~/.curlrc 組態中。

一般來說往後就不再需要重複以上步驟。

建置 RPM 軟體包的基本要領

製作 RPM 軟體包,你需要先有「.spec」文字檔,這份檔案提供打包軟體的相關資訊。接著針對 SPEC 檔執行 rpmbuild 指令,進行產生軟體包的一系列步驟。

一般來說,你應該將原始 (原生) 來源,例如來自原開發者的 .tar.gz 檔,放進 ~/rpmbuild/SOURCES 目錄中。將 .spec 檔放進 ~/rpmbuild/SPECS 目錄中,並命名為「NAME.spec」,而 NAME 為軟體包的基礎名稱。最後同時製作二進位軟體包與源碼軟體包,先將目錄切換至 ~/rpmbuild/SPECS 並執行:

$ rpmbuild -ba NAME.spec

rpmbuild 會讀取 .spec 檔,並以下列所述階段走過檔案內容。以 % 開頭的字為預先定義的巨集 (請見下方的表格)。

階段 讀取 寫入 動作
%prep (準備) %_sourcedir %_builddir 它會讀取源碼目錄 %_sourcedir 下的源碼及補丁。它解開源碼封存檔,將內容放到建置資料夾 %_builddir (大多是 ~/rpmbuild/BUILD/) 內部的子資料夾內部,並套用補丁。
%build (建置) %_builddir %_builddir 它會在建置資料夾 %_builddir 內部編譯檔案。這通常是執行 "./configure && make" 之類的指令。
%install (安裝) %_builddir %_buildrootdir 它會讀取建置資料夾 %_builddir 內部的檔案,並寫入建置根基資料夾 %_buildrootdir 內部的一個目錄下。寫入的檔案即是使用者在安裝二進位軟體包時所要安裝的檔案。請留意這個怪異的術語:建置根基 (build root) 資料夾不是 前面所說的 建置資料夾。 本步驟通常是執行 "make install"。
%check (檢查) %_builddir %_builddir 檢查軟體是否可以順利運作。這通常是執行 "make test" 之類的指令。許多軟體包不處理這個步驟。
bin (二進位包) %_buildrootdir %_rpmdir 它會讀取建置根基資料夾 %_buildrootdir 內部的檔案,以在 RPM 資料夾 %_rpmdir 內部製作二進位 RPM 軟體包。在 RPM 資料夾內有各個 CPU 架構的子資料夾,以及一個可給任何架構使用的 "noarch" 資料夾。這些 RPM 檔即是給使用者安裝用的軟體包。
src (源碼包) %_sourcedir %_srcrpmdir 它會在源碼 RPM 資料夾 %_srcrpmdir 下製作源碼 RPM 軟體包 (.src.rpm)。這些檔案用於軟體包的校閱與上傳。

註:上述表格中的「下」與「內部」意思不同。例如有個檔案位於 /a/b/c,則 c 位於 a 的「內部」而非 a 之「下」。

如你所見,在 rpmbuild 中,特定的資料夾有特定的用途。這些是:

巨集名稱 名稱 通常 用途
%_specdir 規格 (Specification) 資料夾 ~/rpmbuild/SPECS RPM 規格 (.spec) 檔
%_sourcedir 來源 (Source) 資料夾 ~/rpmbuild/SOURCES 元初來源封存檔 (如:tarball) 與補丁 (patch)
%_builddir 建置 (Build) 資料夾 ~/rpmbuild/BUILD 解開源碼檔並在此資料夾內部的子資料夾下編譯。
%_buildrootdir 建置根基 (Build root) 資料夾 ~/rpmbuild/BUILDROOT 在 %install 階段中,檔案安裝於此處。
%_rpmdir 二進位 (Binary) RPM 資料夾 ~/rpmbuild/RPMS 二進位 RPM 檔於此製作、儲存。
%_srcrpmdir 源碼 (Source) RPM 資料夾 ~/rpmbuild/SRPMS 源碼 RPM 檔於此製作、儲存。

如果在某個階段失敗了,你需要查看詳細輸出內容以瞭解 為何 失敗,並根據所需修改 .spec 檔 (或其他輸入來源)。

準備好打包某個程式

如果需要有其他的特別程式才能建置或執行你想要打包的程式,先安裝那些程式然後記下來是哪些 (你會用到這些資訊)。

若要為 Fedora 軟體庫打包程式,你 必須 將元初 (原始) 來源連同修補檔與建置指示都一起包進去;採用預先編譯過的代碼「並不」妥當。請將原始來源 (通常是 .tar.gz 檔) 放在 ~/rpmbuild/SOURCES 目錄 (建置 RPM 的使用者帳號下) 中,然後用它來安裝檔案。

請先閱讀這個程式的手動安裝指示;你接下來會需要編輯「.spec」檔來將流程自動化,所以你必須先瞭解應該要怎麼做。 在你試圖用 RPM 建置程式之前,最好你先親手「實際跑過 (dry run)」建置一次 (如果你對 RPM 還不是很熟的話,這真的很重要)。 除了一些例外,Fedora 軟體中包含的所有二進位檔與函式庫,都必須從源碼軟體包中所含的源碼建置。

拆分程式

應用程式源碼經常與其他外部函式庫一起發行,也就是說整個「綁在一塊」。 然而,請不要將外部函式庫和主程式綁在一塊,統統包成一個軟體包。 相反的,請將他們拆分開來成為獨立的軟體包 。

判斷授權

請只打包法律上允許你打包的軟體。

請參見 Packaging:Guidelines#LegalLicensing:Main、和 Packaging:LicensingGuidelines。 通常來說,只有以核可的開源軟體 OSS 授權 (例如 GPL、LGPL、BSD-new、MIT/X、或 Apache 2.0 等授權) 發行的軟體可以打包。 請確認軟體真的以這種方式授權 (例如:查看源碼的標頭、README 檔等等)。 如果軟體有綁函式庫,請確認這些函式庫也是採用 OSS 授權。

重複使用既有的軟體包資訊

盡可能重複使用。例如,請確認你想打包的不是早就有人打包過的東西。你可以從 Fedora Package Collection Fedora Package Database 中找到既有軟體包的清單。

也請查看 In Progress Review RequestsRetired Packages 清單。你可以直接使用 Fedora Packages Git Repositories 來檢視 SPEC 檔 (與修補檔)。你可以使用 <cod> yum-utils 軟體來下載 SRPMS:

# yum -y install yum-utils
$ yumdownloader --source sourcepackage-name

另外,也可手動從 Fedora mirror http/ftp 網頁下的 releases/39/Everything/source/SRPMS 目錄取得源碼軟體包。請將「39」替換成你想要使用的 Fedora 發行版本,接著下載該軟體的 .src.rpm 軟體包。

一旦你下載好 SRPM,請將它安裝到 ~/rpmbuild

$ rpm -ivh sourcepackage-name*.src.rpm

你也可以用 rpm2cpio 將 SRPM 包解開放到目錄中:

$ mkdir PROGRAMNAME_src_rpm
$ cd PROGRAMNAME_src_rpm
$ rpm2cpio ../PROGRAMNAME-*.src.rpm | cpio -i

有時候利用既有的軟體包作為開始是最簡單的方式,只要稍微清理一下就能讓 Fedora 使用。RPM FindPKGS.org 可以幫你找到一些非 Fedora 系統的 RPM。你可以安裝其他系統的 SRPM,就像安裝 Fedora 的 SRPM 一樣。若找不到可以利用的軟體包,你或許可以參考看看給 UbuntuDebian 用的源碼軟體包 (不是 .deb 檔。源碼軟體包的檔案是標準的 tarball,但是有個「debian/」子目錄)。如果 FreeBSD ports collection 中有你要的軟體,你可以下載 the FreeBSD ports tarball,然後看看他們的打包資訊是否能幫助你作為起點。不過,也有可能這些都一點幫助也沒有。不同的散布版有不同的規則,所以他們的作法或許對 Fedora 而言反而不妥。

製作 SPEC 檔

現在你需要在 ~/rpmbuild/SPECS 目錄中製作一份 SPEC 檔。你應該根據程式名稱來命名 (例:「program.spec」) 這份檔案。你可以使用封存檔的名稱,或如果軟體作者有倡議該用怎樣的名稱就用該名稱,但無論如何都應遵守 軟體包命名規約 中的規範。

SPEC 樣板與範例

樣板

首次製作 SPEC 檔時,可以利用 vim 或 emacs 來自動建立樣板:

 $ cd ~/rpmbuild/SPECS
 $ vim program.spec

以下是樣板看起來的模樣 (注意:供應的樣板不一定有遵守 Fedora 打包規約):

Name:		
Version:	
Release:	1%{?dist}
Summary:	
Group:		
License:	
URL:		
Source0:	

BuildRequires:	
Requires:	

%description

%prep
%autosetup

%build
%configure
make %{?_smp_mflags}

%install
%make_install

%files
%doc

%changelog

你可以用 $RPM_BUILD_ROOT 取代 %{buildroot}。這兩者都能用,只不過記得前後一致就好。

你也可以用 rpmdev-newspec 指令來製作 SPEC 檔。rpmdev-newspec NAME-OF-NEW-PACKAGE 可為新軟體包製作初始 SPEC 檔,適合各種類型的軟體包使用。它會根據你給的軟體包名稱來猜測可能的種類給予對應的樣板,你也可以直接指定特定的樣板。請見 /etc/rpmdevetools/spectemplate-*.spec 來查閱可用的樣板,也可見 rpmdev-newspec --help 瞭解更多資訊。舉例來說,若想為 python 模組製作個新 SPEC 檔:

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
%autosetup -n %{name}

%build
%configure
make %{?_smp_mflags}

%install
%make_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 檔概覽

其他有用的指引:

你需要遵守 Fedora 規約: Package Naming Guidelines, Packaging guidelines,以及 Package review guidelines

你可以用「#」字號作為註解的前導字元,但請避免用到可展開成許多列 (以 % 作開頭) 的巨集 (因為它們會先被替換展開)。如果要註解掉一列,百分比符號請改成兩個 (%%)。此外,也請避免使用列內註解 (「#」),例如在同一列中使用指令稿指令提示符。

下方列的是主要標籤。請注意巨集 %{name}%{version}、和 %{release} 可用來各自指稱 Name 名稱、Version 版本與 Release 發行版次標籤。只要更改標籤,巨集就會自動更新使用新值。

  • Name:軟體包的 (基礎) 名稱,應該與 SPEC 檔名相符。它必須遵守 Package Naming Guidelines,一般只用小寫。
  • Version:上游版本號。請見打包規約的 Version tag section。如果版本包含非數字標籤 (即版本標籤不是用數字表示),你可能需要在 Release 發行版次標籤中加入額外的非數字字元。如果上游版本標籤用的是完整日期來區隔版本,請考慮以 yy.mm[dd] (例如:2008-05-01 就變成 8.05) 格式來作為版本號。
  • Release:發行版次。初始值一般都應該是 1%{?dist}。每次新發行同版本軟體的軟體包就遞增一個數字。若上游發行新的版本,就對應修改 Version 標籤,然後把 Release 發行版次重設回 1。請見打包規約的 Release tag section。選標的 Dist tag 可能會用得到。
  • Summary:簡要的、只用一列的軟體包摘要。記得使用美式英文。 還有,「絕對不可以」加上半形句號 (.) 作為結尾。
  • Group:這個標籤需要使用先前就已經存在過的群組,例如「Applications/Engineering」;請執行「less /usr/share/doc/rpm-*/GROUPS」來查閱完整列表。任何含有文件的子軟體包,請用「Documentation」作為群組 (例如:kernel-doc)。 注意:這個標籤從 Fedora 17 之後就棄用了。請見 [File Reference Preamble]
  • License:授權條款,必須是開源軟體授權。請不要用舊的 Copyright 標籤。採用標準縮寫 (例如:「GPLv2+」),並且明確 (例如可採用 GPL 2 或後續版本,就寫「GPLv2+」,而不是只隨便寫個「GPL」或「GPLv2」就算了)。請見 LicensingLicensing Guidelines。你可以用「and」以及「or」來合併列出多種授權 (例如:「GPLv2 and BSD」)。
  • URL: The full URL for more information about the program (e.g. the project website). Note: This is not where the original source code came from which is meant for the Source0 tag below.
  • Source0: The full URL for the compressed archive containing the (original) pristine source code, as upstream released it. "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: 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 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 "%autosetup"; a common variation is "%autosetup -n NAME" if the source file unpacks into NAME. 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.
  • %install: Script commands to "install" the program. The commands should copy the files from the BUILD directory %{_builddir} into the buildroot directory, %{buildroot}. See the %install section below for more.
  • %check: Script commands to "test" the program. This is run after the %install procedure, 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.
  • %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:
rm -rf %{buildroot}
  • %files: The list of files that will be installed. See the %files section below for more.
  • %changelog: Changes in the package. Use the format example above. Do NOT put software's changelog at here.This changelog is for RPM itself.
  • ExcludeArch: If the package does not successfully compile, build or work on a particular architecture, list those architectures under this tag.
  • 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
Do NOT use these tags
  • Packager
  • Vendor
  • Copyright

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

SPEC 檔區段詳解

%prep section

The %prep section describes how to unpack the compressed packages so that they can be built. Typically, this includes the "%autosetup" command. Alternatively, you can use "%setup" and "%patch" commands with reference to the Source0 (and Source1 etc.) lines. See the Maximum RPM section on %setup and %patch for more details.

The %{patches} and %{sources} macros are available since RPM 4.4.2 and are useful if you have a large list of patches or sources and %autosetup is not what you want, then you can do:

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

However, keep in mind that using these will make your SPEC incompatible with RPMS used in RHEL and other RPM-based dirstributions.

%prep section: %autosetup command

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

  • -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 "%autosetup -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.

If you use "%setup" command instead, then -q' is commonly used to suppress unecessary output.

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 section: %patch commands

If you have used "%autosetup" command, the following manual patch management is not necessary. If you have complex requirements or need compatibility with EPEL, you may still need this. The "%patch0" command applies Patch0 (and %patch1 applies Patch1 etc.). Patches are the normal method of making necessary changes to the source code for packaging. 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.

This is a typical procedure for creating a patch for a single file:

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 -ur ../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 section: 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 section

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.

%install section

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} # redundant except for RHEL 5
%make_install

Ideally you should use %make_install which is equivalent to 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}/

%check section

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 %install section, since files in %buildroot may be tested) instead of within the %build section itself, so that they can be easily skipped when necessary.

Often, this section contains:

make test

Sometimes it can be:

make check

Please explore the Makefile and choose the appropriate way.

%files section

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 sets 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.

An error will occur if:

  • 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 an appropriate directory under /usr/share/doc, whose ownership does not need to be declared.

Note: If specifying a %doc entry, rpmbuild < 4.9.1 removes the doc directory it installs files into before installing them. This means that files already in it, for example installed in the %install section, are removed and do not end up in the package. If you want to install some files in the %install section, install them into a temporary staging directory inside the build dir (not build root), for example _docs_staging, and include them in the in the %files list like %doc _docs_staging/*.

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 example

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

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

Finding duplicates

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 ability are "triggers", which can be run for your package when other packages are installed or uninstalled. See RPM Triggers.

Macros

Macros are text in the format %{string}. Typical macros:

Macro Typical Expansion Meaning
%{_bindir} /usr/bin Binary directory: where executables are usually stored.
%{_builddir} ~/rpmbuild/BUILD Build directory: files are compiled within a subdirectory of the build directory. See %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 %autosetup.
%{_datadir} /usr/share Share directory.
%{_defaultdocdir} /usr/share/doc Default documentation directory.
%{dist} .fcNUMBER Distribution+version short name (e.g. ".fc39")
%{fedora} NUMBER Number of fedora release (e.g. "39")
%{_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} Name of package, set by Name: tag
%{_sbindir} /usr/sbin
%{_sharedstatedir} /var/lib
%{_sysconfdir} /etc
%{version} Version of package, 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.

Other tags

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.

Subpackages

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:

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 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.

Building the binary package

Test with rpmlint

To catch many common errors early, run rpmlint on your SPEC file before trying to build anything from it:

$ rpmlint program.spec

If the reported error doesn't make sense, run it again with the "-i" option for longer messages.

Aim to have no errors, but sometimes rpmlint reports false positives. The Fedora packaging guidelines explains which ones to ignore.

Create binary RPMS from the SPEC file

Once you've created your SPEC file, build the SRPM and binary RPMS by running this:

$ rpmbuild -ba program.spec

If successful, RPMS will be created within ~/rpmbuild/RPMS and SRPMS will be created within ~/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

If you just want to create an SRPM (which does not run the %prep or %build or other stages), run this:

rpmbuild -bs program.spec

Testing binary RPMS with rpmlint

rpmlint can be run on SPEC files, RPMS and SRPMS to check for errors. You need to eliminate or justify warnings before posting a package. This page offers explanations for some of the common issues that come up. If you are in the SPECS directory, do this:

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

Enter the ~/rpmbuild/RPMS directory and into the architecture subdirectory. You will find some binary RPMS. Quickly see their files and permissions (to check whether they are correct) by doing:

$ rpmls *.rpm

If they look fine, install them as 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.

Uninstall packages later by doing:

# rpm -e package1 package2 package3

Mock and 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, submit a Koji buildroot override request via Bodhi. If it's not your own package you depend on, contact its maintainer(s). [Before Bodhi could handle Koji buildroot override requests, the old method has been to 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.

  • rpmdev-bumpspec : bump the release tag in the spec file and add a changelog comment with the right date and version format:
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.

Finally, docker-rpm-builder (APL 2.0) uses Docker to build RPM packages; while using rpmbuild requires building on the same host distro as the target, and mock works fine on Fedora/Centos/RHEL distributions for any target, this last tool works fine whenever Docker can run.

If you want to build your package for diferent distribution and architectures and to have publicly accesible yum repository, you can submit your src.rpm to Copr.

Guidelines and rules

When you create your packages, you'll need to follow the following rules and guidelines:

There are many official guidelines that will help you with specific circumstances (e.g. Java programs, OCaml programs, GNOME programs). You can also learn more from the SIGs and Package Maintainers sections.

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 Packaging Drafts and Packaging Drafts To Do.

You might find ideas from SuSE, Debian, but 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 FPCA.

Maintaining the package

Once your package has been accepted, you and your co-maintainers will need to maintain it. See Package update HOWTO and Package update guidelines. If you update the version in multiple releases of Fedora, do it backwards in time (e.g. release for Fedora N, then once that's accepted, Fedora N-1). The system presumes that later versions of Fedora have the same or later versions of programs.

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

For more information

The Package Maintainers page links to many other useful pages, and the Package update HOWTO describes how to update an existing package you already maintain in Fedora.

For more information, outside of the Fedora Wiki, see:

Note: The rpm5.org site has some documentation, but do not depend on it; that is the home of a fork of RPM maintained by Jeff Johnson. The RPM used by Fedora (and Novell/SuSE) is instead based at rpm.org. lwn.net has a brief article about this.