Archive:BuildingPackagesGuide

--

Documentation Summary:

Purpose: Document to explain how to build and modify packages.

Audience: Experienced users interested in building RPM packages, either for the Fedora Project or their own use.

Assumptions: Reader has root access to a Fedora system.

Related Documents: Maximum RPM; RPM HOWTO

Lead Writer: Ignacio Vazquez-Abrams

--

RahulSundaram Note to Writer:

There seems to be a related guide available. You might want to combine the work being done

http://koti.welho.com/vskytta/packagers-handbook/packagers-handbook.html

VilleSkyttä notes: packagers-handbook is in docs CVS, see http://cvs.fedora.redhat.com/viewcvs/packagers-handbook/?root=docs

--

= Building Packages in Fedora =

Changelog
2005.08.22: 0.0: Initial proposal (Ignacio Vazquez-Abrams) 2005.08.30: 0.1: Moved to wiki (Ignacio Vazquez-Abrams) 2005.09.10: 0.2: Filled in intro to "Creating a New Package" and "Case Study: leafpad" (Ignacio Vazquez-Abrams) 2005.10.31: 0.3: Filled in mock appendix (Ignacio Vazquez-Abrams) 2005.12.30: 0.4: Adjusted the creating a non-root rpmbuild Buildroot (James Lawrence) 2006.03.16: 0.5: Filled in the library section (Ignacio Vazquez-Abrams) 2009.03.30: 0.6: Pruned empty sections (Ignacio Vazquez-Abrams)

Introduction
RPM (RPM Package Manager) is at the heart of Fedora. It is responsible for installing new software, as well as tracking files so that the same software can be uninstalled with a minimum of fuss. But RPM on its own doesn't actually do anything. It's up to the packager to specify how a package is built, as well as explaining what sort of files the package contains, and what other packages it relies upon for proper operation.

Goals
This guide explains how to create packages under Fedora as opposed to other RPM-based Linux distributions. It is not intended to be an exhaustive guide to all possible spec file and rpmbuild options. For those you are invited to look at the latest snapshot of Maximum RPM.

Intended Audience
This guide is written for people who want to build packages in Fedora, either for themselves or for others.

Structure of a Package
This contains things such as the name, version, release, epoch, and architecture the package was built for, as well as what this package requires from other packages and what it provides to other packages.
 * Header

This contains all files, directories, symlinks, etc. contained in the package, as well as the size, permissions, ownership, and SELinux file context.
 * Files

This contains the scripts to be run during package install and uninstall, as well as the script run during an RPM verify.
 * Scripts

Creating a New Package
Tarballs are convenient. They can hold almost anything and they can be opened on almost any operating system. The problem is that files installed from a tarball are almost impossible to track. For this reason it's useful to be able to turn a tarball into a package. This chapter shows you examples of this.

Creating a non-root Buildroot
Most software source code comes in the form of tarballs (a tar archive compressed with either gzip or bzip2). It's possible to inadvertently have code in a makefile or script in a tarball that could damage your system. For this reason it's best to build packages as a user that doesn't have full access to the system.

Creating a non-root buildroot is easy:


 * 1) As root, install the   package:
 * 2) As a normal user, run  . This creates a   directory where packages are built as well as adding vital options to the   file.
 * 3) Open   in a text editor and add a few more useful options at the end of the file:
 * 4) * "%packager Your Name Here "
 * 5) ** This allows other people to find you should they have questions if your package ever gets released into the public.
 * 6) * "%vendor Your Callsign Here"
 * 7) ** This provides an easy way to separate your packages from packages of the same software made by other sources.

Case Study: leafpad
Leafpad is a simple application. For installation, it only requires the binary, the icon, the menu entry, and gettext translations. This makes it a good project to examine for packaging. The homepage for leafpad itself is at http://tarot.freeshell.org/leafpad.

The first step is to go into the buildroot and create a new spec file for your package. In a terminal run the following commands:

