Product SiteDocumentation Site

Following Good Practices

Working through problems is one thing. It’s best, however, to set up an environment to help avoid problems all together. The following sections cover what are considered the best practices for creating RPMs.
Before you make an RPM, you should plan out what you intend to build and how it will be structured. As you build the RPM, you want to watch out for things that can go wrong, and work from a known clean environment.

Preparation

Before you start to make an RPM, you need to follow a few steps to ensure you have everything ready.

Create a Source RPM

Having a source RPM allows you to transfer all the sources for a package from one system to another, along with all the instructions coded in the spec file for actually building the binary package. This is very handy for keeping track of software, and it is also very important since you can regenerate the binary RPM at any time from the source RPM. In other words, make the generation of RPMs follow the RPM conventions and fit this into your normal software build process.
This means that for each RPM you want to build, you really need two: a source and a binary RPM. This isn’t that hard to do, since you can easily make a source RPM into a binary RPM with the rpmbuild command.

Start with Pristine Sources

In addition to planning on making a source RPM, you should also start with pristine, unmodified sources for the application you plan to package as an RPM. Starting with pristine sources means you can reproduce the entire process and recreate the RPM from scratch if necessary. (Quality control and configuration management people really appreciate this.)
The pristine sources should be exactly the sources you got when you downloaded the application, or acquired it in house. This doesn’t mean that you won’t have to modify the sources eventually. For that, you create patches. The key is just to start the process with unmodified sources.
Some RPMs have nearly 100 patches that the rpmbuild command applies when building the RPM. That is a lot of patches, too many for most applications. Even so, the process is the same. Create a patch or patches for all the changes you need to make. You can easily specify patches in the spec file.
Cross Reference
Chapter 9, Working with Spec Files covers the spec file.
Keeping your patches separate from the original sources makes it easier to reproduce the RPM from scratch, and makes it easier to integrate a new version of the base software, since your code, in the form of patches, is separated from the base software code.

Decide What Goes In Each Package

You don’t have to stuff all your software into one RPM. Instead, you can often simplify your RPM by dividing it into two or three separate (but likely dependent) RPMs.
For example, the RPM system itself has one RPM for the basic system, rpm, one for developers of the RPM system, rpm-devel, and one for those building RPMs, rpm-build. Yet another RPM provides the Python programming API, rpm-python.
Cross Reference
Chapter 16, Programming RPM with Python covers Python programming.
This last division is important. The Python RPM draws in as a dependency the Python system itself. Adding this into, say, the core RPM package would needlessly complicate the dependencies for that package.
When dividing your software into RPMs, keep two main issues in mind:
*You want to divide the software into RPMs that fit the model for users of the system.
*You want to divide the software into RPMs such that the separate RPMs are simpler to create and manage.
The RPM system follows these guidelines, especially the first. Few users will extend the RPM system itself, which allows RPM team to shed this functionality from the core RPM and contain it in rpm-devel. Those who build RPMs fit into a different category than those who use RPMs since just about everybody needs to use RPMs to install packages, but few users actually build RPMs. Again, the separation works from a user’s perspective.
You also want your package divisions to make each package easier to specify. You can break particularly tough dependencies into smaller units and simplify things. If the package division doesn’t simplify things, then it may not be a good idea.

Create a Test RPM Database

You don’t always have to work with the system RPM database. In fact, while developing RPMs, you probably don’t want to change the system database.
If you have a test RPM database, you can install your RPMs into this test database. To do so, use the --justdb, --dbpath, --prefix, and --badreloc options. These options allow you to install an RPM into just the database, using a different database, with a different root file location (into a test directory, for example) and handle all files that were not marked for relocation, respectively.
Note
The --test option when installing also allows you to just test the install, not actually perform it.
Combined, all these options mean you can use an RPM database just set up for testing and that problems won’t impact your working Linux systems. To make this work, though, you need a test RPM database.
To be rigorous, you should create the test RPM database from scratch from a known set of packages. This will allow you to exactly verify the behavior of your RPM under different system configurations. This is the best choice since you should install the packages under a known, and non-root, directory hierarchy to avoid having file problems with the working system.
If you want to cheat, you can copy your real RPM database to another directory and use that. Note that in this case, the file paths in the database will point to the real file locations on disk.
Regardless of how you create a test database, recreate the database each time you run a test, so that you are sure of a known starting state. Usually this is as simple as copying a master test RPM database into a directory you use for running tests.