Packaging Guidelines
These guidelines are based on those used by similar distros (e.g. Fedora, Mageia, OpenSUSE etc).
Contents
Package Naming
- The base package names should be the upstream name of the software project, usually lowercase. Upstream names can contain digits, '+', '_' or '.', but no other special characters. Uppercase names are allowed in some circumstances but should be avoided if possible.
- Sub-package names are derived from the upstream name by adding suffixes and should always use '-' as delimiter (e.g. foo-devel or foo-plugins as derived from the foo package). All '_' and '+' in package names must come from upstream naming! The '.' in package names should only come upstream or standard versioning schemes.
- The spec file should be named using the pclos-%{name}.spec scheme. This makes it handy if you are updating a package and encounter a build error. You can install another distributions source package and compare their spec file with yours to see if they added a patch or a different build option to make the new version build.
Package Versions look like : 5.4.3-1pclos2020
- 5.4.3 is the 'Version' number which should match the version number used by the upstream project.
- 1pclos2020 is the 'Release tag' which is made up of 3 fields: First is the release number generated by the %mkrel macro (in this example '%mkrel 1' and needs to be incremented each time the spec file is changed or the package is rebuilt. Next is the 'distsuffix' which will be pclos for official RPMs and SRPMs. Packagers should use their forum name as the distsuffix when submitting packages to the developer's Dropbox. The last field is simply the current year.
SPEC file guidelines
SPEC files in PCLinuxOS should be named pclos-%{name}.spec. The SPEC file contains the "recipe" for building an RPM package and broadly has two areas: A "preamble" which defines various inputs and attributes of the build and then the body of spec file which contains commands and RPM directives to produce the build.
Preamble tags
The preamble should consist of the following RPM tags:
Name
This should be the base name of the package as explained above. The value is assigned to %{name} which should be used to represent the package name throughout the spec file.
Version
This should be the upstream version number of the software. The value is assigned to %{version} which should be used to represent the version number throughout the spec file.
Release
This represents the number of times this version of the software has been released and is generated with %mkrel as explained above.
Summary
The summary is a single line string describing the package. The maximum length is 79 characters and it should start with an uppercase letter and not with a space. The summary should not end with a dot (.) The name of the package should not be repeated in its summary. This is often redundant information and looks silly in various programs' output. It should fit all standard situations and not assume any special context. It should be helpful alone, in alphabetically sorted or unsorted lists of some selected packages, and in alphabetically sorted or unsorted lists of all packages. The summary should be brief and to the point without including redundant information.
Group
The Group tag is used to group packages by the types of functionality they provide, and also makes up the list of Categories in Synaptic. Check in Synaptic to see what groups currently exist for similar software and use that where possible.
License
The License tag is used to document the license of the software being packaged. This must be an open source license abiding by the specific distribution’s licensing guidelines.
URL
The URL tag is usually the full URL to the project website of the software being packaged
Source
The Source tag is used to identify the source files which make up the input to rpmbuild. In most cases this should be a complete URL to the upstream tarball but can also be additional files created to augment the source package. Best practice would be to use macros like %{version} and %{name} for this URL where possible to allow for automatic updates. If needed, more SourceX directives can be added, incrementing the number each time, for example: Source1, Source2, Source3, and so on. These source files can be referred to elsewhere in the spec file using %{SOURCE0}, %{SOURCE1} etc.
Source tarballs should be re compressed as .tar.xz to save space.
Patch
The Patch tag identifies patches which need to be applied to the source before compilation. The Source tag should always point to the original unmodified source files from the upstream provider. Any fixes or customizations must be applied as patches. If needed, more PatchX directives can be added, incrementing the number each time, for example: Patch1, Patch2, Patch3, and so on. The patch files can be referred to elsewhere in the spec file using %{PATCH0}, %{PATCH1} etc.
Patches should be named in a consistent manner to make it very clear against which version of the software the patch was originally generated or applied. To that end, patch names usually follow the convention of [package_name]-[version]-[description].patch (e.g. refind-0.11.2-pclos-customizations.patch).
Patches should be in the unified format (diff -u) and should be applied with 1 strip level in the spec file (%patch -p1). The only exceptions are the patches obtained from another primary source site. The original name, suffix, and format is preserved in this case. Each patch should be kept in plaintext format and uncompressed.
For the patches to be applied, the patches should be mentioned in %prep section of the spec file and should be done as follows
%patch0 -p1 -b .foobar
- -p1 is the patch level, relative from where the patch is applied from
- -b is the suffix that is appended to the backup files which the patch command creates, in this case .foobar, this should similar to or derived from the [description] part of the patch filename (see above).
Alternatively you can use:
%apply_patches
This may be used to replace all the %patchN lines in %prep and can save space in the spec file (especially in packages with many upstream patches) as it will apply all patches listed with one command. However, for this to work all the patches must be -p1 and the PatchN: keyword definitions must be placed immediately following the SourceN: definitions in the spec file, otherwise they may be silently ignored (no error messages during build) so be careful.
BuildRequires
The BuildRequires tag is used to specify packages which need to be installed to successfully build this package. Having proper build requirements saves the time of all packagers because they will not need to search for missing build requirements manually. It is also a safety feature that prevents builds that would not otherwise fail, but would be missing crucial features. For example, a graphical application may exclude PNG support after its configure script detects that libpng is not installed.
BuildRequires should be listed one per line for maximum readability; instead of cramming multiple BuildRequires on a single line, use one BuildRequires tag per dependency. Also please check that you don't add unnecessary BuildRequires. If you BuildRequire package "A" and this has Requires on package "B" and "C" it's redundant to BuildRequire package "B" and "C" additionally.
Try to use architecture-independent virtual provides as BuildRequires when available. For example don't use lib64xcrypt-devel, but use either xcrypt-devel or pkgconfig(libxcrypt). You can check which virtual provides a -devel package has by using:
rpm -q --provides lib64xcrypt-devel
which would result in these:
libxcrypt-devel = 4.4.16-1pclos2020 xcrypt-devel = 4.4.16-1pclos2020 pkgconfig(libcrypt) = 4.4.16 pkgconfig(libxcrypt) = 4.4.16 devel(libcrypt(64bit)) lib64xcrypt-devel = 4.4.16-1pclos2020 lib64xcrypt-devel(x86-64) = 4.4.16-1pclos2020
As you can see, only the two recommended above have no reference to the architecture, unlike devel(libcrypt(64bit)) or lib64xcrypt-devel(x86-64).
If the build uses some binaries like desktop-file-install you must BuildRequire the packages which contain them too.
Requires
The Requires tag is used to specify explicitly any packages which are required by the software to run when installed. It is not usually necessary to specify these since we rely on rpmbuild to automatically add dependencies on shared library SONAMEs, shell script interpreters, and modules used by programs written in popular scripting languages like Perl & Python. Explicit dependencies on specific package names may aid the inexperienced user who attempts to install RPM packages manually, however, history has shown that such dependencies add confusion when library or files are moved from one package to another, when packages get renamed, or when one out of multiple alternative packages would suffice.
Deprecated tags
The BuildRoot tag is no longer required since the build root is handled directly by rpmbuild.
RPM sections
After the preamble the body of the spec file is divided into sections. Each section begins with an rpm directive and should be in the order given here.
%description
A full description of the software packaged in the RPM. This can span multiple lines and can be broken into paragraphs.
%prep
Command or series of commands and/or RPM directives to prepare the software for building. This includes unpacking the source files, patching etc.
%build
Command or series of commands and/or RPM directives for actually building the software (e.g. configure, make, cmake etc.).
%install
Command or series of commands and/or RPM directives for moving the objects built in the %build section to the buildroot which is the directory structure containing the files to be packaged.
%files
The list of files that will be installed on the end-user's system.
%changelog
A record of the changes that have been made to the package between different version or release builds. This gives information as to when the package was built, who built it , an email contact, version number. and a description of what was done to the package. The format of the changelog is as follows:
%changelog * Wed Nov 03 2010 Texstar <texstar at gmail.com> 1.3.6-1pclos2010 - new version - patch1 merged upstream - comment out patch2 as it does not build with it.
If the spec file is based on one from another distro then do not include the full changlog from that spec file. Just create a single entry with "Imported from xxxx". Changelog entries have to be in reverse chronological order: newer change log entries are listed above older entries, with the first entry being the most recent.
Deprecated sections
The %clean section is no longer used as this is handled automatically by rpmbuild. It should be removed if found in existing spec files.
Macros vs. variables
There are two styles of defining and referring to some variables in a spec file. Examples are BuildRoot and Optimization flags.
macro style | variable style | |
Build Root | %{buildroot} | $RPM_BUILD_ROOT |
Opt. Flags | %{optflags} | $RPM_OPT_FLAGS |
Variables which are really definitions, such as $RPM_OPT_FLAGS or $RPM_BUILD_ROOT should not be used. Macros like %{optflags} and %{buildroot} should be used instead. Keep "$*" variables strictly limited to shell constructs and not RPM-based definitions.
Packaging Documentation
Any relevant documentation included in the source distribution should be included in the package. Examples of irrelevant documentation include build instructions, the omnipresent INSTALL file containing generic build instructions and documentation for non-Linux systems, e.g. README.MSDOS. Pay also attention to which subpackage you include documentation in, for example, API documentation belongs in the -devel subpackage, not the main one. Or if there's a lot of documentation, consider putting it into a subpackage. In this case, it is recommended to use *-doc
as the subpackage name, and Documentation
as the value of the Group
tag.
Also, if a package includes something as %doc
, it must not affect the runtime of the application. To summarize: If it is in %doc
, the program must run properly if it is not present.
Check that documentation file permissions allow reading by normal users.
When only English man pages are available, install them uncompressed to %{buildroot}%{_mandir}/manX/
(where X is the appropriate section number). They will be automatically compressed before being packaged, so they must be referred to in the %files
section with a wildcard, e.g. %{_mandir}/man1/xyzzy.1*
. Man pages will be automatically given the %doc
attribute, so don't add that explicitly.
Devel Packages
If the software being packaged contains files intended solely for development, those files should be put in a -devel subpackage. The following are examples of file types which should be in -devel:
- Header files (such as .h files)
- Unversioned shared libraries (such as libfoo.so). Versioned shared libraries (such as libfoo.so.3, libfoo.so.3.0.0) should not be in -devel.
A good rule of thumb is if the file is used for development and not needed for the base package to run properly, it should go in -devel.
.a files and .la files should generally not be included anywhere. They are only useful for statically linking a program against the library (i.e. include the library in the program binary itself, so the library isn't needed at run-time), which is generally not done in most Linux distributions. Libtool archives, foo.la files, should not be included. Packages using libtool will install these by default even if you configure with --disable-static, so they may need to be removed before packaging. Due to bugs in older versions of libtool or bugs in programs that use it, there are times when it is not always possible to remove *.la files without modifying the program. In most cases, it is fairly easy to work with upstream to fix these issues. Note that if you are updating a library in a stable release (not devel) and the package already contains *.la files, removing the *.la files should be treated as an API/ABI change -- ie: Removing them changes the interface that the library gives to the rest of the world and should not be undertaken lightly.
Devel packages must require the base package using a fully versioned dependency:
Requires: %{name} = %{version}-%{release}
Usually, subpackages other than -devel should also require the base package using a fully versioned dependency.
The placement of pkgconfig(.pc) files depends on their usecase. Since they are almost always used for development purposes, they should be placed in a -devel package. A reasonable exception is when the main package itself is a development tool not installed in a user runtime, such as gcc or gdb.
Packages containing libraries should be built as shared libraries.
An ldconfig isn't needed anymore for libraries in %post
and %postun
, this is handled automagically by RPM filetriggers . If this is encountered, please remove the ldconfig calls and if this is the only purpose of %post / %postun then remove the whole %post / %postun section
Static Libraries
Packages including libraries should exclude static libs as far as possible (eg by configuring with --disable-static). Static libraries should only be included in exceptional circumstances. Applications linking against libraries should as far as possible link against shared libraries, not static versions.
- In general, packagers are strongly encouraged not to ship static libs unless a compelling reason exists.
- We want to be able to track which packages are using static libraries (so we can find which packages need to be rebuilt if a security flaw in a static library is fixed, for instance). There are two scenarios in which static libraries are packaged:
- Static libraries and shared libraries. In this case, the static libraries must be placed in a *-static-devel subpackage. Separating the static libraries from the other development files in *-devel allow us to track this usage by checking which packages
BuildRequire
the *-static-devel package. The intent is that whenever possible, packages will move away from using these static libraries, to the shared libraries. - Static libraries only. When a package only provides static libraries you can place all the static library files in the *-devel subpackage.
- If (and only if) a package has shared libraries which require static libraries to be functional, the static libraries can be included in the *-devel subpackage.
Configuration files
Configuration files must be marked as such in packages.
As a rule of thumb, use %config(noreplace)
instead of plain %config
unless your best, educated guess is that doing so will break things. In other words, think hard before overwriting local changes in configuration files on package upgrades. An example case when /not/ to use noreplace
is when a package's configuration file changes so that the new package revision wouldn't work with the config file from the previous package revision. Whenever plain %config
is used, add a brief comment to the specfile explaining why.
Don't use %config or %config(noreplace) for files in /usr because there should not be any configuration files there.
Desktop files
If a package contains a GUI application, then it needs to also include a properly installed .desktop file. Installed .desktop files MUST follow the desktop-entry-spec , paying particular attention to validating correct usage of Name, GenericName, Categories ,
StartupNotify
entries.
Please always validate .desktop files via desktop-file-validate
from the package desktop-file-utils.
Icon key in Desktop Files
The icon key can only be specified in one way:
- Short name without file extension/path:
Icon=comical
The short name without file extension allows for icon theming (it assumes .png by default, then tries .svg and finally .xpm)
.desktop file creation
If the package doesn't already include and install its own .desktop file, you need to make your own. You can do this by generating a .desktop file you create as a Source: (such as Source3: %{name}.desktop) or generating it in the spec file via a "here document". Here is an example of such a here document, the green part is the contents of the .desktop file
mkdir -p %{buildroot}%{_datadir}/applications
cat > %{buildroot}%{_datadir}/applications/%{name}.desktop << EOF
[Desktop Entry]
Name=Ginkgo
Comment=Ginkgo is a graphical front-end for Nepomuk
Exec=%{_bindir}/%{name}
Icon=nepomuk
Type=Application
Categories=Utility;KDE;Qt;
EOF
Localizing .desktop files
The values of Name or GenericName are displayed as captions to the graphical desktop icon, so they should be localized according to the Desktop Entry Specification. Most of the time, only language codes or language/country codes are needed to select the intended system locale. For example:
[Desktop Entry] Type=Application Name=Clocks Name[de]=Uhrzeit Name[es]=Relojes Name[fr]=Horloges Name[pt_BR]=Relógios Name[zh_CN]=时钟
In the above .desktop file, [de] specifies the German language locale, covering any German-speaking locale, such as de_DE or de_AT.
Note: Since a language/country code (e.g. pt_BR) is more specific than a language code (e.g. pt), a string for the pt_BR locale will not be used for the Portuguese language locale (pt). If a string is appropriate for every Portuguese locale, you can use "Name[pt]" instead.
The installation of the desktop file on the target system does not have to be handled manually anymore as had to be done previously in %post/%postun, this is automagically handled now via RPM filetriggers. Just make sure that all desktop files you want to install are correct and validated as pointed out above.
MandrivaLinux special categories
In many older .desktop files in packages imported from Mandriva there are deprecated X-MandrivaLinux category entries. They were used when switching from Debian Menu System to Freedesktop XDG menu system, and are deprecated and should be replaced by standard Freedesktop categories. Those can be seen in Freedesktop specification
Packaging Locale Files
Locale files, also known as localisations or (as an abbreviation) l10n files or i18n files (short form of internationalisation, the number shows how many letters have been left out) are compiled .mo files. This section is not about man pages.
(If a package includes translations, it is no longer needed to add the gettext BuildRequire, because gettext is already present in the build environment.)
There is an rpm macro called %find_lang
. This macro will locate all of the locale files that belong to your package (by name), and put this list in a file. You can then use that file to include all of the locales. %find_lang
should be run in the %install section of your spec file, after all of the files have been installed into the buildroot. The correct syntax for %find_lang
is usually:
%find_lang %{name}
In some cases, the application may use a different "name" for its locales. You may have to look at the locale files and see what they are named. If they are named myapp.mo
, then you will need to pass myapp
to %find_lang
instead of %{name
}.
After %find_lang
is run, it will generate a file in the active directory (by default, the top level of the source dir). This file will be named based on what you passed as the option to the %find_lang
macro. Usually, it will be named %{name}.lang
. You should then use this file in the %files
list to include the locales detected by %find_lang
. To do this, you should include it with the -f parameter to %files
.
%files -f %{name}.lang %{_bindir}/foobar ...
If you are already using the -f parameter for the %files
section where the locales should live, just append the contents of %{name}.lang
to the end of the file that you are already using with -f. (Note that only one file may be used with %files -f
.)
Why do we need to use %find_lang?
Using %find_lang
helps keep the spec file simple, and helps avoid several other packaging mistakes.
- Packages that use
%{_datadir}/*
to grab all the locale files in one line also grab ownership of the locale directories, which is not permitted. - Most packages that have locales have lots of locales. Using
%find_lang
is much easier in the spec file than having to do:
%{_datadir}/locale/ar/LC_MESSAGES/%{name}.mo %{_datadir}/locale/be/LC_MESSAGES/%{name}.mo %{_datadir}/locale/cs/LC_MESSAGES/%{name}.mo %{_datadir}/locale/de/LC_MESSAGES/%{name}.mo %{_datadir}/locale/es/LC_MESSAGES/%{name}.mo ...
- As new locale files appear in later package revisions,
%find_lang
will automatically include them when it is run, preventing you from having to update the spec any more than is necessary.
Keep in mind that usage of %find_lang
in packages containing locales is a MUST.
Scriptlets
Great care should be taken when using scriptlets in packages. If scriptlets are used, those scriptlets must be sane.
Scriptlets requirements
Do not use the Requires(pre,post)
style notation for scriptlet dependencies, because of two bugs in RPM. Instead, they should be split like this:
Requires(pre): ... Requires(post): ...
For more information, see www.redhat.com .
Running scriptlets only in certain situations When the rpm command executes the scriptlets in a package it indicates if the action preformed is an install, erase, upgrade or reinstall by passing an integer argument to the script in question according to the following:
macro | install | erase | upgrade | reinstall |
%pre | 1 | - | 2 | 2 |
%post | 1 | - | 2 | 2 |
%preun | - | 0 | 1 | - |
%postun | - | 0 | 1 | - |
This means that for example a package that installs an init script with the chkconfig
command should uninstall it only on erase and not upgrade with the following snippet:
%preun if [ $1 -eq 0 ] ; then /sbin/chkconfig --del %{name} fi
See also /usr/share/doc/rpm-*/triggers
, which gives a more formal, generalized definition about the integer value(s) passed to various scripts.
Scriplets are only allowed to write in certain directories Build scripts of packages (%prep, %build, %install, %check and %clean) may only alter files (create, modify, delete) under %{buildroot}, %{_builddir} and valid temporary locations like /tmp, /var/tmp (or $TMPDIR or %{_tmppath} as set by the rpmbuild process) according to the following matrix
/tmp, /var/tmp, $TMPDIR, %{_tmppath} | %{_builddir} | %{buildroot} | |
%prep | yes | yes | no |
%build | yes | yes | no |
%install | yes | yes | yes |
%check | yes | yes | no |
%clean | yes | yes | yes |
Further clarification: That should hold true irrespective of the builder's uid.
Obsoleting a package
- if the package is replaced by the other one which provides the same functionality, add it as obsolete in the new package.
- if the package is not replaced by an other one and is simply dropped, obsolete it by the task-obsolete package. Don't forget to add a comment with the reason for obsoleting.