From Fedora Project Wiki
m (internal link cleaning)
 
(46 intermediate revisions by 2 users not shown)
Line 247: Line 247:
- handle multi-partition devices with spaces in mount points properly (#608502)
- handle multi-partition devices with spaces in mount points properly (#608502)
</pre>
</pre>
===== =====
{{Anchor|Spec_file_pieces_explained}}


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


Other useful guides:
其他有用的指引:
其他有用的指引:
* [http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM Guide] 描寫如何寫作 SPEC 檔。
* [http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM Guide] 描寫如何寫作 SPEC 檔。
Line 270: Line 266:
* '''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 File Reference Preamble]] '''''
* '''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 File Reference Preamble]] '''''
* '''License''':授權條款,必須是開源軟體授權。請''不要''用舊的 Copyright 標籤。採用標準縮寫 (例如:「<code>GPLv2+</code>」),並且明確 (例如可採用 GPL 2 或後續版本,就寫「<code>GPLv2+</code>」,而不是只隨便寫個「<code>GPL</code>」或「<code>GPLv2</code>」就算了)。請見 [[Licensing]] 與 [[Packaging/LicensingGuidelines|Licensing Guidelines]]。你可以用「<code>and</code>」以及「<code>or</code>」來合併列出多種授權 (例如:「<code>GPLv2 and BSD</code>」)。
* '''License''':授權條款,必須是開源軟體授權。請''不要''用舊的 Copyright 標籤。採用標準縮寫 (例如:「<code>GPLv2+</code>」),並且明確 (例如可採用 GPL 2 或後續版本,就寫「<code>GPLv2+</code>」,而不是只隨便寫個「<code>GPL</code>」或「<code>GPLv2</code>」就算了)。請見 [[Licensing]] 與 [[Packaging/LicensingGuidelines|Licensing Guidelines]]。你可以用「<code>and</code>」以及「<code>or</code>」來合併列出多種授權 (例如:「<code>GPLv2 and BSD</code>」)。
* URL: The URL for more information about the program, e.g., the project website.  Note: This is NOT where the original source code came from, see "Source" (next!).
* '''URL''': 有關該程式更多資訊的完整 URL (例如該程式的專案網站)。 '''''注意:這不是原本源碼的來源 URL,源碼封存檔的來源 URL 應該用下列的 Source0'''''。
* Source0: The URL for the compressed archive containing (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.  '''Warning:''' ''Source0:'' and ''URL:'' are different - normally they are both URLs, but the "URL:" entry points to the project website, while the "Source0:" entry points to the actual file containing the source code (and is typically a .tar.gz file).  As noted in the guidelines, "When downloading sources, patches etc, consider using a client that preserves the upstream timestamps. For example wget -N or curl -R. To make the change global for wget, add this to your ~/.wgetrc: timestamping = on, and for curl, add to your ~/.curlrc: -R."  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, you can list each of them as sources as well, but list them ''after'' the pristine sources. A copy of each of these sources will be included in any source package you create (unless you specially direct otherwise).  See [[Packaging/SourceURL]] for more information on special cases (using revision control, when upstream uses prohibited code, etc.).
* '''Source0''':包含 (原始) 元初源碼的壓縮後封存檔的完整 URL,即上游發行該源碼的位置。「<code>Source</code>」與「<code>Source0</code>」同義。如果你給的是完整的 URL (而且你也該這麼做),會用其基礎名稱去查找 <code>SOURCES</code> 目錄。如果可以的話,請用 <code>%{name}</code> 和 <code>%{version}</code> 替換嵌入 URL 中,這樣只要有所變動時都會自動對應。下載源碼檔案時記得[[Packaging:Guidelines#Timestamps|保留時間戳記]]。如果不只有一份源碼封存檔,請用 <code>Source1</code>、<code>Source2</code> 等等依序羅列。如果你要在元初來源外還要再加一些全新的檔案,請將它們列在元初來源''之後''。任何你製作出的 SRPM 都會包入這些來源的副本,除非你有另外直接指定那就例外。請見 [[Packaging/SourceURL|Source URL]] 瞭解更多特殊案例的資訊 (例如:revision control 修訂控制)
* Patch0: The name of the first patch that you will apply to the source code.  If you need to patch the files after they've been uncompressed, you should edit the files, save their differences as a "patch" file in your ~/rpmbuild/SOURCES directory.  Patches should make only one logical change, so it's quite possible to have multiple patch files.
* '''Patch0''':第一個要套用到源碼上的修補檔 (patch) 名稱。如果你需要在檔案解壓縮之後對一些檔案作修補,你應該要先編輯檔案並將兩者間的差異儲存成「patch」檔,然後放在 <code>~/rpmbuild/SOURCES</code> 目錄下。一個 Patch 應該只做一種目的更動 (logical change),所以正常來講可能會有多個 patch 檔。
* BuildRoot: This is where files will be "installed" during the "%install" process (which happens after the %build compilation process).  Normally you should just leave this line alone; under the usual Fedora setup, this will be a macro that will create a new special directory under /var/tmp. Newer versions of RPM will ignore this value, and instead place the build root in "%{_topdir}/BUILDROOT/".
* '''BuildArch''':如果你要打包的檔案並不依賴任何架構 (例如:shell 指令稿、資料檔等),那麼請用「<code>BuildArch: noarch</code>」。二進位檔 RPM 的架構就會跟著變成「<code>noarch</code>」。
* BuildRequires: A comma-separated list of packages required for building (compiling) the program.  These are ''not'' automatically determined, so you need to include ''everything'' needed to build the program.  There are a few packages that are so common in builds that you don't need to mention them, such as "gcc"; see the [[Packaging/Guidelines| Packaging Guidelines]] for the complete list of the packages you may omit.  You can also specify minimum versions, if necessary, like this: "ocaml >= 3.08". You can have more than one line of BuildRequires (in which case they are all required for building).  If you need file /EGGS, you can get its package by running "rpm -qf /EGGS"; if EGGS is a program, you determine its package quickly by running "rpm -qf `which EGGS`".  Try to specify only the minimal set of packages necessary to properly build the package, since each one will slow down a "mock"-based build (e.g., try to use sed instead of perl if you don't really need perl's abilities).  Watch out: Some applications permanently disable functions if their package isn't detected during the build; in those cases you may need to include those additional packages.  If you have trouble figuring out this list, the "auto-br-rpmbuild" command (from the auto-buildrequires package) may be helpful.
* '''BuildRoot''':這是 %install 程序 (%build 程序之後) 期間檔案要「安裝」到的地方。這一項目前在 Fedora 中是多餘的,只有 EPEL5 還需要它。預設情況下,建置根基目錄放在「<code>%{_topdir}/BUILDROOT/</code>」。
* Requires: A comma-separate list of packages that are required when the program is installed.  Note that the list of packages for ''Requires'' (what's required when installing/running) and ''BuildRequires'' (what's required to build the binary RPM) are independent; a package may be in one list but not the other, or it could be in both.  The dependencies of binary packages are in many cases automatically detected by rpmbuild, so it is often the case that you don't need to specify the ''Requires'' tag at all. But if you want to highlight some specific packages as being required, or require a package that rpm can't detect should be required, then add it here.
* '''BuildRequires''':建置 (編譯) 該程式所需要的軟體包列表,以半形逗號分隔各個項目。這個欄位可以 (而且通常) 多列重複。這些依賴項目 ''不會'' 自動判定,所以你需要納入建置該程式所需要的 ''所有'' 項目。[[Packaging/Guidelines#Exceptions_2|有些常見軟體包可以省略]],例如 <code>gcc</code>。如果有必要,你也可以指定最低要求版本 (例:"<code>ocaml >= 3.08</code>")。如果你需要 <code>/EGGS</code> 檔案,可以執行「<code>rpm -qf /EGGS</code>」來判斷它的所屬軟體包。請維持最低限度的依賴 (例如你不需要 perl 的功能,那就用 <code>sed</code> 而不需用到 <code>perl</code>),但請注意有些應用程式若沒有某功能相關的依賴項目時,會永久停用該功能;這些情況中你可能需要納入額外的軟體包。 {{package|auto-buildrequires}} 軟體包可能會有所用處。
* %description - A longer, multi-line description of the program.  Use American English. All lines must be 80 characters or less. "Blank lines are assumed to separate paragraphs. Some graphical user interface installation programs will reformat paragraphs...  (lines that) start with whitespace, such as a space or tab, will be treated as preformatted text and displayed as is, normally with a fixed-width font." (per the [http://docs.fedoraproject.org/drafts/rpm-guide-en/ch09s03.html RPM Guide]).
* '''Requires'':當程式安裝之時所需要的軟體包清單,請以半形逗號隔開各個項目。請注意 BuildRequires 標籤應列出的是建置二進位檔 RPM 的項目清單,而 Requires 標籤列出的是安裝/執行該程式所需的項目清單;一個軟體包可以放在其中一個清單,或同時兩個清單中。在許多情況下,<code>rpmbuild</code> 會自動偵測依賴項目,所以不見得需要 Requires 標籤。然而,你可能會希望特別標明那些軟體包是需要的,或是哪些軟體包沒自動偵測到而你需要手動標明。
* %prep - Script commands to "prepare" the program, that is, to uncompress it so that it will be ready for building (compiling).  Typically this is just "%setup -q" or some variation of it; a common variation is "%setup -q -n NAME" if the source file unpacks into NAME. See the "%prep" section below for more.
* '''%description''':長篇的、跨多列的程式描述。請使用美式英文。每一列都必須小於等於 80 個字元。空白列表示新段落的開始。有些圖形使用者介面安裝程式會重新格式化段落;以空白起頭的列會被視為已預先格式化過的格式,會如其所述表現,顯示時一般採用等寬字型。請見 [http://docs.fedoraproject.org/drafts/rpm-guide-en/ch09s03.html RPM Guide].
* %build - Script commands to "build" the program, that is, 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.
* '''%prep''':「準備」程式的指令稿指令 (例如:將之解壓縮),這樣才能建置程式。一般這只是「<code>%autosetup</code>」。如果源碼檔案要解開放到 <code>NAME</code> 的話,常見的變化形式是「<code>%autosetup -n NAME</code>」。請見下方的 %prep 小節瞭解更多資訊。
* %check - Script commands to self-test the program. This is run after %build and before %install, so you should 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.  This isn't documented in many places.
* '''%build''':「建置」程式的指令稿指令 (例如:編譯它),準備完成以便後續安裝。程式應該有附上如何執行此步驟的指示。請見下方 %build 小節來瞭解更多資訊。
* %install - Script commands to "install" the program.  The commands should copy the files from the "build directory" %{_builddir} (which would be under ~/rpmbuild/BUILD) into the buildroot directory, %{buildroot} (which would normally be under /var/tmp). See the "%install" section below for more.
* '''%install''':「安裝」程式的指令稿指令。指令應該要將檔案從 <code>BUILD</code> 目錄 <code>%{_builddir}</code> 複製到建置根基目錄 <code>%{buildroot}</code> 中。請見下方的 %install 小節瞭解更多細節。
* %clean - instructions to clean out the build root. Typically:
* '''%check''':「測試」程式的指令稿指令。這是在 %install 程序後執行,所以如果你需要此區段的話,請將它放在該處。通常它僅包含「<code>make test</code>」或「<code>make check</code>」。這要和 %build 分開,這樣人們才能在需要的時候略過自我測試。
* '''%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''':軟體包的變動。請使用上述格式。'''請「不要」把軟體的變更記錄放在這裡。這裡是 RPM 自身的變更記錄。'''
* ExcludeArch: If the package does not successfully compile, build or work on an architecture, then those architectures should be listed in the spec in an ExcludeArch tag.
* '''ExcludeArch''':如果軟體包無法在某特定架構上成功編譯、建置或運作,請在此標籤下列出這些架構。* 你可以加入些代碼區段,這樣代碼會在軟體包於真實系統上安裝或移除時執行 (與之相反的是只執行 %install 指令稿,它只會作虛擬安裝 (pseudo-install),安裝到建置根基目錄中)。這些代碼稱之為「scriptlet」指令稿片段,他們通常以軟體包中的資訊更新執行中的系統。請見下方的「scriptlet」瞭解更多細節。
* 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.


Don't use the tags "Packager" or "Vendor".  Don't use "Copyright" - use "License" instead.
RPM 也支援從單一 SPEC 檔製作出多個軟體包 (稱為 [[How_to_create_an_RPM_package#Subpackages|子軟體包]]) 的功能,例如 <code>name-libs</code> 和 <code>name-devel</code> 等軟體包。
Don't create a "relocatable" package - they don't add value in Fedora yet they make things more complicated.


RPM supports subpackages, that is, a single spec file can generate many
{{admon/caution|請'''「不要」'''使用這些標籤|
binary packages.  For example, if the documentation is very large, you might generate
* Packager
a separate "-doc" subpackage.
* Vendor
See below for more.
* Copyright}}


=== %prep section ===
請'''不要'''製作「relocatable」可重新變換位置的軟體包;他們不會幫 Fedora 加值,反而把事情搞得更複雜。
The "%prep" section 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 section 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.
== SPEC 檔區段詳解 ==


The new RPM 4.4.2.x series adds two new macros, %{patches} and %{sources}, so you can do things like:
=== %prep 區段 ===
 
%prep 區段描述的是如何解開壓縮後軟體包的方法,這樣才能拿來建置。一般而言,這包含「<code>%autosetup</code>」指令。另外,你可以使用「<code>%setup</code>」和「<code>%patch</code>」指令搭配參照 Source0 (與 Source1 等) 條目。請見 [http://rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html Maximum RPM 一文中的 %setup and %patch 小節] 瞭解更多細節。
 
RPM 4.4.2 起可以使用 %{patches} %{source} 巨集,若你有大量補丁或來源清單,以及 %autosetup 效果並非你所想要的話會很好用,例如你可以這樣做:
  for p in %{patches}; do
  for p in %{patches}; do
...
    ...
  done
  done
These new macros can 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 section: %setup command ====
然而請記住,使用上述功能,會讓你的 SPEC 和 RHEL 以及其他 RPM 散布版中所使用的 RPMS 不相容。
 
==== %prep 區段:%autosetup 指令 ====
 
「<code>%autosetup</code>」指令會解開來源軟體包。可用選項包括:
* '''<code>-n</code> ''name'' ''' :如果 Source tarball 所要解開成的目錄名稱與 RPM 名稱不同,這個切換開關用來指定正確的目錄名稱。舉例來說,如果 tarball 要解開成 FOO 目錄,則使用「<code>%autosetup -n FOO</code>」。
* '''<code>-c</code> ''name'' ''' :如果 Source tarball 需要解開成多個目錄,而非單一個目錄時,這個切換開關可以用來建立名為 ''name'' 的目錄,然後將內容解開放在裡面。


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:
如我你改用「<code>%setup</code>」指令,則通常使用 ''<code>-q</code>''' 來抑止不必要的輸出。
* -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
如果你打算解開多份檔案,[http://rpm.org/max-rpm-snapshot/s1-rpm-inside-macros.html 有更多 %spec 選項可以用],這在你製作子軟體包時會很有用 (請見下方)。比較重要的有:
[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:


{|
{|
|-
|-
| -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> || 在切入目錄後,只解開指定數字的 Source 目錄 (例:「<code>–a 0</code>」代表 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> ||  在切入目錄前,只解開指定數字的 Source 目錄 (例:「<code>–b 0</code>」代表 Source0)。
|-
|-
| -D || Do not delete the directory before unpacking.
| <code>-D</code> || 在解開之前不要刪除目錄。
|-
|-
| -T || Disable the automatic unpacking of the archives.
| <code>-T</code> || 停用自動解開封存檔。
|}
|}


==== %prep section: %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>%autosetup</code>」指令,就不需要下列的手動補丁管理程序。如果你的需求很複雜,或是需要和 EPEL 相容,還是可能需要用到。「<code>%patch0</code>」指令會套用 Patch0 (而 %patch1 會套用 Patch1,依此類推)。補丁是對來源程式碼做出必要修改使之符合打包規約的正常作法。常用的「<code>-pNUMBER</code>」選項會傳遞引數給 <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.
補丁的檔名通常看起來像是「<code>telnet-0.17-env.patch</code>」這樣,命名格式依循「<code>%{name} - %{version} - REASON.patch</code>」(不過有時候會省略 version 版本)。補丁檔通常是「<code>diff -u</code>」的成果;如果你是從if you do this from the subdirectory of <code>~/rpmbuild/BUILD</code> 的子目錄執行這個指令的,那麼你之後便不必指定 <code>-p</code> 層級。


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:
這是為單一檔案製作補丁的典型程序:
  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:
如果需要修改許多檔案,有個簡單的方法,就是複製 <code>BUILD</code> 下的整個子目錄,然後執行子目錄的 diff。在你切入「<code>~rpmbuild/BUILD/NAME</code>」目錄後,執行以下指令:
  cp -pr ./ ../PACKAGENAME.orig/
  cp -pr ./ ../PACKAGENAME.orig/
  ... many edits ...
  ... 修改許多檔案 ...
  diff -u ../PACKAGENAME.orig . > ~/rpmbuild/SOURCES/''NAME''.''REASON''.patch
  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 package) to create a patch with the differences.  Do "man gendiff" for more information.
如果你想在一個補丁中編輯多重檔案,你也可以在編輯之前用同樣的檔名結尾「<code>.orig</code>」來複製原始檔案。然後,你可以用「<code>gendiff</code>」(在 <code>rpm-build</code> 軟體包中) 製作檔案差異的補丁檔。


Try to ensure that in your patch the "context" matches exactly.
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 it unique.
試著確保你的路徑完全符合情境。預設的「fuzz」值是「<code>0</code>」,代表比對要求完全相同。你可以加入「<code>%global _default_patch_fuzz 2</code>」來轉換成舊版 Fedora RPM 版本所採用的值,但我們建議你應盡量避免這樣做。
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 section: 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):
如 [[Packaging/PatchUpstreamStatus]] 所詳述的,SPEC 檔中所有的補丁上方都要有個註解描述它的目前上游狀態為何。如果這是 Fedora 特別需要的補丁,你應該提及為何它如此特別。Fedora 專案致力不與上游分歧;請見 [[PackageMaintainers/WhyUpstream]] 瞭解此事的重要性。
  cp -p %SOURCE1 .


=== %build section ===
==== %prep 區段:未修改的檔案 ====


The "%build" section is sometimes complicated; here you configure and compile/build the files to be installed.
有時候,來源的一個或多個檔案並不需要解壓縮。你可以「prep」準備這些項目到建置目錄中,如 (這裡的 <code>SOURCE1</code> 代表對應的來源檔):
cp -p %SOURCE1 .


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}).
=== %build 區段 ===


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:
「%build」區段偶爾會有點複雜;在這個區段中你設置組態,並編譯/建置用來安裝的檔案。
 
許多程式採用 GNU <code>configure</code> 的方法 (或據此變化)。預設情況下,檔案會安裝到前綴為「<code>/usr/local</code>」的路徑下,這對解開檔案的存放來說相當合理;但是,現在你是要打包程式,所以請將路徑前綴改成「<code>/usr</code>」。函式庫則應該視架構而定,安裝到 <code>/usr/lib</code> 或 <code>/usr/lib64</code> 中。
 
由於 GNU <code>configure</code> 非常常見,可以自動使用「<code>%configure</code>」巨集來喚起正確的選項 (例如,將前綴路徑改成 <code>/usr</code>)。有些變化也多能作用:
   %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:
若要凌駕 makefile 變數,請將它作為參數傳遞給 <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].
至於其他深入資訊,請參見 [http://sourceware.org/autobook/ "GNU autoconf, automake, and libtool"] 以及 [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.
也有些程式使用 <code>cmake</code>。請參見 [[Packaging/cmake]]


If you include some self-tests (and that's a good idea), put them in a separate "%check" section 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.
=== %install 區段 ===


=== %check section ===
本區段內含「安裝」該程式用的指令稿指令,即從 <code>%{_builddir}</code> 資料夾複製相關檔案到 <code>%{buildroot}</code> 中 (通常代表從 <code>~/rpmbuild/BUILD</code> 複製到 <code>~/rpmbuild/BUILDROOT</code>),並且根據需要在 <code>%{buildroot}</code> 中新建資料夾。


The "%check" section does testing, often it's "make test".
有些術語的名稱可能讓人會錯意:
This is not documented in many other sources of RPM info.
* 「建置目錄 build directory」,也稱為 <code>%{_builddir}</code>,實際上和「建置根基 build root」,又稱為 <code>%{buildroot}</code>,是不一樣的資料夾。我們會在前者中編譯,而要打包的檔案則從前者複製到後者去。
* 在 %build 區段中,目前的目錄起始於 <code>%{buildsubdir}</code>,是 %prep 階段中在 <code>%{_builddir}</code> 下建立的子資料夾。這個資料夾名稱通常會是 <code>~/rpmbuild/BUILD/%{name}-%{version}</code> 這樣。
* %install 區段在終端使用者安裝二進位 RPM 軟體包時並 '''不會''' 執行 ;事實上 %install 區段只有在製作軟體包時才會執行。


=== %install section ===
一般來說,這裡執行的是「<code>make install</code>」之類的:
%install
rm -rf %{buildroot} # redundant except for RHEL 5
%make_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.
理想上您應該使用 %make_install,對於支援的程式來說,它等同於 [http://www.gnu.org/prep/standards/html_node/DESTDIR.html <code>DESTDIR=%{buildroot}</code>],因為它會重新導引檔案安裝到指定的目錄中,也就是我們在 %install 區段中預期發生的事。


'''Watch out''': Some of the terminology is very misleading:
如果程式不支援 <code>DESTDIR</code>(且僅在有此情況之下),您有許多 (下方所列) 方式可以避開問題:
* 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 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}.
* 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}.


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:
* 修補 makefile 來讓它支援 <code>DESTDIR</code>。在 <code>DESTDIR</code> 中視需要建立目錄,並提交該 patch 補丁給上游。
* 使用「<code>%makeinstall</code>」巨集。這個方法可能有效,但也可能導致些微失敗。該巨集會展開成「<code>make prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ... install</code>」,而可能導致有些程式無法正常運作。請在 <code>%{buildroot}</code> 下視需要建立目錄。
* 考慮使用 <code>auto-destdir</code> 軟體包。它需要「<code>BuildRequires: auto-destdir</code>」、並將「<code>make install</code>」修改成「<code>make-redir DESTDIR=%{buildroot} install</code>」。這只在安裝僅使用到特定常用指令來安裝檔案時才能作用,例如 <code>cp</code> 和 <code>install</code>。
* 手動執行安裝。這可能牽涉到在 <code>%{buildroot}</code> 下建立必要的目錄,並從 <code>%{_builddir}</code> 複製檔案到 <code>%{buildroot}</code> 裡去。要特別注意更新,通常會有新檔名或修改過檔名。此程序的範例:
  %install
  %install
  rm -rf %{buildroot}
  rm -rf %{buildroot}
  make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install
  mkdir -p %{buildroot}%{_bindir}/
cp -p mycommand %{buildroot}%{_bindir}/


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.
=== %check 區段 ===


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:
如果可以自我測試的話,將它們納入其中的話會是個好主意。他們應該放在 %check 區段中 (緊接在 %install 區段之後,因為應該測試 %buildroot 中的檔案) 而不是放在 %build 區段中,這樣才能在必要時刻輕易略過。
* 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.
 
* 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>).
通常,此區段包含:
* 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.
  make test
* 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:
 
%install
有時候也可以用:
  rm -rf %{buildroot}
  make check
mkdir -p %{buildroot}%{_bindir}/
 
cp -p mycommand %{buildroot}%{_bindir}/
請探索一下 Makefile 的用法,並選擇適當的方式。


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:
=== %files 區段 ===
make INSTALL="install -p" CP="cp -p" DESTDIR=%{buildroot} install


=== %files section ===
此區段宣告哪些檔案與目錄是由該軟體包擁有,還有哪些檔案與目錄會放到二進位檔 RPM 中。
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.


==== %files Basics ====
==== %files 基礎 ====


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".
<code>%defattr</code> 會設定預設的檔案權限,通常可以在 <code>%files</code> 區段的開頭看到使用。請注意到,如果不需要修改權限的話,那就不再需要用到它。它的使用格式為:
%defattr(<file permissions>, <user>, <group>, <directory permissions>)
第四個參數通常會省略。通常我們會這樣用 <code>%defattr(-,root,root,-)</code>,其中「<code>-</code>」代表預設權限。


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/bin/mycommand, then your %files section ''could'' simply say:
您應該列出該軟體包擁有的所有檔案和目錄。請盡量用巨集來取代目錄名稱,您可以到 [[Packaging:RPMMacros]] (舉例:使用 <code>%{_bindir}/mycommand</code> 取代 <code>/usr/bin/mycommand</code>) 來查看巨集表。如果起頭樣式為「<code>/</code>」(或從巨集擴展而來),則從 <code>%{buildroot}</code> 目錄取用。否則,將假定檔案位在目前的目錄中 (例如:在 <code>%{_builddir}</code> 內部,例如您想要納入的文件檔)。若您的軟體包僅安裝單一檔案如 <code>/usr/sbin/mycommand</code>,則 <code>%files</code> 區段可以像這樣簡單:
  %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:
若要讓您的軟體包較不受上游改動而影響,請依這種樣式比對來宣告該軟體包擁有的目錄下所有檔案:
  %{_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.
若要納入單一目錄:
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 copying 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.
請注意,<code>%{_bindir}/*</code> 並不會宣稱此軟體包擁有 <code>/usr/bin</code> 目錄,而只有包含其下的檔案。如果您列出一個目錄,則您正試圖宣稱該軟體包擁有這個目錄,以及該目錄內的所有檔案與子目錄。所以,請 '''不要''' 列出 <code>%{_bindir}</code>,而且要小心處理那些可能和其他軟體包共享的目錄。


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.
如果有下列情形可能引發錯誤:
* 試圖樣式比對,卻沒比對到任何檔案或目錄
* 重複列出或重複比對到某個檔案或目錄
* 沒有列出 <code>%{buildroot}</code> 下的某個檔案或目錄


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.)
您也可以使用 <code>%exclude</code> glob 來從前個比對中排除檔案。這對於想用不同的樣式比對來將幾乎全部檔案納入其中時會很有用,但是請注意如果沒有比對到任何東西也會造成失敗。


==== %files prefixes ====
==== %files 前綴字 ====
You may need to add one or more prefixes to a %files entry (if more than one, use a space to separate them).
您可能需要在 <code>%files</code>  區段的內容中加入一個或多個前綴字;請用空格隔開。請見 [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).
通常,「<code>%doc</code>」用來列出 <code>%{_builddir}</code> 內,但未複製到 <code>%{buildroot}</code> 中的文件檔。通常包括 <code>README</code> 和 <code>INSTALL</code> 檔。它們會放到 <code>/usr/share/doc</code> 下適當的目錄中,而 <code>/usr/share/doc</code> 的擁有權不必宣告。


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.
'''注意:''' 如果有指定 <code>%doc</code> 條目,rpmbuild < 4.9.1 在安裝之前會將檔案安裝到其中的 doc 文件目錄移除。這代表已經放到裡面去的檔案,例如,在 <code>%install</code> 區段中安裝的檔案,會被移除,因此最終不會出現在軟體包中。如果您想要在 <code>%install</code> 區段中安裝一些檔案,請將它們安裝到建置目錄 (是 build dir,而不是建置根基 build root) 內的暫時鄰架目錄 (temporary staging directory) 中,例如 <code>_docs_staging</code>,接著將之納入 <code>%files</code> 列表中,如 <code>%doc _docs_staging/*</code> 這樣。


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).
組態檔應該要放在 <code>/etc</code> 中,一般會這樣指定 (可以確保使用者所作的更動不會在更新時被覆蓋)
%config(noreplace) %{_sysconfdir}/foo.conf
如果更新程序用的是無法向前相容的組態格式 (non-backwards-compatible configuration format),則應這樣指定:
%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>」可以用來指派更精細的權限控制,而「<code>-</code>」代表是用預設值:
%attr(0644, root, root) FOO.BAR


If a file is in particular natural language, use %lang to note that. E.G.:
如果檔案是以特定的自然語言撰寫,請使用 <code>%lang</code> 來標註:
  %lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*
  %lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*


Some documentation claims that %license and %readme are valid prefixes; they are ''not'' valid in Fedora.  Use %doc instead.
使用到區域語言 (Locale) 檔案的程式應該遵循 [[Packaging:Guidelines#Handling_Locale_Files|處理 i18n 檔的建議方法 (英)]]:
* 在 <code>%install</code> 步驟中找出檔名:<code> %find_lang ${name}</code>
* 加入必要的建置依賴: <code>BuildRequires: gettext</code>
* 使用找到的檔名: <code>%files -f ${name}.lang</code>


==== %files and Filesystem Hierarchy Standard (FHS) ====
以下前綴字在 Fedora 中 '''無效''':<code>%license</code> 和 <code>%readme</code>。


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}".
==== %files 與檔案系統階層標準 (Filesystem Hierarchy Standard, FHS) ====


You shouldn't be installing files under /usr/local; that is where ''unpackaged'' files go.
您應該遵守 [http://www.pathname.com/fhs/ 檔案系統階層標準 (FHS)]。執行檔應放在 <code>/usr/bin</code>,全域組態檔放進 <code>/etc</code>,函式庫放到 <code>/usr/lib</code> (或 <code>/usr/lib64</code>) 等等。只有一項例外:一般不該給使用者或管理員執行的執行檔,應該放到 <code>/usr/libexec</code> 中的子資料夾中,資料夾名稱為 <code>%{_libexecdir}/%{name}</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.
請 '''不要''' 把檔案安裝到 <code>/opt</code> 或 <code>/usr/local</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 ====
不幸地,許多程式預設情況下並不遵守 FHS。尤其是,系統架構獨立的函式庫被放到 <code>/usr/lib</code> 而非 <code>/usr/share</code> 之中。前者是給系統架構依賴的函式庫使用,後者才是給系統架構獨立的函式庫運用;這代表不同 CPU 架構的系統都能共享 <code>/usr/share</code> 資料夾。Fedora 中也是有一些例外 (例如 Python 和 Perl),然而 Fedora 比起其他散佈版來說更嚴格遵守標準規範,<code>rpmlint</code> 一般會在你將 ELF 以外的檔案放進 <code>/usr/lib</code> 內時提出抱怨。


Here's a simple example of a %files section:
==== %files 範例 ====
 
以下為 %files 區段的簡單範例:
  %files
  %files
%defattr(-,root,root,-)
  %doc README LICENSE
  %doc README LICENSE
  %{_bindir}/*
  %{_bindir}/*
  %{_sbindir}/*
  %{_sbindir}/*
  %{_datadir}/%{name}/
  %{_datadir}/%{name}/
%config(noreplace) %{_sysconfdir}/*.conf


=== 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 transactionSee [[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:
您可以列出任兩個二進位軟體包的重複檔案,做法爲:
cd ~/rpmbuild/RPMS/ARCH # 請將 "ARCH" 替換為您的系統架構
rpm -qlp PACKAGE1.*.rpm | sort > ,1
rpm -qlp PACKAGE2.*.rpm | sort > ,2
  comm -12 ,1 ,2
 
=== 小指令稿 (Scriptlet) ===
 
當終端使用者在安裝 RPM 時,您可能想要執行一些指令。這可以透過小指令稿完成。請見 [[Packaging/ScriptletSnippets]]
 
小指令稿可以:
* 在軟體包安裝之前 ('''<code>%pre</code>''') 或之後 ('''<code>%post</code>''') 執行
* 在軟體包移除之前 ('''<code>%preun</code>''') 或之後 ('''<code>%postun</code>''') 執行
* 在處理事項的開頭 ('''<code>%pretrans</code>''') 或結尾 ('''<code>%posttrans</code>''') 執行
 
舉例來說,每一會在任何 dinamic linker 預設路徑中儲存共享函式庫檔案的二進位檔 RPM 軟體包,都必須在 <code>%post</code> 和 <code>%postun</code> 中呼叫 <code>ldconfig</code>。如果該軟體包有多個附帶函式庫的子軟體包,則每個軟體包也都應該執行相同的動作。
  %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.
如果僅執行單一指令,則「<code>-p</code>」選項會執行相接的指令但不會喚起 shell。然而,若有許多指令時,請省去這個選項,並在其下納入 shell 指令。
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.
如果你在小指令稿中有執行任何程式,你就必須以「<code>Requires(CONTEXT)</code>」(例: <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>、和 <code>%postun</code> 提供了 <code>$1</code> 引數,表示動作完成之後系統上留下的此名稱之軟體包有幾個。請不要拿這個值來比較是否等於 <code>2</code>,而是比較是否大於或等於 <code>2</code>。至於 <code>%pretrans</code> 和 <code>%posttrans</code>,<code>$1</code> 的值則恆為 <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:


舉例來說,如果軟體包安裝了一份 info manual (資訊手冊),那麼可以用 <code>info</code> 軟體包提供的 <code>install-info</code> 來更新資訊手冊索引。首先,我們不保證 <code>info</code> 軟體包總會存在,除非我們明確宣告它是必備的部分;再來,我們不想要在 <code>install-info</code> 失敗之時讓軟體包的執行動作完全失敗:
  Requires(post): info
  Requires(post): info
  Requires(preun): info
  Requires(preun): info
Line 526: Line 522:
  fi
  fi


Another scriptlet-like abilility are ''triggers''.  You can define triggers for when ''other'' packages
還有一件安裝資訊手冊時相關的小瑕疵。<code>install-info</code> 指令會更新資訊目錄,所以我們應該要在 <code>%install</code> 區段中刪掉 %{buildroot} 中無用的空目錄:
are installed or uninstalled. See ''Maximum RPM'' for more information about triggers.
 
  rm -f %{buildroot}%{_infodir}/dir
=== Macros ===


Spec files may contain "macro" references (text beginning with "%"), which are replaced with other values.
另一個類似小指令稿的能力是「triggers」(觸發器),可以在其他軟體包已安裝或已移除之時,為你的軟體包執行一些動作。請見 [http://rpm.org/api/4.4.2.2/triggers.html RPM Triggers]。
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
=== 巨集 (Macro) ===
[[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:
巨集是 <code>%{string}</code> 這類寫法的文字。典型的巨集有:


{|
{|
! Macro !! Typical Expansion !! Meaning
! 巨集 !!典型擴展 !! 意義
|-
|-
| %{_bindir} || /usr/bin || Binary directory (where executables are usually stored)
| <code>%{_bindir}</code> || <code>/usr/bin</code> || 二進位檔資料夾 (Binary directory):執行檔通常存放的位置。
|-
|-
| %{_builddir} || ~/rpmbuild/BUILD || Build directory; files are compiled a subdirectory of the build directory.  See %buildsubdir.
| <code>%{_builddir}</code> || <code>~/rpmbuild/BUILD</code> || 建置資料夾 (Build directory):檔案放在建置目錄下的子目錄中編譯。請見 <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):在 <code>%install</code> 階段中的檔案「安裝」之處,會將 <code>%{_builddir}</code> 子目錄下的檔案複製到 <code>%{buildroot}</code> 的子目錄之下。(過去,<code>%{buildroot}</code> 所採用的位置是「/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):在 <code>%build</code> 階段中檔案會在 <code>%{_builddir}</code> 的子目錄中編譯。這個位置會在 <code>%autosetup</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> || fedora 發行版號 (例:「<code>{{FedoraVersion}}</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> || || 軟體包的名稱,由 Name: tag 決定
|-
|-
| %{_sbindir} || /usr/sbin
| <code>%{_sbindir}</code> || <code>/usr/sbin</code>
|-
|-
| %{_sharedstatedir} || /usr/com
| <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> || || 軟體包版本,由 Version: tag 決定
|}
|}


To see more about macros you
您可以查看 <code>/etc/rpm/*</code> 和 <code>/usr/lib/rpm</code>、甚至是 <code>/usr/lib/rpm/macros</code> 以進一步瞭解巨集。或是用 <code>rpm --showrc</code> 來顯示 RPM 運用這些巨集時所採用的值 (會根據 <code>rpmrc</code> 與巨集組態檔而有所變動)。
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
您可以利用 %global 來定義自己的巨集值,但是請確定在使用巨集之前先已定義過。(巨集在定義之時也可以指涉 (refer to) 其他巨集。)
can refer to other macros.  For example:
範例:
  %global myvalue 50
  %global date 2012-02-08


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:
請用 <code>rpmbuild</code> 的「<code>-E</code>」選項來尋找巨集在 SPEC 檔中代表的值:
  rpmbuild -E '%{_bindir}' myfile.spec
  rpmbuild -E '%{_bindir}' myfile.spec


[[Packaging/RPMMacros]] has more information on macros, as does
也請參見 [[Packaging/RPMMacros]] [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 ===
=== 其他標籤 (tag) ===


We noted the "Requires" and "BuildRequires" tags earlier.
除了 Requires BuildRequires 標籤之外,你還可以使用以下這些控制依賴關係:
There are a few other tags for controlling dependencies:
* '''Provides''':列出此軟體包提供的虛擬軟體包名稱。例如,可能有個 <code>foo</code> 軟體包需要來自其他程式的「bar」功能;若有許多軟體包可以滿足該需求,則這些軟體包可以指定「<code>Provides: bar</code>」,而「<code>foo</code>」軟體包則可以指定「<code>Requires: bar</code>」。你也可以使用 [http://dailypackage.fedorabook.com/index.php?/archives/6-Wednesday-Why-The-Alternatives-System.html "alternatives" 系統],但是若同個系統中有多位使用者,不同人可能希望使用不同的預設值,此時請避免使用它,畢竟這些設定屬於系統全域設定。請用「<code>rpm -q --provides PACKAGENAME</code>」來查看指定的軟體包提供那些東西。一些 Fedora 中虛擬軟體包的範例:
Provides, Obsoletes, Conflicts, and BuildConflicts.
** MTA:用作郵件傳輸代理 (mail transport agent, MTA),例如 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): 用作 latex
** ''MTA'' : Used for mail transport agents, such as sendmail.
* '''Obsoletes''':當這個軟體包安裝時移除另一個指名的軟體包。當軟體包名稱更換之時,或是用該軟體包完全取代另一個不同的軟體包之時可以使用。
** ''tex(latex)'' : Used for latex
* '''Conflicts''':表示無法與此軟體包同時安裝的其他軟體包。如果可以請避免使用這個標籤。請見 [[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''':表示在建置此軟體包之時無法安裝的軟體包。如果可以請避免使用這個標籤。
* "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:
若要處理不同的系統架構,有兩種標籤可以使用:
* '''ExcludeArch''':排除此軟體包無法建置的系統架構。例如:
  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''':僅納入指定的系統架構。除非絕對正確,否則請避免使用。
可用的系統架構列在 [[Architectures]] 中。
 
=== 子軟體包 (或稱細分包,Subpackage) ===


=== Subpackages ===
一份 SPEC 檔可以定義多份二進位檔軟體包。換句話說,一個內含一份 SPEC 檔的 SRPM 檔可能製作出許多 RPM 檔來。請注意到這依然只會有一道製作 (%prep、%build、%install 等) 程序。 <code>name-doc</code> 和 <code>name-devel</code> 為常見的文件檔和開發檔子軟體包。
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:
請使用 <code>%package</code> 巨集指令來定義子軟體包:
  %package sub_package_name
  %package subpackage_name


By default, the subpackage name is PACKAGE_NAME, "-", SUBPACKAGE_NAME; you can
在每個 <code>%package</code> 指令之後,請列出該子軟體包的數個標籤 (tag)。這應該至少包括 Summary 和 Group 標籤、以及 <code>%description subpackage_name</code> 和 <code>%files subpackage_name</code> 指令:
use "-n" to override this and make a new name:
%package -n new_sub_package_name


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.
For the directives, if you used "-n" with %package,
you'll need it again for these directives.
You need to specify the name for the other directives, e.g., %pre and %post,
if you use them in the subpackage.


[http://docs.fedoraproject.org/drafts/rpm-guide-en/ch10s04.html See the RPM Guide section on subpackages] for more information.
預設情況下,如果該軟體包的名稱為「<code>foo</code>」而子軟體包名稱為「<code>bar</code>」,則子軟體包成果則會是「<code>foo-bar</code>」。你可以利用「<code>-n</code>」選項 (但如果你在這裡特別指定的話,你也需要在所有其他的指令中用到這道指令) 來凌駕原先的規則:
%package -n new_subpackage_name


=== Conditionals ===
[http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch10s04.html 請見 RPM Guide 針對子軟體包所寫的小節]瞭解更多資訊。


You can insert conditional statements.
=== 條件判斷 (Conditional) ===
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:
反面 (negated) 的論述版本為:
  %ifnarch ARCHITECTURE_NAME
  %ifnarch ARCHITECTURE_NAME
or the more general conditional:
或更一般的條件判斷式:
  %if TRUE_OR_FALSE
  %if TRUE_OR_FALSE


There is an optional "%else" section; all of these are closed with "%endif".
也有個可選擇性使用的「<code>%else</code>」區段;以上這些全都必須以「<code>%endif</code>」作結尾。


=== 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
有許多應用程式專門規約可以協助你 (例:專門的程式語言、應用程式、函式庫、建置系統等)。大多都列在
[[Packaging/Guidelines#Application_Specific_Guidelines|Application Specific Guidelines of Packaging/Guidelines]].  Examples of application-specific guidelines are those for:
[[Packaging/Guidelines#Application_Specific_Guidelines|應用程式專用打包規約/規約 (英)]] 之中。一些應用程式專門規約的例子有:
* [[Packaging:Cmake|Cmake]]
* [[Packaging:Cmake|Cmake]]
* [[Packaging:Emacs|Emacs]]
* [[Packaging:Emacs|Emacs]]


Failing that, some other ways of finding application-specific help are:
如果上述的資訊都沒有涵括到,還有一些可以幫助你找到應用程式專用協助的方法:
* The 'SEARCH' command on Fedoraproject.org.
* Fedoraproject.rog 上的「SEARCH」指令。
* [[PackagingDrafts]]
* [[PackagingDrafts]]
* A [[SIGs|Special Interest Group (SIG)]]
* [[SIGs|Special Interest Group (SIG)]]
* [http://fedoraproject.org/wiki/Special:PrefixIndex/Packaging Wiki pages prefixed with 'Packaging']
* [[Special:PrefixIndex/Packaging|名稱以「Packaging」起頭的 Wiki 頁面]]


=== Miscellaneous hints ===
=== 其他注意事項 (Miscellaneous hints) ===


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:
[[Packaging/FrequentlyMadeMistakes]] 有列出常見錯誤的相關資訊。[[PackageMaintainers/Packaging Tricks]] 則有列出一些建議、以及具爭議性的技巧。
 
請試著撰寫你的 SPEC 檔,盡可能讓上游發行新版本時一切都能水到渠成,使你除了要改版本號並刷新來源檔案外,都不必做任何其他修改。舉例來說,如果要替 *.txt 檔設執行位元,請不要用
   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:
而是考慮用以下這種方式來處理,可以直接處理使用相同命名規則的新檔名:
   chmod a-x *.txt
   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
   rpm -qa --queryformat "\n\nPACKAGE: %{name}\n" --scripts | less


[[Packaging/FrequentlyMadeMistakes]] has information on frequently-made mistakes.
請不要嘗試和使用者互動;RPM 是以支援批量安裝為設計核心。如果有個程式需要顯示 EULA 終端使用者授權協議,則該動作應是初次執行時才做,而非安裝之時做。


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.
建議你不要試圖啟動服務,因為在大量安裝的過程中可能會讓一切變得緩慢。若你有安裝 init 或 systemd 指令稿,請考慮用 <code>chkconfig</code> 或 <code>systemctl</code> 來安排服務在下次重新開機之時啟動/停止該項服務。在解除安裝之前,如果這些服務還在跑,一般而言你應該先嘗試停止這些服務。


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.
解除安裝應該要盡可能還原安裝階段中所做過的改變,但是不要移除任何使用自行建立的檔案。


Uninstall should reverse most changes made during installation, but don't remove any user-created files.
一般而言,如果有二進位執行檔,則一般二進位軟體包應該剝離除錯用符號 (debugging symbols),並放到 <code>name-debug</code> 子軟體包中。如果不應發生這樣的事,你可以在你的 SPEC 檔頂端放入停用剝離動作:
 
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:
  %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}


A way to check for the version of Fedora in a spec file for conditional builds is:
若想避免剝離動作,你也需要在 <code>%install</code> 區段中做以下動作:
export DONT_STRIP=1
 
在 SPEC 檔中檢查 Fedora 版本作條件判斷式建置的方法: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.)
<code>?</code> 會讓巨集在 <code>%fedora</code> 未定義之時評斷為空白。這樣會讓結果成為 <code>0</code> (數字零,所以很好),而 <code>%fedora</code> 若真的有個數值時也不會有所干擾。(請注意這種做法在 Koji 的「scratch」建置中沒有作用,<code>%fedora</code> 的值會在 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.)
GUI 程式必須有桌面條目 (desktop entry),這樣用戶才能從圖形化桌面選單中喚起這些程式。對於 <code>.desktop</code> 檔案,請見 [[Packaging/Guidelines#Desktop_files|Fedora packaging guidelines for desktop files]] 和 [http://standards.freedesktop.org/desktop-entry-spec/latest/ desktop entry spec];至於 <code>/usr/share/icons</code>,請見 [http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html icon theme spec]。


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
=== 利用 rpmlint 作測試 ===
[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 ===
若要在早期捕捉個種常見錯誤,請在嘗試用 SPEC 檔建置任何軟體包之前先對它執行 <code>rpmlint</code>:
Some older documents about RPM have the most information, but some older documents make claims that are no longer true:
  $ rpmlint program.spec
* 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.
如果回報的錯誤看起來不怎麼合理,請重新以「<code>-i</code>」選項執行以取得更詳細的訊息。
* 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 ==
請以無報錯為目標,不過有時 <code>rpmlint</code> 會有誤報的情況發生。[[Packaging/Guidelines#Use_rpmlint|Fedora 打包規約]] 中有解釋到那些錯誤可以忽略。


Before trying to build anything from it, you should run ''rpmlint'' on the spec file:
=== 以 SPEC 檔製作二進位 RPM 包 ===
rpmlint program.spec
This will catch many errors early. If the reported error doesn't make sense,
run it again with the "-i" option (this gives longer messages).


Generally, you should not have errors from rpmlint, but sometimes
一旦你做好 SPEC 檔之後,請執行以下指令來建置 SRPM 與二進位 RPM:
rpmlint is excessively noisy.
$ rpmbuild -ba program.spec
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 ==
如果製作成功,RPM 會放到 <code>~/rpmbuild/RPMS</code> 裡面,而 SRPM 會放到 <code>~/rpmbuild/SRPMS</code> 之內。


Once you've create a spec file, say "program.spec", you can create
如果製作失敗,請前往對應的資料夾來看看留下了什麼。若想取得除錯協助,你可以用「<code>--short-circuit</code>」選項來略過早期的成功階段。例如:若想要 (略過更早期階段) 重新從 <code>%install</code> 階段開始,請執行:
source and binary RPMs by simply running this:
$ rpmbuild -bi --short-circuit 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.
若你只想要製作 SRPM 檔 (不會執行 <code>%prep</code> 或 <code>%build</code> 或其他階段),請執行:
 
When things go wrong, you can "cd" into the appropriate directory and see what's left over.
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
 
If you just want to create a source RPM (.src.rpm), do this in the SPECS directory:
  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 檔執行來檢查是否存在錯誤。你需要在發佈軟體包之前解除或糾正發出的警告。[[Common_Rpmlint_issues|這個網頁]]提供一些常見問題的解釋。如果你位於 SPEC 目錄中,請執行:
  $ 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。請用以下指令快速查看這些檔案和權限 (來檢查看看是否正確):
$ 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:
請以不同的方式來測試程式看是否全部都正常運作。如果它是 GUI 工具,請確認有出現在桌面選單中,否則代表 <code>.desktop</code> 條目可能有錯。
# 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]] 是在近乎空白的環境下,運用你剛製作的 SRPM 來建置二進位軟體包的強大工具。這可以揭露你實際的建置依賴關係。如果建置失敗,則代表你忘記在 BuildRequires 中列出其中一些東西。請參見 [[Using Mock to test package builds]]。一旦你的帳號屬於「<code>mock</code>」群組的成員之一,你可以執行這樣的指令來做本地端測試:
  $ 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.
你可以利用 Koji (會運用 <code>mock</code>) 在各種不同的系統上執行建置,包括那些你沒有的系統架構。[[PackageMaintainers/Join]] [[PackageMaintainers/UsingKoji]] 上面有更多有關 Koji 的資訊。一旦設定完成,你就可以在各種平臺上使用以下指令來測試你的 SRPM:
 
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.
請將 <code>dist-f9</code> 以任意近期 Fedora 發行版本替換,但別使用 <code>dist-rawhide</code>。請記住,<code>%fedora</code>、<code>%fc9</code>、等這類的值都不會在 scratch build 中得到修正,所以如果你的 SPEC 檔會依據上述值來做不同的事,則無法作用。


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.
你的 Koji 建置僅能依賴 TARGET 散佈版軟體庫中實際存在的軟體包。所以,如果你的軟體包依賴 Bodhi 尚未發行的其他軟體包,就無法用 Koji 來為已發行的散佈版作建置。如果你需要對尚未成為穩定版的發行更新建置軟體包,請透過 Bodhi 提交 Koji 建置根基凌駕請求 (Koji buildroot override requet)。如果它並非你的軟體包依賴,請聯絡其維護者。[在 Bodhi 可以處理 Koji 建置根基凌駕請求之前,以前的舊方法是在此處對 rel-eng 提交請票 (ticket):https://fedorahosted.org/rel-eng/newticket ,並請求將該軟體包加入成為建置根基凌駕之一。]
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>:增進 SPEC 檔中的發行版本標籤,並以當下時間與版本格式加入 changelog 評註:
  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 files.  E.G., "yumdownloader --source glib; rpm -Uvh glib*.src.rpm".
<code>yum-utils</code> 軟體包也提供一些好用工具:
* <code>yumdownloader</code>:請執行以下指令下載該軟體包的 SRPM:
  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.
<code>auto-buildrequires</code> 軟體包有一對優質工具可以幫助我們找出適當的 BuildRequires 條目。在安裝這個軟體包之後,請用「<code>auto-br-rpmbuild</code>」替換 「<code>rpmbuild</code>」,你就會看見自動產生的 BuildRequires 清單。


You might find [http://rust.sourceforge.net/ RUST] useful (GPL).
你可能發現到 [http://rust.sourceforge.net/ RUST] 滿好用的 (GPL),但是它無法製作出符合 Fedora 軟體包品質的 SPEC 檔。[http://kitenet.net/~joey/code/alien/ Alien] 則可以在軟體包格式之間轉換;它無法製作出乾淨的 SRPM,但是從既有的軟體包轉換程式或許能提供一些有用的資訊。
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.
最後,[https://github.com/alanfranz/docker-rpm-builder docker-rpm-builder] (APL 2.0) 使用 [http://www.docker.com Docker] 來建置 RPM 軟體包;想用 rpmbuild 建置的目標架構需要與主控散佈版相同,至於 mock 則對於任何目標架構的 Fedora/Centos/RHEL 散佈版都能良好處理,'''這是無論 Docker 是否能跑都能運用的最後工作'''
It won't produce clean source RPMs, but converting an existing package
might provide helpful information.


== Guidelines and rules ==
若你想要為你的軟體包建置出不同的散佈版與系統架構,並且公開存取 yum 軟體庫,你可以提交你的 src.rpm 到 [https://copr.fedoraproject.org Copr]。


When you create your packages, you'll need to follow the following rules and guidelines:
== 規約與規則 ==
* [[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
* [[Join the package collection maintainers|如何成為 Fedora 軟體包集合的維護者]]
[[Packaging:Guidelines|Packaging Guidelines]] include cross-references to those guidelines.
* [[Packaging:Guidelines|打包規約]]
You can also learn more from the [[SIGs]] and
* [[Packaging:NamingGuidelines|軟體包名稱規約]]
[[:Category:Package Maintainers|Package Maintainers]] sections.
* [[Packaging:LicensingGuidelines|軟體包授權規約]]
[https://fedoraproject.org/wiki/Special:Prefixindex/Packaging You can also see the list of all Wiki pages about Packaging] to see if any apply.
* [[Packaging:DistTag|散佈版標籤規約]]  
* [[Packaging:ReviewGuidelines|軟體包校閱規約]]


Failing that, you might find some useful recommendations in the unofficial
有許多官方規約可以引導你處理一些特定情況 (例:Java 程式、OCaml 程式、GNOME 程式等)。你也可以從 [[SIGs|SIG]] 瞭解更多資訊,與 [[:Category:Package Maintainers|軟體包維護者]] 小節。
[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].
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
[[Special:Prefixindex/Packaging|你也可以查看所有關於打包的 Wiki 頁面]]來看是否有適用的。
[http://fedoraproject.org/wiki/Legal/Licenses/CLA CLA].


== Maintaining the package ==
如果找不到,你可能想要找一些非官方的好用建議,例如 [[Special:Search?ns0=1&search=PackagingDrafts%2F&searchx=Search|Packaging Drafts]] 和 [[PackagingDrafts|Packaging Drafts To Do]]。


Once your package is accepted, you (or your co-maintainers) need to maintain it.
你也可以從 [http://en.opensuse.org/Packaging SuSE]、
See the [[Package update HOWTO]] and [[Package update guidelines]] for more information.
[http://www.debian.org/doc/debian-policy/ Debian] 的資料中找到一些想法,但是
If you update the version in multiple releases of Fedora, do it "backwards" in time, e.g.,
[http://www.mail-archive.com/distributions@lists.freedesktop.org/msg00156.html 各個散佈版所用的規則會不同],所以不要直接想說他們的東西可以直接拿來用。
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:
'''你製作的 .spec 檔必須是開源軟體,如 [[Legal:Fedora_Project_Contributor_Agreement|FPCA]] 中所提及。'''
* [http://www.dwheeler.com/essays/releasing-floss-software.html Releasing Free/Libre/Open Source Software (FLOSS) for Source Installation] (a quick summary)
 
== 維護軟體包 ==
 
一旦你的軟體包被接受,你和你的共同維護者會需要維護這份軟體包。請見 [[Package update HOWTO]] 和 [[Package update guidelines]]。如果你在多個 Fedora 發行版中更新了它的版本,請即時往前做 (例:為 Fedora N 發行新版,一旦被接受,就做 Fedora N-1)。系統會假定新的 Fedora 版本會有相同版本或更後續版本的程式。
 
請鼓勵上游開發者使用標準源碼發行慣例。請使用標準慣例以便讓打包流程更輕鬆。若想要瞭解更多資訊,請見:
* [http://www.dwheeler.com/essays/releasing-floss-software.html Releasing Free/Libre/Open Source Software (FLOSS) for Source Installation] (簡明摘要)
* [http://www.gnu.org/prep/standards/html_node/Managing-Releases.html GNU Coding Standards release process]
* [http://www.gnu.org/prep/standards/html_node/Managing-Releases.html GNU Coding Standards release process]
* [http://en.tldp.org/HOWTO/Software-Release-Practice-HOWTO/ Software Release Practice HOWTO]
* [http://en.tldp.org/HOWTO/Software-Release-Practice-HOWTO/ Software Release Practice HOWTO]
Line 847: Line 777:
* [http://offog.org/articles/packaging/ Packaging Unix software]
* [http://offog.org/articles/packaging/ Packaging Unix software]


== For more information ==
== 更多資訊 ==


The [[:Category:Package Maintainers|Package Maintainers]] page links to many other useful pages, and the
[[:Category:Package Maintainers|Package Maintainers]] 頁面連結到許多其他有用的網頁去,而
[[Package update HOWTO]] describes how to update an existing package you already maintain in Fedora.
[[Package update HOWTO]] 則描述了如何更新你已經在 Fedora 中維護的既有軟體包。


For more information, outside of the Fedora Wiki, see:
若想瞭解更多資訊,在 Fedora Wiki 以外的地方,可以看看下面這些:
* [http://www.g-loaded.eu/2006/04/05/how-to-build-rpm-packages-on-fedora/ How to build RPM packages on Fedora] - very brief run-through
* [http://www.g-loaded.eu/2006/04/05/how-to-build-rpm-packages-on-fedora/ How to build RPM packages on Fedora] - very brief run-through
* Packaging software with RPM (developerWorks) [http://www.ibm.com/developerworks/library/l-rpm1/ Part 1], [http://www.ibm.com/developerworks/library/l-rpm2/ Part 2], and [http://www.ibm.com/developerworks/library/l-rpm3.html Part 3]
* Packaging software with RPM (developerWorks) [http://www.ibm.com/developerworks/library/l-rpm1/ Part 1], [http://www.ibm.com/developerworks/library/l-rpm2/ Part 2], and [http://www.ibm.com/developerworks/library/l-rpm3.html Part 3]
Line 859: Line 789:
* [http://www.redhatmagazine.com/2008/02/28/when-sally-met-eddie-the-fedora-package-story/ When Sally met Eddie] - a simple tale, but little detail
* [http://www.redhatmagazine.com/2008/02/28/when-sally-met-eddie-the-fedora-package-story/ When Sally met Eddie] - a simple tale, but little detail
* [http://rpm.org/max-rpm-snapshot/ Maximum RPM Book] - most complete information, but in some cases old/obsolete
* [http://rpm.org/max-rpm-snapshot/ Maximum RPM Book] - most complete information, but in some cases old/obsolete
* [http://docs.fedoraproject.org/drafts/rpm-guide-en/ch-creating-rpms.html RPM Guide, section on creating RPMs] - this has lots of good information, and is slightly more up-to-date, but is a draft
* [http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html RPM Guide, section on creating RPMs] - this has lots of good information, and is slightly more up-to-date, but is a draft
* [http://docs.fedoraproject.org/developers-guide/ch-rpm-building.html Developer's guide, section on building RPMs]
* [http://docs.fedoraproject.org/developers-guide/ch-rpm-building.html Developer's guide, section on building RPMs]
* [http://www.gurulabs.com/GURULABS-RPM-LAB/GURULABS-RPM-GUIDE-v1.0.PDF Creating RPMS slides] from Guru Labs
* [http://www.gurulabs.com/GURULABS-RPM-LAB/GURULABS-RPM-GUIDE-v1.0.PDF Creating RPMS slides] from Guru Labs
* [http://freshrpms.net/docs/fight/ The fight, my first attempt to make a readable rpm package building introduction.]
* [http://freshrpms.net/docs/fight/ The fight, my first attempt to make a readable rpm package building introduction.]
* [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 RPM HOWTO: RPM at Idle by Donnie Barnes]
* [http://home.fnal.gov/~dawson/rpms/howto/index.html RPM HowTo] by Dawson
* [http://home.fnal.gov/~dawson/rpms/howto/index.html RPM HowTo by Dawson]
* [http://en.opensuse.org/SUSE_Build_Tutorial SuSE build tutorial] - but about SuSE, not Fedora. [http://en.opensuse.org/Build_Service/cross_distribution_package_how_to Cross-distribution package HOWTO] has hints if you're building one RPM for many distributions.
* [http://en.opensuse.org/Build_Service/cross_distribution_package_how_to Cross-distribution package HOWTO] has hints if you're building one RPM for many distributions.
* [http://wiki.mandriva.com/en/Development/Howto/RPM Mandriva Rpm HowTo (en)] ([http://www.mandrivaclub.com/xwiki/bin/view/KB/MandrivaRpmHowTo alt]) is an RPM tutorial, though for Mandriva (nee Mandrake).  Note: In Fedora, do ''not'' recompress original tarballs, as Mandriva suggests, because that would change their cryptographic hashes.
* [http://wiki.mandriva.com/en/Development/Howto/RPM Mandriva Rpm HowTo (en)] is an RPM tutorial, though for Mandriva (nee Mandrake).  Note: In Fedora, do ''not'' recompress original tarballs, as Mandriva suggests, because that would change their cryptographic hashes.
* [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] has some useful information, such as the [http://wiki.rpm.org/Problems list of known RPM problems]
* The [http://wiki.rpm.org/ rpm.org Wiki] has some useful information, such as the [http://wiki.rpm.org/Problems list of known RPM problems]


Note: The [http://rpm5.org/ 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 [http://www.rpm.org rpm.org].
註:[http://rpm5.org/ rpm5.org] 網站也有提供一些文件,但是請不要依靠裡面的內容;那是 Jeff Johnson 維護的 RPM「分支」,也就是 ''fork''。Fedora (Novell/SuSE) 所用的 RPM 則是基於 [http://www.rpm.org rpm.org]
[http://lwn.net/Articles/236029/ lwn.net has a brief article] about this.
[http://lwn.net/Articles/236029/ lwn.net 有個簡要的文章]報導這件事。
 
[[Category:Package Maintainers]][[Category:How to]]


[[Category:Package Maintainers]]
[[Category:How to]]
[[Category:Zh]]
[[Category:Zh]]
[[Category:Zh/Translation]]
[[Category:Zh/Translation]]

Latest revision as of 21:00, 19 September 2016

翻譯: 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/40/Everything/source/SRPMS 目錄取得源碼軟體包。請將「40」替換成你想要使用的 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: 有關該程式更多資訊的完整 URL (例如該程式的專案網站)。 注意:這不是原本源碼的來源 URL,源碼封存檔的來源 URL 應該用下列的 Source0
  • Source0:包含 (原始) 元初源碼的壓縮後封存檔的完整 URL,即上游發行該源碼的位置。「Source」與「Source0」同義。如果你給的是完整的 URL (而且你也該這麼做),會用其基礎名稱去查找 SOURCES 目錄。如果可以的話,請用 %{name}%{version} 替換嵌入 URL 中,這樣只要有所變動時都會自動對應。下載源碼檔案時記得保留時間戳記。如果不只有一份源碼封存檔,請用 Source1Source2 等等依序羅列。如果你要在元初來源外還要再加一些全新的檔案,請將它們列在元初來源之後。任何你製作出的 SRPM 都會包入這些來源的副本,除非你有另外直接指定那就例外。請見 Source URL 瞭解更多特殊案例的資訊 (例如:revision control 修訂控制)。
  • Patch0:第一個要套用到源碼上的修補檔 (patch) 名稱。如果你需要在檔案解壓縮之後對一些檔案作修補,你應該要先編輯檔案並將兩者間的差異儲存成「patch」檔,然後放在 ~/rpmbuild/SOURCES 目錄下。一個 Patch 應該只做一種目的更動 (logical change),所以正常來講可能會有多個 patch 檔。
  • BuildArch:如果你要打包的檔案並不依賴任何架構 (例如:shell 指令稿、資料檔等),那麼請用「BuildArch: noarch」。二進位檔 RPM 的架構就會跟著變成「noarch」。
  • BuildRoot:這是 %install 程序 (在 %build 程序之後) 期間檔案要「安裝」到的地方。這一項目前在 Fedora 中是多餘的,只有 EPEL5 還需要它。預設情況下,建置根基目錄放在「%{_topdir}/BUILDROOT/」。
  • BuildRequires:建置 (編譯) 該程式所需要的軟體包列表,以半形逗號分隔各個項目。這個欄位可以 (而且通常) 多列重複。這些依賴項目 不會 自動判定,所以你需要納入建置該程式所需要的 所有 項目。有些常見軟體包可以省略,例如 gcc。如果有必要,你也可以指定最低要求版本 (例:"ocaml >= 3.08")。如果你需要 /EGGS 檔案,可以執行「rpm -qf /EGGS」來判斷它的所屬軟體包。請維持最低限度的依賴 (例如你不需要 perl 的功能,那就用 sed 而不需用到 perl),但請注意有些應用程式若沒有某功能相關的依賴項目時,會永久停用該功能;這些情況中你可能需要納入額外的軟體包。 Package-x-generic-16.pngauto-buildrequires 軟體包可能會有所用處。
  • 'Requires:當程式安裝之時所需要的軟體包清單,請以半形逗號隔開各個項目。請注意 BuildRequires 標籤應列出的是建置二進位檔 RPM 的項目清單,而 Requires 標籤列出的是安裝/執行該程式所需的項目清單;一個軟體包可以放在其中一個清單,或同時兩個清單中。在許多情況下,rpmbuild 會自動偵測依賴項目,所以不見得需要 Requires 標籤。然而,你可能會希望特別標明那些軟體包是需要的,或是哪些軟體包沒自動偵測到而你需要手動標明。
  • %description:長篇的、跨多列的程式描述。請使用美式英文。每一列都必須小於等於 80 個字元。空白列表示新段落的開始。有些圖形使用者介面安裝程式會重新格式化段落;以空白起頭的列會被視為已預先格式化過的格式,會如其所述表現,顯示時一般採用等寬字型。請見 RPM Guide.
  • %prep:「準備」程式的指令稿指令 (例如:將之解壓縮),這樣才能建置程式。一般這只是「%autosetup」。如果源碼檔案要解開放到 NAME 的話,常見的變化形式是「%autosetup -n NAME」。請見下方的 %prep 小節瞭解更多資訊。
  • %build:「建置」程式的指令稿指令 (例如:編譯它),準備完成以便後續安裝。程式應該有附上如何執行此步驟的指示。請見下方 %build 小節來瞭解更多資訊。
  • %install:「安裝」程式的指令稿指令。指令應該要將檔案從 BUILD 目錄 %{_builddir} 複製到建置根基目錄 %{buildroot} 中。請見下方的 %install 小節瞭解更多細節。
  • %check:「測試」程式的指令稿指令。這是在 %install 程序後執行,所以如果你需要此區段的話,請將它放在該處。通常它僅包含「make test」或「make check」。這要和 %build 分開,這樣人們才能在需要的時候略過自我測試。
  • %clean: 清理建置根基目錄的指令。請注意這個區段目前在 Fedora 中是多餘的,並且只有 EPEL 需要。一般這只包含:
rm -rf %{buildroot}
  • %files:會安裝的檔案清單。請見下方 %files 小節以瞭解更多細節。
  • %changelog:軟體包的變動。請使用上述格式。請「不要」把軟體的變更記錄放在這裡。這裡是 RPM 自身的變更記錄。
  • ExcludeArch:如果軟體包無法在某特定架構上成功編譯、建置或運作,請在此標籤下列出這些架構。* 你可以加入些代碼區段,這樣代碼會在軟體包於真實系統上安裝或移除時執行 (與之相反的是只執行 %install 指令稿,它只會作虛擬安裝 (pseudo-install),安裝到建置根基目錄中)。這些代碼稱之為「scriptlet」指令稿片段,他們通常以軟體包中的資訊更新執行中的系統。請見下方的「scriptlet」瞭解更多細節。

RPM 也支援從單一 SPEC 檔製作出多個軟體包 (稱為 子軟體包) 的功能,例如 name-libsname-devel 等軟體包。

Stop (medium size).png
「不要」使用這些標籤
  • Packager
  • Vendor
  • Copyright

不要製作「relocatable」可重新變換位置的軟體包;他們不會幫 Fedora 加值,反而把事情搞得更複雜。

SPEC 檔區段詳解

%prep 區段

%prep 區段描述的是如何解開壓縮後軟體包的方法,這樣才能拿來建置。一般而言,這包含「%autosetup」指令。另外,你可以使用「%setup」和「%patch」指令搭配參照 Source0 (與 Source1 等) 條目。請見 Maximum RPM 一文中的 %setup and %patch 小節 瞭解更多細節。

自 RPM 4.4.2 起可以使用 %{patches} 和 %{source} 巨集,若你有大量補丁或來源清單,以及 %autosetup 效果並非你所想要的話會很好用,例如你可以這樣做:

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

然而請記住,使用上述功能,會讓你的 SPEC 和 RHEL 以及其他 RPM 散布版中所使用的 RPMS 不相容。

%prep 區段:%autosetup 指令

%autosetup」指令會解開來源軟體包。可用選項包括:

  • -n name :如果 Source tarball 所要解開成的目錄名稱與 RPM 名稱不同,這個切換開關用來指定正確的目錄名稱。舉例來說,如果 tarball 要解開成 FOO 目錄,則使用「%autosetup -n FOO」。
  • -c name :如果 Source tarball 需要解開成多個目錄,而非單一個目錄時,這個切換開關可以用來建立名為 name 的目錄,然後將內容解開放在裡面。

如我你改用「%setup」指令,則通常使用 -q' 來抑止不必要的輸出。

如果你打算解開多份檔案,有更多 %spec 選項可以用,這在你製作子軟體包時會很有用 (請見下方)。比較重要的有:

-a number 在切入目錄後,只解開指定數字的 Source 目錄 (例:「–a 0」代表 Source0)。
-b number 在切入目錄前,只解開指定數字的 Source 目錄 (例:「–b 0」代表 Source0)。
-D 在解開之前不要刪除目錄。
-T 停用自動解開封存檔。

%prep 區段:%patch 指令

如果你用的是「%autosetup」指令,就不需要下列的手動補丁管理程序。如果你的需求很複雜,或是需要和 EPEL 相容,還是可能需要用到。「%patch0」指令會套用 Patch0 (而 %patch1 會套用 Patch1,依此類推)。補丁是對來源程式碼做出必要修改使之符合打包規約的正常作法。常用的「-pNUMBER」選項會傳遞引數給 patch 程式來套用對應補丁。

補丁的檔名通常看起來像是「telnet-0.17-env.patch」這樣,命名格式依循「%{name} - %{version} - REASON.patch」(不過有時候會省略 version 版本)。補丁檔通常是「diff -u」的成果;如果你是從if you do this from the subdirectory of ~/rpmbuild/BUILD 的子目錄執行這個指令的,那麼你之後便不必指定 -p 層級。

這是為單一檔案製作補丁的典型程序:

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

如果需要修改許多檔案,有個簡單的方法,就是複製 BUILD 下的整個子目錄,然後執行子目錄的 diff。在你切入「~rpmbuild/BUILD/NAME」目錄後,執行以下指令:

cp -pr ./ ../PACKAGENAME.orig/
... 修改許多檔案 ...
diff -ur ../PACKAGENAME.orig . > ~/rpmbuild/SOURCES/NAME.REASON.patch

如果你想在一個補丁中編輯多重檔案,你也可以在編輯之前用同樣的檔名結尾「.orig」來複製原始檔案。然後,你可以用「gendiff」(在 rpm-build 軟體包中) 製作檔案差異的補丁檔。


試著確保你的路徑完全符合情境。預設的「fuzz」值是「0」,代表比對要求完全相同。你可以加入「%global _default_patch_fuzz 2」來轉換成舊版 Fedora RPM 版本所採用的值,但我們建議你應盡量避免這樣做。


Packaging/PatchUpstreamStatus 所詳述的,SPEC 檔中所有的補丁上方都要有個註解描述它的目前上游狀態為何。如果這是 Fedora 特別需要的補丁,你應該提及為何它如此特別。Fedora 專案致力不與上游分歧;請見 PackageMaintainers/WhyUpstream 瞭解此事的重要性。

%prep 區段:未修改的檔案

有時候,來源的一個或多個檔案並不需要解壓縮。你可以「prep」準備這些項目到建置目錄中,如 (這裡的 SOURCE1 代表對應的來源檔):

cp -p %SOURCE1 .

%build 區段

「%build」區段偶爾會有點複雜;在這個區段中你設置組態,並編譯/建置用來安裝的檔案。

許多程式採用 GNU configure 的方法 (或據此變化)。預設情況下,檔案會安裝到前綴為「/usr/local」的路徑下,這對解開檔案的存放來說相當合理;但是,現在你是要打包程式,所以請將路徑前綴改成「/usr」。函式庫則應該視架構而定,安裝到 /usr/lib/usr/lib64 中。

由於 GNU configure 非常常見,可以自動使用「%configure」巨集來喚起正確的選項 (例如,將前綴路徑改成 /usr)。有些變化也多能作用:

 %configure
 make %{?_smp_mflags}

若要凌駕 makefile 變數,請將它作為參數傳遞給 make

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

至於其他深入資訊,請參見 "GNU autoconf, automake, and libtool" 以及 "Open Source Development Tools: An Introduction to Make, Configure, Automake, Autoconf" by Stefan Hundhammer

也有些程式使用 cmake。請參見 Packaging/cmake

%install 區段

本區段內含「安裝」該程式用的指令稿指令,即從 %{_builddir} 資料夾複製相關檔案到 %{buildroot} 中 (通常代表從 ~/rpmbuild/BUILD 複製到 ~/rpmbuild/BUILDROOT),並且根據需要在 %{buildroot} 中新建資料夾。

有些術語的名稱可能讓人會錯意:

  • 「建置目錄 build directory」,也稱為 %{_builddir},實際上和「建置根基 build root」,又稱為 %{buildroot},是不一樣的資料夾。我們會在前者中編譯,而要打包的檔案則從前者複製到後者去。
  • 在 %build 區段中,目前的目錄起始於 %{buildsubdir},是 %prep 階段中在 %{_builddir} 下建立的子資料夾。這個資料夾名稱通常會是 ~/rpmbuild/BUILD/%{name}-%{version} 這樣。
  • %install 區段在終端使用者安裝二進位 RPM 軟體包時並 不會 執行 ;事實上 %install 區段只有在製作軟體包時才會執行。

一般來說,這裡執行的是「make install」之類的:

%install
rm -rf %{buildroot} # redundant except for RHEL 5
%make_install

理想上您應該使用 %make_install,對於支援的程式來說,它等同於 DESTDIR=%{buildroot},因為它會重新導引檔案安裝到指定的目錄中,也就是我們在 %install 區段中預期發生的事。

如果程式不支援 DESTDIR(且僅在有此情況之下),您有許多 (下方所列) 方式可以避開問題:

  • 修補 makefile 來讓它支援 DESTDIR。在 DESTDIR 中視需要建立目錄,並提交該 patch 補丁給上游。
  • 使用「%makeinstall」巨集。這個方法可能有效,但也可能導致些微失敗。該巨集會展開成「make prefix=%{buildroot}%{_prefix} bindir=%{buildroot}%{_bindir} ... install」,而可能導致有些程式無法正常運作。請在 %{buildroot} 下視需要建立目錄。
  • 考慮使用 auto-destdir 軟體包。它需要「BuildRequires: auto-destdir」、並將「make install」修改成「make-redir DESTDIR=%{buildroot} install」。這只在安裝僅使用到特定常用指令來安裝檔案時才能作用,例如 cpinstall
  • 手動執行安裝。這可能牽涉到在 %{buildroot} 下建立必要的目錄,並從 %{_builddir} 複製檔案到 %{buildroot} 裡去。要特別注意更新,通常會有新檔名或修改過檔名。此程序的範例:
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}%{_bindir}/
cp -p mycommand %{buildroot}%{_bindir}/

%check 區段

如果可以自我測試的話,將它們納入其中的話會是個好主意。他們應該放在 %check 區段中 (緊接在 %install 區段之後,因為應該測試 %buildroot 中的檔案) 而不是放在 %build 區段中,這樣才能在必要時刻輕易略過。

通常,此區段包含:

make test

有時候也可以用:

make check

請探索一下 Makefile 的用法,並選擇適當的方式。

%files 區段

此區段宣告哪些檔案與目錄是由該軟體包擁有,還有哪些檔案與目錄會放到二進位檔 RPM 中。

%files 基礎

%defattr 會設定預設的檔案權限,通常可以在 %files 區段的開頭看到使用。請注意到,如果不需要修改權限的話,那就不再需要用到它。它的使用格式為:

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

第四個參數通常會省略。通常我們會這樣用 %defattr(-,root,root,-),其中「-」代表預設權限。

您應該列出該軟體包擁有的所有檔案和目錄。請盡量用巨集來取代目錄名稱,您可以到 Packaging:RPMMacros (舉例:使用 %{_bindir}/mycommand 取代 /usr/bin/mycommand) 來查看巨集表。如果起頭樣式為「/」(或從巨集擴展而來),則從 %{buildroot} 目錄取用。否則,將假定檔案位在目前的目錄中 (例如:在 %{_builddir} 內部,例如您想要納入的文件檔)。若您的軟體包僅安裝單一檔案如 /usr/sbin/mycommand,則 %files 區段可以像這樣簡單:

%files
%{_sbindir}/mycommand

若要讓您的軟體包較不受上游改動而影響,請依這種樣式比對來宣告該軟體包擁有的目錄下所有檔案:

%{_bindir}/*

若要納入單一目錄:

%{_datadir}/%{name}/

請注意,%{_bindir}/* 並不會宣稱此軟體包擁有 /usr/bin 目錄,而只有包含其下的檔案。如果您列出一個目錄,則您正試圖宣稱該軟體包擁有這個目錄,以及該目錄內的所有檔案與子目錄。所以,請 不要 列出 %{_bindir},而且要小心處理那些可能和其他軟體包共享的目錄。

如果有下列情形可能引發錯誤:

  • 試圖樣式比對,卻沒比對到任何檔案或目錄
  • 重複列出或重複比對到某個檔案或目錄
  • 沒有列出 %{buildroot} 下的某個檔案或目錄

您也可以使用 %exclude glob 來從前個比對中排除檔案。這對於想用不同的樣式比對來將幾乎全部檔案納入其中時會很有用,但是請注意如果沒有比對到任何東西也會造成失敗。

%files 前綴字

您可能需要在 %files 區段的內容中加入一個或多個前綴字;請用空格隔開。請見 Max RPM section on %files directives

通常,「%doc」用來列出 %{_builddir} 內,但未複製到 %{buildroot} 中的文件檔。通常包括 READMEINSTALL 檔。它們會放到 /usr/share/doc 下適當的目錄中,而 /usr/share/doc 的擁有權不必宣告。

注意: 如果有指定 %doc 條目,rpmbuild < 4.9.1 在安裝之前會將檔案安裝到其中的 doc 文件目錄移除。這代表已經放到裡面去的檔案,例如,在 %install 區段中安裝的檔案,會被移除,因此最終不會出現在軟體包中。如果您想要在 %install 區段中安裝一些檔案,請將它們安裝到建置目錄 (是 build dir,而不是建置根基 build root) 內的暫時鄰架目錄 (temporary staging directory) 中,例如 _docs_staging,接著將之納入 %files 列表中,如 %doc _docs_staging/* 這樣。

組態檔應該要放在 /etc 中,一般會這樣指定 (可以確保使用者所作的更動不會在更新時被覆蓋):

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

如果更新程序用的是無法向前相容的組態格式 (non-backwards-compatible configuration format),則應這樣指定:

%config %{_sysconfdir}/foo.conf

%attr(mode, user, group)」可以用來指派更精細的權限控制,而「-」代表是用預設值:

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

如果檔案是以特定的自然語言撰寫,請使用 %lang 來標註:

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

使用到區域語言 (Locale) 檔案的程式應該遵循 處理 i18n 檔的建議方法 (英)

  • %install 步驟中找出檔名: %find_lang ${name}
  • 加入必要的建置依賴: BuildRequires: gettext
  • 使用找到的檔名: %files -f ${name}.lang

以下前綴字在 Fedora 中 無效%license%readme

%files 與檔案系統階層標準 (Filesystem Hierarchy Standard, FHS)

您應該遵守 檔案系統階層標準 (FHS)。執行檔應放在 /usr/bin,全域組態檔放進 /etc,函式庫放到 /usr/lib (或 /usr/lib64) 等等。只有一項例外:一般不該給使用者或管理員執行的執行檔,應該放到 /usr/libexec 中的子資料夾中,資料夾名稱為 %{_libexecdir}/%{name}.

不要 把檔案安裝到 /opt/usr/local 中。

不幸地,許多程式預設情況下並不遵守 FHS。尤其是,系統架構獨立的函式庫被放到 /usr/lib 而非 /usr/share 之中。前者是給系統架構依賴的函式庫使用,後者才是給系統架構獨立的函式庫運用;這代表不同 CPU 架構的系統都能共享 /usr/share 資料夾。Fedora 中也是有一些例外 (例如 Python 和 Perl),然而 Fedora 比起其他散佈版來說更嚴格遵守標準規範,rpmlint 一般會在你將 ELF 以外的檔案放進 /usr/lib 內時提出抱怨。

%files 範例

以下為 %files 區段的簡單範例:

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

找出重複檔案

您可以列出任兩個二進位軟體包的重複檔案,做法爲:

cd ~/rpmbuild/RPMS/ARCH # 請將 "ARCH" 替換為您的系統架構
rpm -qlp PACKAGE1.*.rpm | sort > ,1
rpm -qlp PACKAGE2.*.rpm | sort > ,2
comm -12 ,1 ,2

小指令稿 (Scriptlet)

當終端使用者在安裝 RPM 時,您可能想要執行一些指令。這可以透過小指令稿完成。請見 Packaging/ScriptletSnippets

小指令稿可以:

  • 在軟體包安裝之前 (%pre) 或之後 (%post) 執行
  • 在軟體包移除之前 (%preun) 或之後 (%postun) 執行
  • 在處理事項的開頭 (%pretrans) 或結尾 (%posttrans) 執行

舉例來說,每一會在任何 dinamic linker 預設路徑中儲存共享函式庫檔案的二進位檔 RPM 軟體包,都必須在 %post%postun 中呼叫 ldconfig。如果該軟體包有多個附帶函式庫的子軟體包,則每個軟體包也都應該執行相同的動作。

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

如果僅執行單一指令,則「-p」選項會執行相接的指令但不會喚起 shell。然而,若有許多指令時,請省去這個選項,並在其下納入 shell 指令。

如果你在小指令稿中有執行任何程式,你就必須以「Requires(CONTEXT)」(例: Requires(post)) 的形式來列出所有的執行需求。

%pre%post%preun、和 %postun 提供了 $1 引數,表示動作完成之後系統上留下的此名稱之軟體包有幾個。請不要拿這個值來比較是否等於 2,而是比較是否大於或等於 2。至於 %pretrans%posttrans$1 的值則恆為 0

舉例來說,如果軟體包安裝了一份 info manual (資訊手冊),那麼可以用 info 軟體包提供的 install-info 來更新資訊手冊索引。首先,我們不保證 info 軟體包總會存在,除非我們明確宣告它是必備的部分;再來,我們不想要在 install-info 失敗之時讓軟體包的執行動作完全失敗:

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

還有一件安裝資訊手冊時相關的小瑕疵。install-info 指令會更新資訊目錄,所以我們應該要在 %install 區段中刪掉 %{buildroot} 中無用的空目錄:

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

另一個類似小指令稿的能力是「triggers」(觸發器),可以在其他軟體包已安裝或已移除之時,為你的軟體包執行一些動作。請見 RPM Triggers

巨集 (Macro)

巨集是 %{string} 這類寫法的文字。典型的巨集有:

巨集 典型擴展 意義
%{_bindir} /usr/bin 二進位檔資料夾 (Binary directory):執行檔通常存放的位置。
%{_builddir} ~/rpmbuild/BUILD 建置資料夾 (Build directory):檔案放在建置目錄下的子目錄中編譯。請見 %buildsubdir
%{buildroot} ~/rpmbuild/BUILDROOT 建置根基 (Build root):在 %install 階段中的檔案「安裝」之處,會將 %{_builddir} 子目錄下的檔案複製到 %{buildroot} 的子目錄之下。(過去,%{buildroot} 所採用的位置是「/var/tmp/」。)
%{buildsubdir} %{_builddir}/%{name} 建置子資料夾 (Build subdirectory):在 %build 階段中檔案會在 %{_builddir} 的子目錄中編譯。這個位置會在 %autosetup 後設置。
%{_datadir} /usr/share 共用資料夾。
%{_defaultdocdir} /usr/share/doc 預設文件資料夾。
%{dist} .fcNUMBER 散佈版+版本短名 (例:「.fc40」)
%{fedora} NUMBER fedora 發行版號 (例:「40」)
%{_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: tag 決定
%{_sbindir} /usr/sbin
%{_sharedstatedir} /var/lib
%{_sysconfdir} /etc
%{version} 軟體包版本,由 Version: tag 決定

您可以查看 /etc/rpm/*/usr/lib/rpm、甚至是 /usr/lib/rpm/macros 以進一步瞭解巨集。或是用 rpm --showrc 來顯示 RPM 運用這些巨集時所採用的值 (會根據 rpmrc 與巨集組態檔而有所變動)。

您可以利用 %global 來定義自己的巨集值,但是請確定在使用巨集之前先已定義過。(巨集在定義之時也可以指涉 (refer to) 其他巨集。) 範例:

%global date 2012-02-08

請用 rpmbuild 的「-E」選項來尋找巨集在 SPEC 檔中代表的值:

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

也請參見 Packaging/RPMMacrosRPM Guide chapter 9

其他標籤 (tag)

除了 Requires 和 BuildRequires 標籤之外,你還可以使用以下這些控制依賴關係:

  • Provides:列出此軟體包提供的虛擬軟體包名稱。例如,可能有個 foo 軟體包需要來自其他程式的「bar」功能;若有許多軟體包可以滿足該需求,則這些軟體包可以指定「Provides: bar」,而「foo」軟體包則可以指定「Requires: bar」。你也可以使用 "alternatives" 系統,但是若同個系統中有多位使用者,不同人可能希望使用不同的預設值,此時請避免使用它,畢竟這些設定屬於系統全域設定。請用「rpm -q --provides PACKAGENAME」來查看指定的軟體包提供那些東西。一些 Fedora 中虛擬軟體包的範例:
    • MTA:用作郵件傳輸代理 (mail transport agent, MTA),例如 sendmail。
    • tex(latex): 用作 latex
  • Obsoletes:當這個軟體包安裝時移除另一個指名的軟體包。當軟體包名稱更換之時,或是用該軟體包完全取代另一個不同的軟體包之時可以使用。
  • Conflicts:表示無法與此軟體包同時安裝的其他軟體包。如果可以請避免使用這個標籤。請見 Packaging/Conflicts
  • BuildConflicts:表示在建置此軟體包之時無法安裝的軟體包。如果可以請避免使用這個標籤。

若要處理不同的系統架構,有兩種標籤可以使用:

  • ExcludeArch:排除此軟體包無法建置的系統架構。例如:
ExcludeArch: ppc
  • ExclusiveArch:僅納入指定的系統架構。除非絕對正確,否則請避免使用。

可用的系統架構列在 Architectures 中。

子軟體包 (或稱細分包,Subpackage)

一份 SPEC 檔可以定義多份二進位檔軟體包。換句話說,一個內含一份 SPEC 檔的 SRPM 檔可能製作出許多 RPM 檔來。請注意到這依然只會有一道製作 (%prep、%build、%install 等) 程序。 name-docname-devel 為常見的文件檔和開發檔子軟體包。

請使用 %package 巨集指令來定義子軟體包:

%package subpackage_name

在每個 %package 指令之後,請列出該子軟體包的數個標籤 (tag)。這應該至少包括 Summary 和 Group 標籤、以及 %description subpackage_name%files subpackage_name 指令:

任何子軟體包中未特別指定到的東西,都會從其親代沿襲下來。

預設情況下,如果該軟體包的名稱為「foo」而子軟體包名稱為「bar」,則子軟體包成果則會是「foo-bar」。你可以利用「-n」選項 (但如果你在這裡特別指定的話,你也需要在所有其他的指令中用到這道指令) 來凌駕原先的規則:

%package -n new_subpackage_name

請見 RPM Guide 針對子軟體包所寫的小節瞭解更多資訊。

條件判斷 (Conditional)

你可以插入條件判斷陳述,例如測試你是否會為特定系統架構製作二進位檔:

%ifarch ARCHITECTURE_NAME

反面 (negated) 的論述版本為:

%ifnarch ARCHITECTURE_NAME

或更一般的條件判斷式:

%if TRUE_OR_FALSE

也有個可選擇性使用的「%else」區段;以上這些全都必須以「%endif」作結尾。

應用程式專門規約

有許多應用程式專門規約可以協助你 (例:專門的程式語言、應用程式、函式庫、建置系統等)。大多都列在 應用程式專用打包規約/規約 (英) 之中。一些應用程式專門規約的例子有:

如果上述的資訊都沒有涵括到,還有一些可以幫助你找到應用程式專用協助的方法:

其他注意事項 (Miscellaneous hints)

Packaging/FrequentlyMadeMistakes 有列出常見錯誤的相關資訊。PackageMaintainers/Packaging Tricks 則有列出一些建議、以及具爭議性的技巧。

請試著撰寫你的 SPEC 檔,盡可能讓上游發行新版本時一切都能水到渠成,使你除了要改版本號並刷新來源檔案外,都不必做任何其他修改。舉例來說,如果要替 *.txt 檔設執行位元,請不要用

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

而是考慮用以下這種方式來處理,可以直接處理使用相同命名規則的新檔名:

 chmod a-x *.txt

如果你想要查看大量的小指令稿範例,你可以利用下列指令來顯示所有已安裝程式的小指令稿:

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

請不要嘗試和使用者互動;RPM 是以支援批量安裝為設計核心。如果有個程式需要顯示 EULA 終端使用者授權協議,則該動作應是初次執行時才做,而非安裝之時做。

建議你不要試圖啟動服務,因為在大量安裝的過程中可能會讓一切變得緩慢。若你有安裝 init 或 systemd 指令稿,請考慮用 chkconfigsystemctl 來安排服務在下次重新開機之時啟動/停止該項服務。在解除安裝之前,如果這些服務還在跑,一般而言你應該先嘗試停止這些服務。

解除安裝應該要盡可能還原安裝階段中所做過的改變,但是不要移除任何使用自行建立的檔案。

一般而言,如果有二進位執行檔,則一般二進位軟體包應該剝離除錯用符號 (debugging symbols),並放到 name-debug 子軟體包中。如果不應發生這樣的事,你可以在你的 SPEC 檔頂端放入停用剝離動作:

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

若想避免剝離動作,你也需要在 %install 區段中做以下動作:

export DONT_STRIP=1

在 SPEC 檔中檢查 Fedora 版本作條件判斷式建置的方法:A way to check for the version of Fedora in a SPEC file for conditional builds is:

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

? 會讓巨集在 %fedora 未定義之時評斷為空白。這樣會讓結果成為 0 (數字零,所以很好),而 %fedora 若真的有個數值時也不會有所干擾。(請注意這種做法在 Koji 的「scratch」建置中沒有作用,%fedora 的值會在 SRPM 製作之時就設定好。)

GUI 程式必須有桌面條目 (desktop entry),這樣用戶才能從圖形化桌面選單中喚起這些程式。對於 .desktop 檔案,請見 Fedora packaging guidelines for desktop filesdesktop entry spec;至於 /usr/share/icons,請見 icon theme spec

建置二進位軟體包

利用 rpmlint 作測試

若要在早期捕捉個種常見錯誤,請在嘗試用 SPEC 檔建置任何軟體包之前先對它執行 rpmlint

$ rpmlint program.spec

如果回報的錯誤看起來不怎麼合理,請重新以「-i」選項執行以取得更詳細的訊息。

請以無報錯為目標,不過有時 rpmlint 會有誤報的情況發生。Fedora 打包規約 中有解釋到那些錯誤可以忽略。

以 SPEC 檔製作二進位 RPM 包

一旦你做好 SPEC 檔之後,請執行以下指令來建置 SRPM 與二進位 RPM:

$ rpmbuild -ba program.spec

如果製作成功,RPM 會放到 ~/rpmbuild/RPMS 裡面,而 SRPM 會放到 ~/rpmbuild/SRPMS 之內。

如果製作失敗,請前往對應的資料夾來看看留下了什麼。若想取得除錯協助,你可以用「--short-circuit」選項來略過早期的成功階段。例如:若想要 (略過更早期階段) 重新從 %install 階段開始,請執行:

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

若你只想要製作 SRPM 檔 (不會執行 %prep%build 或其他階段),請執行:

rpmbuild -bs program.spec

利用 rpmlint 來測試二進位 RPM 檔

rpmlint 可以對 SPEC 檔、RPM 檔、SRPM 檔執行來檢查是否存在錯誤。你需要在發佈軟體包之前解除或糾正發出的警告。這個網頁提供一些常見問題的解釋。如果你位於 SPEC 目錄中,請執行:

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

請進入 ~/rpmbuild/RPMS 目錄,再進入系統架構子目錄中。你會看到一些二進位檔 RPM。請用以下指令快速查看這些檔案和權限 (來檢查看看是否正確):

$ rpmls *.rpm

如果一切看起都很好,請以 root 身份安裝:

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

請以不同的方式來測試程式看是否全部都正常運作。如果它是 GUI 工具,請確認有出現在桌面選單中,否則代表 .desktop 條目可能有錯。

稍後可以利用以下指令來解除安裝軟體包:

# rpm -e package1 package2 package3

Mock 和 Koji

Mock 是在近乎空白的環境下,運用你剛製作的 SRPM 來建置二進位軟體包的強大工具。這可以揭露你實際的建置依賴關係。如果建置失敗,則代表你忘記在 BuildRequires 中列出其中一些東西。請參見 Using Mock to test package builds。一旦你的帳號屬於「mock」群組的成員之一,你可以執行這樣的指令來做本地端測試:

$ mock -r fedora-9-i386 rebuild path_to_source_RPM

你可以利用 Koji (會運用 mock) 在各種不同的系統上執行建置,包括那些你沒有的系統架構。PackageMaintainers/JoinPackageMaintainers/UsingKoji 上面有更多有關 Koji 的資訊。一旦設定完成,你就可以在各種平臺上使用以下指令來測試你的 SRPM:

$ koji build --scratch dist-f9 path_to_source_RPM

請將 dist-f9 以任意近期 Fedora 發行版本替換,但別使用 dist-rawhide。請記住,%fedora%fc9、等這類的值都不會在 scratch build 中得到修正,所以如果你的 SPEC 檔會依據上述值來做不同的事,則無法作用。

你的 Koji 建置僅能依賴 TARGET 散佈版軟體庫中實際存在的軟體包。所以,如果你的軟體包依賴 Bodhi 尚未發行的其他軟體包,就無法用 Koji 來為已發行的散佈版作建置。如果你需要對尚未成為穩定版的發行更新建置軟體包,請透過 Bodhi 提交 Koji 建置根基凌駕請求 (Koji buildroot override requet)。如果它並非你的軟體包依賴,請聯絡其維護者。[在 Bodhi 可以處理 Koji 建置根基凌駕請求之前,以前的舊方法是在此處對 rel-eng 提交請票 (ticket):https://fedorahosted.org/rel-eng/newticket ,並請求將該軟體包加入成為建置根基凌駕之一。]

有用的工具

rpmdevtools 軟體包有各種好用工具;「rpm -qil rpmdevtools」會展示給你看它會安裝哪些東西。

  • rpmdev-bumpspec:增進 SPEC 檔中的發行版本標籤,並以當下時間與版本格式加入 changelog 評註:
rpmdev-bumpspec --comment=COMMENT --userstring=NAME+EMAIL_STRING SPECFILES

yum-utils 軟體包也提供一些好用工具:

  • yumdownloader:請執行以下指令下載該軟體包的 SRPM:
yumdownloader --source PACKAGENAME

auto-buildrequires 軟體包有一對優質工具可以幫助我們找出適當的 BuildRequires 條目。在安裝這個軟體包之後,請用「auto-br-rpmbuild」替換 「rpmbuild」,你就會看見自動產生的 BuildRequires 清單。

你可能發現到 RUST 滿好用的 (GPL),但是它無法製作出符合 Fedora 軟體包品質的 SPEC 檔。Alien 則可以在軟體包格式之間轉換;它無法製作出乾淨的 SRPM,但是從既有的軟體包轉換程式或許能提供一些有用的資訊。

最後,docker-rpm-builder (APL 2.0) 使用 Docker 來建置 RPM 軟體包;想用 rpmbuild 建置的目標架構需要與主控散佈版相同,至於 mock 則對於任何目標架構的 Fedora/Centos/RHEL 散佈版都能良好處理,這是無論 Docker 是否能跑都能運用的最後工作

若你想要為你的軟體包建置出不同的散佈版與系統架構,並且公開存取 yum 軟體庫,你可以提交你的 src.rpm 到 Copr

規約與規則

當你製作軟體包之時,你需要遵守下列規則與規約:

有許多官方規約可以引導你處理一些特定情況 (例:Java 程式、OCaml 程式、GNOME 程式等)。你也可以從 SIG 瞭解更多資訊,與 軟體包維護者 小節。

你也可以查看所有關於打包的 Wiki 頁面來看是否有適用的。

如果找不到,你可能想要找一些非官方的好用建議,例如 Packaging DraftsPackaging Drafts To Do

你也可以從 SuSEDebian 的資料中找到一些想法,但是 各個散佈版所用的規則會不同,所以不要直接想說他們的東西可以直接拿來用。

你製作的 .spec 檔必須是開源軟體,如 FPCA 中所提及。

維護軟體包

一旦你的軟體包被接受,你和你的共同維護者會需要維護這份軟體包。請見 Package update HOWTOPackage update guidelines。如果你在多個 Fedora 發行版中更新了它的版本,請即時往前做 (例:為 Fedora N 發行新版,一旦被接受,就做 Fedora N-1)。系統會假定新的 Fedora 版本會有相同版本或更後續版本的程式。

請鼓勵上游開發者使用標準源碼發行慣例。請使用標準慣例以便讓打包流程更輕鬆。若想要瞭解更多資訊,請見:

更多資訊

Package Maintainers 頁面連結到許多其他有用的網頁去,而 Package update HOWTO 則描述了如何更新你已經在 Fedora 中維護的既有軟體包。

若想瞭解更多資訊,在 Fedora Wiki 以外的地方,可以看看下面這些:

註:rpm5.org 網站也有提供一些文件,但是請不要依靠裡面的內容;那是 Jeff Johnson 維護的 RPM「分支」,也就是 fork。Fedora (和 Novell/SuSE) 所用的 RPM 則是基於 rpm.orglwn.net 有個簡要的文章報導這件事。