cd ~/rpmbuild/SPECS rpmdev-newspec leafpad

This creates a new spec file called.

Open the spec file in a text editor.

Name:          leafpad Version: Release:       1 Summary:

Group: License: URL: Source0: BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

BuildRequires: Requires:

%description

%prep %setup -q

%build %configure make %{?_smp_mflags}

%install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT

%clean rm -rf $RPM_BUILD_ROOT

%files %defattr(-,root,root,-) %doc

%changelog

Since this is an unofficial package, the first thing you do is set the release to something lower than 1. Also, put a "tag" in the release to help show where the package comes from. Then follow it with the actual release in the sequence of packages that you may eventually release.

Next you fill in the version (as of writing this, 0.8.3) as well as add a summary pulled from the website.

Version:       0.8.3 Release:       0.docs.1 Summary:       A GTK+ based simple text editor

Now you need to categorize the package into an appropriate group. The groups are listed in  or in RPMGroups. In this case the appropriate group is Applications/Editors since leafpad is a text editor.

For the license field, leafpad uses the GPL. From the leafpad website, get the URL for downloading leafpad 0.8.3.

Use this information to fill out the next section:

Group:         Applications/Editors License:       GPL URL:           http://tarot.freeshell.org/leafpad/ Source0:       http://savannah.nongnu.org/download/leafpad/leafpad-0.8.3.tar.gz

Next you must deal with BuildRequires and Requires. According to the leafpad webpage, it needs GTK+ >= 2.0.0 in order to build or run. You can let RPM figure out what libraries it needs to run, so fill in BuildRequires and comment out Requires for now.

BuildRequires: gtk2-devel >= 2.0.0
 * 1) Requires:

Add a description for the package. The lines of text in %description should be at most 79 charaters long.

%description Leafpad is a GTK+ based simple text editor. The user interface is similar to Notepad. It aims to be lighter than GEdit and KWrite, and to be as useful as them.

For now we'll skip most of the sections and just worry about %changelog at this time. Fill it in with the date (the command  will give you the exact text you should put), your name, your e-mail address, the version and release of the package, and a short description of what's changed in the package. Since this is the first package we'll just say that instead.

%changelog - Initial RPM release
 * Gud Fez 74 6395 Foobly Barowitz  0.8.3-0.docs.1

So now the spec file should look like this (except with today's date and your name and e-mail address in %changelog):

Name:          leafpad Version:       0.8.3 Release:       0.docs.1 Summary:       A GTK+ based simple text editor

Group:         Applications/Editors License:       GPL URL:           http://tarot.freeshell.org/leafpad/ Source0:       http://savannah.nongnu.org/download/leafpad/leafpad-0.8.3.tar.gz BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

BuildRequires: gtk2-devel >= 2.0.0
 * 1) Requires:

%description Leafpad is a GTK+ based simple text editor. The user interface is similar to Notepad. It aims to be lighter than GEdit and KWrite, and to be as useful as them.

%prep %setup -q

%build %configure make %{?_smp_mflags}

%install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT

%clean rm -rf $RPM_BUILD_ROOT

%files %defattr(-,root,root,-) %doc

%changelog - Initial RPM release
 * Gud Fez 74 6395 Foobly Barowitz  0.8.3-0.docs.1

Now you need to actually download the source for leafpad and put it in the right place. Go ahead and download the tarball with your browser, wget, curl, or some other tool, then move it to ~/rpmbuild/SOURCES.

So now that you have the spec file and the sources, you need to actually go through the motions of building the package, which involves going through to the end of %build. Type the following commands in a terminal:

cd ~/rpmbuild/SPECS rpmbuild -bc leafpad.spec

At this point you will most likely end up with an error message, especially if you've never built any software on your machine before. Let's work through them one at a time.


 * bash: /usr/bin/rpmbuild: No such file or directory

This indicates that you need to install the rpm-build package, however you should already have it installed since it's a dependency of rpmdevtools which you had to install in order to previously create the non-root buildroot.

