initCommon(); $template->displayHeader(); ?>

Chapter 4. Building RPM Packages

This chapter attempts to discuss how to build RPMs so that the package conforms to Fedora Project standards. It does not attempt to explain everything there is to know about RPM or building RPMs.

A good source for learning more about RPM is the Red Hat RPM Guide by Eric Foster-Johnson; Red Hat Press.

4.1. Spec File

This section describes how the spec file should be written.

Name: foo
Summary:  The foo package does foo
Version: 1.0
Release: 1
License: GPL
Group: Applications/Internet
URL: http://www.example.org/
Source0: %{name}-%{version}.tar.gz
Patch0: foo-1.0-iconfix.patch
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root
Requires: anything
Prereq: something
BuildPrereq: something-else

%description 
This package performs the foo operation.
%prep 
%setup -q
%patch0 -p1 -b .iconfix

%build 
%configure 
make

%install 
rm -fr %{buildroot}

%makeinstall

%clean 
rm -fr %{buildroot}

%post 
/sbin/chkconfig --add foo 
/sbin/ldconfig

%preun 
if [ "$1" = 0 ]; then 
  /sbin/service foo stop > /dev/null 2>&1 
  /sbin/chkconfig --del foo 
fi

%postun 
if [ "$1" -ge "1" ]; then 
  /sbin/service foo condrestart > /dev/null 2>&1 
  /sbin/ldconfig 
fi