gtk2-devel >= 2.0.0 is needed by leafpad-0.8.3-0.docs.1.i386
 * error: Failed build dependencies:

This message tells you that you need to install files or packages in order to build the package. You can use yum to install the files or packages that it indicates. In this case you would use  in order to do so.

Once you get a clean build the last line of output will be. You can then go ahead and test %install like so:

rpmbuild -bi leafpad.spec

At this point you definitely will see errors:

RPM build errors: Installed (but unpackaged) file(s) found: /usr/bin/leafpad /usr/share/applications/leafpad.desktop /usr/share/locale/bg/LC_MESSAGES/leafpad.mo /usr/share/locale/ca/LC_MESSAGES/leafpad.mo /usr/share/locale/cs/LC_MESSAGES/leafpad.mo /usr/share/locale/de/LC_MESSAGES/leafpad.mo /usr/share/locale/es/LC_MESSAGES/leafpad.mo /usr/share/locale/fr/LC_MESSAGES/leafpad.mo /usr/share/locale/hu/LC_MESSAGES/leafpad.mo /usr/share/locale/it/LC_MESSAGES/leafpad.mo /usr/share/locale/ja/LC_MESSAGES/leafpad.mo /usr/share/locale/lt/LC_MESSAGES/leafpad.mo /usr/share/locale/pl/LC_MESSAGES/leafpad.mo /usr/share/locale/pt/LC_MESSAGES/leafpad.mo /usr/share/locale/ru/LC_MESSAGES/leafpad.mo /usr/share/locale/sk/LC_MESSAGES/leafpad.mo /usr/share/locale/sv/LC_MESSAGES/leafpad.mo /usr/share/locale/ta/LC_MESSAGES/leafpad.mo /usr/share/locale/vi/LC_MESSAGES/leafpad.mo /usr/share/locale/zh_CN/LC_MESSAGES/leafpad.mo /usr/share/locale/zh_TW/LC_MESSAGES/leafpad.mo /usr/share/pixmaps/leafpad.png

The next step is to take all those files and put them in %files. But just copying and pasting them would be the wrong thing to do.

RPM has a number of macros that can be used to shorten the spec file or add needed flexibility. You can see some of the directory-based macros in RPMMacros. You can get a complete list by running.

So go ahead and add all of the files except the ones under /usr/share/locale to %files, substituting macros where appropriate.

%files %defattr(-,root,root,-) %doc %{_bindir}/leafpad %{_datadir}/applications/leafpad.desktop %{_datadir}/pixmaps/leafpad.png

Now you just need to handle the files under /usr/share/locale. Fortunately Fedora provides the  macro for that. It looks for all files under /usr/share/locale that match the argument you pass it and puts them in a file of the same name appended with ".lang". The macro is called at the end of %install. Since the name of the package is "leafpad" we can just use the appropriate macro instead.

%install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %find_lang %{name}

And you also need to tell %files to include the files listed in the generated file.

%files -f %{name}.lang %defattr(-,root,root,-) %doc %{_bindir}/leafpad %{_datadir}/applications/leafpad.desktop %{_datadir}/pixmaps/leafpad.png

At this point the package will build, but there is another step to take before you're ready.

You need to fill in the %doc specifier in %files with any documentation for the app. Go to  and look at the files there. Most of them are only needed to build the app, but some are useful to include. The specific files you're interested in are AUTHORS, ChangeLog, COPYING, NEWS, and README, so go ahead and add them to %doc in %files.

%files -f %{name}.lang %defattr(-,root,root,-) %doc AUTHORS ChangeLog COPYING NEWS README %{_bindir}/leafpad %{_datadir}/applications/leafpad.desktop %{_datadir}/pixmaps/leafpad.png

Now you can go ahead and test the package again.

rpmbuild -bi leafpad.spec

Success! You can now go ahead and build the binary and source packages.

rpmbuild -ba leafpad.spec