%files 
%defattr(-,root,root) 
%{_bindir}/* 
%{_mandir}/* 
%{_datadir}/* 
%{_doc}/*

%changelog 

* Mon Jun 16 2003 Some One <one@example.com>
— fixed the broken frobber (#86434)
Name

The name of the package.

Summary

A short summary of the purpose of the package, should not include the name of the package in the summary as this is redundant information.

Version

The version of the package. Should match the version of the (main) tarball of the source. If the "real" version has dashes in it, replace them with underscores.

Release

This is the Fedora Project release count for the package. Each time it is modified for the Fedora Project (sent through the build system) this number must be incremented. NEVER rebuild a package without incrementing this number, as this gives a totally false impression to the user — that the package has not changed at all. Whenever a package is rebuilt, it changes, even if the source code was not updated.

License

One of GPL, LGPL, BSD(-like), Artistic, etc. Most old packages erroneously call this the "Copyright" field. This is incorrect but the two are synonyms for each other. Fix old packages to have the correct tag if found.

Group

This must be one of the canonical groups from the /usr/share/doc/rpm-<version>/GROUPS file. Do not make up group names.

URL

The Web address for the package, if one exists.

Source

Start numbering the sources at 0 (Source0 , Source1, etc.). A tag of Source is implicitly source 0. Include the full URL or path to the source package if necessary. If a filename without a URL or path is given as the source, the file should be in the SOURCES directory under your top level directory — /usr/src/redhat/SOURCES/ by default or define the top level directory in your ~/.rpmmacros file.

Use the special macros %name and %version where possible so that updating these particular fields automatically update the source field.

Patch

Start numbering patch files with 0 (Patch0, Patch1, etc.). To make patches, name them in the format <name>-<version>-<whatisfixed>.patch. Do not use the %name and %version macros here; chances are these patches may be needed even when you upgrade the package source code after generating the initial patch, and it will probably apply without modifications. If you use the macros, you will have to rename or regenerate your patch. Please send any patches that you make to the upstream package maintainer at the time you generate them, as well as any hacks you have to do in your spec file to get things to build cleanly. Only if we make a better effort to do this will the tons of little changes we have to make in our own packages be integrated upstream over time.

To create a patch, follow this process:

  1. Enter the directory where the source code for the package is, and copy the original file to the same name as the file with the <whatisfixed> string appended to it. For example, if the the old file was called sourcecode.c, copy it to sourcecode.c.iconfix.

  2. Then, make your edits/changes/fixes to the file sourcecode.c.

  3. Go into the directory one level above the sourcecode, usually the directory ../BUILD. Use the gendiff command from the rpm package to generate the patch file:

    gendiff <source-dir> <fixed-extension> > ../SOURCES/<source-dir>-<fixed-extension>.patch
    

    For example, if the source code is in the directory program-1.0/, and the backup file was appended with the string iconfix, the command would be as follows:

    gendiff sourcecode-1.0 .iconfix > ../SOURCES/sourcecode-1.0-iconfix.patch
    
Buildroot

Make sure you use the special %{_tmppath} macro. Do not hard code /tmp/ or /var/tmp/ because users or the build system may have configured RPM to put temporary files elsewhere or may declared a different location for temporary files. Use the name and version macros so that two different versions of the package can be built at the same time without collisions.

Requires

If your package requires other packages to be on the system at the time of installation, list them here. Include versions if necessary (for example, somepackage >= 2.0). Multiple entries must be separated by a space or a comma. Explicit file dependencies may be listed rather than package dependencies by giving the full path (for example, /sbin/chkconfig).

Prereq

Similar to Requires, except that this tag lists packages or files that are required to be present before the package is actually installed. Very important if you are packaging something that needs to make use of other programs in %pre or %post sections.

BuildPrereq

If your package needs other packages installed to build, list them after this tag. Examples include gtk2-devel and db3-devel.

%description

Make your description as complete as possible, but not more than 10-15 lines of text. If other packages are necessary, or this package works with others, it is probably wise to describe the specifics of that operation here.

%prep

This phase should unpack the source code and apply any patches necessary for the build. Additionally, if autoconf and/or automake needs to be rerun, do so here. You usually unpack source code with the %setup macro, and usually provide the -q flag so that it is quiet while unpacking:

%setup -q

Other options to %setup include:

  • -a <num>, where <num> is the number given the source file such as 0 for source0, means that only the source files specifies should be unpacked. The files are unpacked after changing to the directory.

  • -b <num>, where <num> is the number given the source file such as 0 for source0, means that only the source files specifies should be unpacked. The files are unpacked before changing to the directory.

  • -c is used to create the directory before unpacking the sources.

  • -n <name> can be used to specify the directory name

  • -D specifies that the directory should not be deleted before unpacking.

While applying patches, be sure to provide the -b argument followed by the string you used in the name of the patch file:

%patch0 -p1 -b .<fixupstring>
%build

Include the command necessary to build the program in this section (for example, make).

Always use the %configure macro where possible. This macro expands to automatically configure properly packaged programs that use autoconf and automake. It sets up all the paths and optimized CFLAGS correctly for whatever version of Fedora Core you are building on. If you need to provide extra flags, do so after the %configure entry. Example:

%configure --extra-flag=yes
%install

Include all the command needed to install the package.

Usually you want to clean out any old buildroots that might be lying around before actually installing files into it:

rm -fr %{buildroot}
%makeinstall

Like the %configure macro, the %makeinstall macro correctly installs a autoconf/automake style package into your buildroot. Use it where possible.

%clean

Supply a command to clean up your buildroot. Usually the command rm -fr %{buildroot} suffices.

%post

Include anything that needs to happen immediately after package installation. For example, if the package includes an initscript that needs to be run to start the service. Another example is if the ldconfig command needs to be run after installing or upgrading any system libraries. Provide the full path to the commands.

%preun

Similar to the %post section, but run right before a package is removed. For example, it can check what the package reference count is. This is important to know whether you are upgrading a package (which involves installing a new version and then removing an old version) or just uninstalling the package. In an upgrade, the reference count check on the $1 variable returns a number greater than 1 (corresponding to the number of packages with that name still installed). When it is being uninstalled, it will return 0.

If you are going to stop a service and remove it from use in your %preun section, you want to make sure you are really removing the package, and not just upgrading.

%postun

Similar to the %preun section, but run after a package is removed. In this example, the service is restarted if and only if it remains on the system. We do this in the postuninstall phase of the "old" package. If the reference count on the package name is greater than or equal to one, we know the package is still on the system (for example, it was upgraded, not removed), and the service is restarted if it was already running with the condrestart directive.

[Warning]Warning

All script sections of an RPM, including %pre, %preun, %post, %postun should never output to standard error or standard out. Redirect those messages to /dev/null if they can not be avoided. If the package is installed in a batch fashion, via a graphical RPM tool, or via an automated system, the user never sees those messages. Do not rely on standard error or standard out text in one of these sections for giving the user additional instructions after an RPM has been installed. For the same reasons, scripts should never be interactive.

%files

List the files that should be included in the package. The files listed here are displayed when the rpm -ql command is issued for the package.

A package should not put a file in a directory that it does not own and that none of its dependencies own. If this happens, the file is removed when the package is removed, but the directory is not.

Another common mistake is to put a file in a directory that another package owns without adding a dependency on that package. For example, assume mypkg owns the /foo/ directory and yourpkg owns the /foo/bar file. If both packages are installed and then mypkg is removed, the /foo directory is not removed because it is not empty. And when yourpkg is removed, the file is removed, but the directory is not.

In summary, make sure the package owns all the directories it uses or you depend on packages that do.

Use the FHS transparent macros that are defined on a per-platform basis so the package is portable back to older versions of Fedora Core if the locations for these special directories change.

Other macros for directories include:

  • %{_bindir}bin directory for the system

  • %{_mandir} — the default directory for manual pages

  • %{_datadir} — the default share directory location

  • %{_defaultdocdir} — the default directory for documentation

The %defattr macro specifies what the default permissions, user, and group are for files found in the %files section. In almost every case specify the following:

%defattr(-,root,root,-)

It is is in the form (file permissions, owner, group, directory permissions). If a dash (-) is specified for any field, whatever the actual permissions/ownership of the file in the buildroot are at packaging time are used instead.

If necessary, specify attributes on a particular file can also be specified to make sure they are correct. For instance, to make sure a file has the mode 0400:

%attr(0400,root,root) /etc/readonlyrootfile

If the file is a directory, it can be marked as a directory with the %dir prefix. %dir is only required if the directory only (and not the files under it) should be packaged (or package the files under it with different flags). Listing a directory only includes the directory, not the file in it and not any of its subdirectories.

%dir %{_datadir}/%{name}

If the file is a documentation file, mark it with the %doc prefix. The paths are relative to the RPM build directory. For example:

%doc doc/*

If it is a configuration file it should be marked as follows:

%config <filename>

If the configuration file should not be replaced when the RPM is upgraded, mark it as follows:

%config(noreplace) <filename>

For files that should be included in the list of files so that they are uninstalled when the package is removed but may not exist until they are created during post-install should be marked as follows:

%config(missingok) <filename>
%changelog

Supply a changelog entry whenever a change to a package is made. It must be in proper format as shown in the example. Be as descriptive as possible; sentences such as fixed bug does not example what has been fixed. If the changes include a fix for a bug filed in Bugzilla, include the Bugzilla number in the changelog entry.

displayFooter('$Date: 2005/12/06 19:37:03 $'); ?>