Close to the end of the process you'll see three files being written. The first one is the source package, the second is the binary package, and the third is the debug information for the binary package. If you already have leafpad installed from Fedora go ahead and remove it now, and install the new binary package as root.

rpm -e leafpad rpm -Uvh /path/to/leafpad-0.8.3-0.docs.1.$(uname -i).rpm

After installing it a menu entry named Leafpad should appear under Accessories. Go ahead and run it, and try it out a bit.

You may notice that leafpad currently uses the old-style GTK+ file dialog box for opening and saving files. In order to make it use the new-style file dialog box you need to pass an option to configure. Normally you would run  to show us the different options, but the act of producing a proper package wipes the necessary files. In a terminal run the following:

cd ~/rpmbuild/SPECS rpmbuild -bp leafpad.spec

This goes through just the %prep section of the spec file (unpacks the tarball and applies any patches). Now you can do the following to see the options:

cd ~/rpmbuild/BUILD/leafpad-0.8.3 ./configure --help

In this case the option you're looking for is. Go ahead and modify %build appropriately.

%build %configure --enable-chooser make %{?_smp_mflags}

Now you need to increment the release and add the %changelog entry.

Version:       0.8.3 Release:       0.docs.2 Summary:       A GTK+ based simple text editor

%changelog - Enabled new-style GTK+ file dialog
 * Wed Jan 30 2008 Foobly Barowitz  0.8.3-0.docs.2

- Initial RPM release
 * Mon Jan 21 2008 Foobly Barowitz  0.8.3-0.docs.1

So now rebuild the package.

rpmbuild -ba leafpad.spec

Since the release of the new package is higher than the old package you can just upgrade it directly as root.

rpm -Uvh /path/to/leafpad-0.8.3-0.docs.2.$(uname -i).rpm

When you run it you will see that loading and saving files now uses the new-style file dialog box.

Case Study: OpenEXR
OpenEXR is a library created by Industrial Light & Magic  for creating and using high dynamic range images. Create and fill in a spec file for OpenEXR in the same manner as you did for leafpad.

Name:          OpenEXR Version:       1.2.2 Release:       0.docs.1 Summary:       A high dynamic-range (HDR) image file format

Group:         System Environment/Libraries License:       BSD URL:           http://www.openexr.com/ Source0:       http://savannah.nongnu.org/download/openexr/OpenEXR-1.2.2.tar.gz BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

BuildRequires:
 * 1) Requires:

%description OpenEXR is a high dynamic-range (HDR) image file format developed by Industrial Light & Magic for use in computer imaging applications.

%prep %setup -q

%build %configure make %{?_smp_mflags}

%install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT

%clean rm -rf $RPM_BUILD_ROOT

%files %defattr(-,root,root,-) %doc

%changelog - Initial RPM release
 * Gud Fez 74 6395 Foobly Barowitz  1.2.2-0.docs.1

Unfortunately the OpenEXR website is far less forthcoming regarding what packages are required to build the library. Comment out the BuildRequires line for now, download the source tarball, and run the prep stage.


 * 1) BuildRequires:
 * 2) Requires:

rpmbuild -bp OpenEXR.spec

Go into the BUILD/OpenEXR-1.2.2 directory and open the INSTALL file there. Most packages have build instructions in this file. Some even include a list of build requirements. Unfortunately OpenEXR does not.So then close this file and open README instead. About halfway through the file it reads "exrdisplay requires FLTK 1.1 or greater" so go ahead and add this to BuildRequires, remembering to uncomment it.

BuildRequires: fltk-devel >= 1.1
 * 1) Requires:

Now try to compile the package:

rpmbuild -bc OpenEXR.spec

error: Failed build dependencies: fltk-devel >= 1.1 is needed by OpenEXR-1.2.2-0.docs.1.i386

Of course, you need to actually install the  package in order to build OpenEXR, so do so now with yum. Once that is done, try compiling the package again.

checking for strerror... yes checking for compress in -lz... no configure: error:
 * OpenEXR requires a recent version of zlib, which you don't appear to
 * have.
 * This could be because the run-time linker is not finding zlib, or it
 * is finding the wrong version. In this case, you'll need to set your
 * LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point
 * to the proper version. Also, make sure you have run ldconfig if
 * that is required on your system.
 * that is required on your system.

error: Bad exit status from /var/tmp/rpm-tmp.XXXXX (%build)

RPM build errors: Bad exit status from /var/tmp/rpm-tmp.XXXXX (%build)

It seems that FLTK isn't the only package required to build OpenEXR. Go ahead and add zlib-devel to BuildRequires and install it via yum.

BuildRequires: fltk-devel >= 1.1 zlib-devel
 * 1) Requires:

Now compile once more.

[more messages above] makeTiled.cpp: In function 'void ::reduceY(const TypedImageChannel&, TypedImageChannel&, bool, Extrapolation, bool) [with T = unsigned int] ': makeTiled.cpp:447:  instantiated from here makeTiled.cpp:318: error: 'class TypedImageChannel ' has no member named 'image' makeTiled.cpp:319: error: 'const class TypedImageChannel ' has no member named 'image' makeTiled.cpp:320: error: 'class TypedImageChannel ' has no member named 'image' make[1] : *** [makeTiled.o] Error 1 make: *** [all-recursive] Error 1 error: Bad exit status from /var/tmp/rpm-tmp.XXXXX (%build)

RPM build errors: Bad exit status from /var/tmp/rpm-tmp.XXXXX (%build)

Isn't this an interesting predicament. What has happened here is that the compiler has detected a problem in the source and is failing because the compiler cannot make sense of it. If you scroll back to the first few error messages you can get a clue about what is causing the error.

./Image.h:59: error: expected. Scroll up a bit further to find out where this file is located.

Making all in exrmaketiled make[1] : Entering directory, and go to line 59.

class ImageChannel { public:

friend class Image;

ImageChannel (Image &Image); virtual ~ImageChannel;

virtual Imf::Slice slice  const = 0;

Image &            image                 {return _image;} const Image &      image  const          {return _image;}

What you have here is the beginning of the declaration for the  class. When you examine the problems in the error messages listed above in relation to the source code you will notice that they all refer to. The C++ standard dictates that you cannot use a type until the compiler knows about it, however the  declaration on line 57 is not enough to do so. You must add a line telling the compiler about the  class. But before you do so, copy the file to :

cp Image.h Image.h.friend

Now put a forward declaration of the  class before the declaration of the   class. You are supposed to edit the original file, not the new.

class Image;

class ImageChannel {

Since RPM uses pristine tarballs to build packages, you now need to make a patch containing the difference between the original file and the modified file. RPM provides a convenient tool for this called. When run against a directory and passed a suffix it will compare all files with that suffix to the corresponding files without that suffix and generate a patch with the changes:

cd ~/rpmbuild/BUILD gendiff OpenEXR-1.2.2 .friend > ../SOURCES/OpenEXR-1.2.2-friend.patch

The generated patch should look similar to this:

--- OpenEXR-1.2.2/exrmaketiled/Image.h.friend  YYYY-MM-DD hh:mm:ss.xxxxxxxxx -ZZZZ +++ OpenEXR-1.2.2/exrmaketiled/Image.h YYYY-MM-DD hh:mm:ss.xxxxxxxxx -ZZZZ @@ -49,6 +49,7 @@

+class Image;

class ImageChannel {

Now add the patch to the spec file so that rpmbuild uses it during the build.

Source0:       http://savannah.nongnu.org/download/openexr/OpenEXR-1.2.2.tar.gz Patch0:         OpenEXR-1.2.2-friend.patch BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

%prep %setup -q %patch0 -p1 -b .friend

%build

Compile the package once again.

make[1] : Leaving directory  subpackage to contain the files required for building packages against OpenEXR.

%description OpenEXR is a high dynamic-range (HDR) image file format developed by Industrial Light & Magic for use in computer imaging applications.

%package       devel Summary:       Headers and libraries for building apps that use OpenEXR Group:         Development/Libraries Requires:      %{name} = %{version}-%{release}

%description   devel This package contains headers and libraries required to build applications that use the OpenEXR format.

%prep

%files %defattr(-,root,root,-) %doc

%files devel %defattr(-,root,root,-) %doc

%changelog

The tarball also rudely places examples in the documentation directory of the main package when it would make more sense to have them in the devel subpackage.

%install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT%{_defaultdocdir}/%{name}-%{version}/examples

All executables and *.so.* files should be placed in the main package.

%files %defattr(-,root,root,-) %doc %{_bindir}/* %{_libdir}/*.so.*

All headers, static libraries, libtool archives, *.so files, autotools, and pkgconfig files go in the -devel subpackage.

%files devel %defattr(-,root,root,-) %doc %{_includedir}/%{name} %{_libdir}/*.a %{_libdir}/*.la %{_libdir}/*.so %{_libdir}/pkgconfig/%{name}.pc %{_datadir}/aclocal/*.m4

We should add the examples to the documentation in the -devel subpackage. Normally we would use

%doc examples

to do this, but unfortunately there are 2 problems. The first is that the directory isn't called "examples". By looking at the various files under BUILD/OpenEXR-1.2.2 we find that the directory is actually called "IlmImfExamples". The second problem is that the directory will contain several files that we don't want included in the final package. What should be done is to copy it in %prep to the proper name and remove to undesired files, and then add it to %doc in -devel, and any appropriate files to %doc in the main package.

%prep %setup -q %patch0 -p1 -b .friend cp -a IlmImfExamples examples rm examples/Makefile*

%files %defattr(-,root,root,-) %doc AUTHORS ChangeLog LICENSE NEWS README %{_bindir}/* %{_libdir}/*.so.*

%files devel %defattr(-,root,root,-) %doc examples %{_includedir}/%{name} %{_libdir}/*.a %{_libdir}/*.la %{_libdir}/*.so %{_libdir}/pkgconfig/%{name}.pc %{_datadir}/aclocal/*.m4

Since the package places shared libraries into normal directories /sbin/ldconfig will have to be invoked after the package has been installed or removed as described in ScriptletSnippets.

%clean rm -rf $RPM_BUILD_ROOT

%post -p /sbin/ldconfig

%postun -p /sbin/ldconfig

%files

So now if you rebuild it you will find that it builds cleanly. Go ahead and build and then install the binary packages.

rpmbuild -bb OpenEXR.spec

rpm -Uvh /path/to/OpenEXR-1.2.2-0.docs.1.arch.rpm /path/to/OpenEXR-devel-1.2.2-0.docs.1.arch.rpm

Appendix: mock: Chroot Buildtool
Turning a spec file, a tarball, and patches into an actual package is a complex process. Installed development packages can poison the package with unexpected capabilities, which will cause users of the package to complain when their builds lack those capabilities. Additionally, it is very easy to miss BuildRequires that need to be added to the spec file.

Unix-class operating systems provide a facility known as chroot which causes a subdirectory to become the new root directory temporarily. is a tool which takes advantage of this facility to provide a "cleanroom" build of a source package. Only a basic set of packages plus the packages listed in BuildRequires are installed into the chroot and then mock builds the package under the chroot. This creates a clean, reproducible build of the package.

takes the following command line arguments:


 * : This gives the root you want to use. It should match one of the configuration files in.
 * : This tells mock where you want the logs and built packages to be placed.
 * : This is the source RPM you want to rebuild.

E.g.,

The configuration file is actually a Python script that creates a dictionary that contains all the values used by   for generating the chroot and building source packages. The keys in the dictionary include:


 * : The directory under  in which to generate the chroot.
 * : The processor architecture the chroot handles.
 * : The yum configuration file content used by the chroot.
 * : A set of RPM macros to be initialized by.