Chapter 19

Using RPM on Non-Red Hat Linuxes

Copyright (c) 2005 by Eric Foster-Johnson. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/).

In This Chapter

*	Dealing with RPM issues on other versions of Linux

*	RPM standardization

*	Working around RPM differences when installing RPMs

*	Working around RPM differences when building RPMs

*	Dealing with non-RPM-based Linux distributions

Although its name was originally the Red Hat Package Manager, RPM has been adopted by most major Linux distributions. With this adoption, RPM has moved from its Red Hat roots, and RPM now stands for the RPM Package Manager.

In addition, the RPM package format is being adopted by the Linux Standards Base (LSB). The LSB defines a set of standards to help maintain compatibility for all Linux distributions.

Cross Reference

See www.linuxbase.org for more on the LSB.

This chapter covers differences in how Linux distributions use RPM, ways to work around these differences, and also tools you can use for non-RPM distributions.

Troubleshooting RPM Installation Issues

The main RPM issues when dealing with installing RPMs on other versions of Linux are:

*	Different versions of RPM itself

*	Different divisions of software into packages

*	Dealing with dependency issues

*	Different install locations

The following sections expand on these issues.

Dealing with RPM versions

Red Hat Linux 8.0 ships with RPM version 4.1. Other distributions of Linux ship with other versions of RPM. Thus, one of the first commands you can run on another Linux distribution is the rpm --version command, to see what RPM version is in use and help identify any issues. For example:

$ rpm --version

RPM version 4.1

Once you know the RPM version, you can plan for any issues that arise from installing RPMs made with a different RPM version. For example, RPM 4.0 and higher inserts dependency information automatically into RPMs. If your Linux distribution runs RPM 3.x, you may need to disable some of the dependency checks, for example, if you want to install RPMs built under RPM 4.x onto an RPM 3.x system.

On installing RPMs, you can disable the dependency checks with the --nodeps option. If you do this, though, you should manually check that the dependencies are really met by your Linux installation.

On the other hand, if you want to install RPMs built on an RPM 3.x system onto an RPM 4.x system, you may need to deal with package signatures. RPM 4.x versions also automatically check for signatures. When installing packages on an RPM 4.x system, you can disable this feature with the --nosignature option.

Using these techniques, you should be able to install packages built with RPM 4.1 on systems that use RPM 3.x versions or vice versa.

Dealing with divisions of software into packages

There is no standardization as to how large applications are divided into packages on different Linux distributions. This means that dependencies between packages may differ.

If your dependencies are for packages provided with the Linux distribution, which includes a huge number of packages, you must address this issue. The package an RPM depends on may not exist and may not even be needed, on a particular Linux distribution.

If instead the dependencies are for files, especially shared libraries, you should be okay for the most part, unless the files are located in different directories.

The only real solution to this problem is to turn off dependency checks on installing, with the --nodeps option. Then you must check manually that your system really does provide all the necessary dependencies. Use the techniques shown in Chapter 6 to verify all the dependencies are met on your system.

Warning

Using the --nodeps option can lead to problems with your RPM database, because you are installing packages by defeating the RPM system's safeguards for dependencies. Only use the --nodeps option if you are really sure the dependencies are met on your system, even if from a different package than expected.

Dealing with dependency issues

One of the toughest areas to deal with is the problem of dependencies. This topic ranges from the very simple issue of installing a necessary package to complex issues of shared library versions or particular Perl modules.

Start with the simple case and make certain that you haven’t failed to install a necessary RPM that provides the right dependency. In most cases, you can download a vendor-specific package from your Linux vendor, such as www.suse.com for SuSE Linux. Most Linux vendors provide HTTP or FTP sites with a large set of packages created for their distributions. If such a distribution-specific package solves a dependency issue, this is the easiest way around the problem.

After you verify that you haven't simply omitted a necessary package, move on to other potential explanations. Another issue involves shared libraries and ELF, or Extended Linking Format, symbols. A package may require an older or newer version of a shared library. Applications that are tied to a particular version of a shared library can cause problems, since you may not want to install incompatible versions of a shared library.

If the dependency is for a system-shared library, such as the shared C library, you can often recompile the package (rebuild from a source RPM) to get the package to use the newer or older version of the system library. This is possible because most Linux applications don’t call on version-specific features of system shared libraries (some do, but most don’t). If the dependency is for an application-shared library, this is more serious, since there were likely API changes that could impact the application. Install the package owning the application-shared library and again, try to rebuild the package from the source RPM.

Cross Reference

You can use the rpm -qf command to query which package owns a given file. You can use the rpm -q --whatprovides command to query for which package provides a given capability. Chapter 6 covers more on dependencies.

Some packages are considered developer packages. These usually depend on some base package. For example, the rpm-devel package depends on the rpm package. The rpm-python package depends on both the rpm package and the python package (at particular version numbers as well).

This naming scheme of a base package and base-devel is used for Red Hat Linux packages, but may not be used for other vendor packages. In any case, you can solve this type of dependency by finding the relevant base packages that the package you are trying to install depends on. Consult the manuals that come with your Linux distribution or browse the online RPM repositories to see what naming conventions are used for your Linux distribution.

Many packages depend on scripting language interpreters, such as Perl. Sometimes the dependency is based on scripts used in a package, such as install or trigger scripts. You can have problems arise with the locations of these scripting interpreters. Perl, for example, is usually installed in /usr/bin/perl on most Linux systems. Another common location is /usr/local/bin/perl. In addition, packages may depend on particular add-on modules, especially Perl modules. With most versions of Linux released in the last few years, you should be able to override a Perl dependency with the --nodeps option as long as you have Perl installed.

File paths may also cause problems. For example, a file that a package depends on may be in a different location or owned by a different package. For this case, you can try to find the package that owns the file and make sure that package is installed. If your Linux vendor provides a pre-built RPM database of all packages, such as the rpmdb-redhat package, you can query this database to find out which package owns the file for that version of Linux.

Dealing with install locations

Linux vendors can install software anywhere. For example, some distributions place a lot of software under /opt instead of the more common /usr. From an RPM perspective, this is mostly an issue with file dependencies and the install location for packages. Evolving file system standards also help limit this issue.

You can attempt to relocate any package using the --badreloc option.

Cross Reference

Chapter 4 covers the --badreloc option.

But, while the --badreloc option will relocate the files in a package, it will not modify the contents of those files. So, any file inside a package that references files and directory locations may not work properly, since it may have the old, invalid, paths.

The only real way around this problem is to edit any script files that come with the package and contain hard-coded paths. If the paths reside inside binary executables, you need to get a source RPM for the package, patch the sources and then create a new RPM.

When all else fails, rebuild from the source package

When all of these techniques fail to install a package, you still have a fallback option. If you have the source RPM for a package, you can install the source RPM on the new system and then edit the spec file until you can rebuild a package that will install on your version of Linux.

For example, a set of Build Root Policy (brp) helper scripts are run at the end of the %install section in an RPM. These scripts perform tasks such as compressing man pages. The Mandrake brp scripts use bzip2 compression. Red Hat brp scripts use gzip compression. This is one case where rebuilding an RPM and then installing may work best.

Handling Problems Building RPMs

Given all these differences, how can you create RPMs while avoiding problems? With some work setting things up, you can create an RPM build environment that solves most vendor issues. This depends on taking a methodical approach to building your packages and using techniques to avoid vendor issues wherever possible.

When building RPMs, you will face many of the same problems@@mdand solutions@@mdas when installing RPMs. For example, due to the different ways Linux vendors divide software into packages, your RPMs will likely have issues defining the proper dependencies. There are also a number of issues that apply only when building RPMs.

The following sections cover the main issues when building RPMs.

Writing distribution-specific packages

One of the ways around all the differences between Linux distributions in RPM usage is to define distribution-specific packages. To do this, you create a separate package on each Linux distribution you support.

That’s a lot of work. If possible, fit the differences into macros and use a single spec file to reduce some of this work. This technique works up to a point. Sometimes, your spec file becomes too complicated and you may decide that it is easier to create multiple spec files, one per Linux distribution.

One way to help make vendor-specific packages, or to see which RPM macros are defined on a given Linux distribution, is to look for an RPM that contains the distribution-specific RPM configuration. For example, on Red Hat Linux systems, the Red Hat RPM configuration is defined by the redhat-rpm-config package.

You can list the files in this package to see where Red Hat defines macros specific to their Linux distribution.

$ rpm -ql redhat-rpm-config

/usr/lib/rpm/redhat

/usr/lib/rpm/redhat/brp-compress

/usr/lib/rpm/redhat/brp-redhat

/usr/lib/rpm/redhat/brp-sparc64-linux

/usr/lib/rpm/redhat/brp-strip

/usr/lib/rpm/redhat/brp-strip-comment-note

/usr/lib/rpm/redhat/brp-strip-shared

/usr/lib/rpm/redhat/find-lang.sh

/usr/lib/rpm/redhat/find-provides

/usr/lib/rpm/redhat/find-requires

/usr/lib/rpm/redhat/macros

/usr/lib/rpm/redhat/perl.prov

/usr/lib/rpm/redhat/perl.req

/usr/lib/rpm/redhat/rpmrc

These files, such as /usr/lib/rpm/redhat/macros, show you what is specific to a given Linux distribution. You can then look at the macros defined in these files to identify settings for a particular distribution, in this case, Red Hat. Armed with this knowledge, you can better create portable RPM spec files.

Dealing with automatic dependency generation

One of the features in RPM 4.x is the automatic generation of dependencies. For a variety of reasons including different package layouts, different directory structures, or different versions of RPM, you may need to disable some or all of automatic generation of dependencies.

You can disable the automatic generation of dependencies by placing the following directive in your spec file:

Autoreq: 0

If you do so, you need to use the Requires: tag to manually define all requirements. This is not a good solution to the issue of automatic dependencies however. Most likely, you will need to override the %{__find_requires} and %{__find_provides} macros in order to filter out any unwanted dependencies.

These two macros resolve to shell scripts that perform the automated dependency checks, as you can see with the rpm --eval command:

$ rpm --eval "%__find_provides"

/usr/lib/rpm/find-provides

rpm --eval "%__find_requires"

/usr/lib/rpm/find-requires

You can override these scripts to filter out any dependencies that cause problems for your packages.

Dealing with different macros

Different Linux vendors define different macros in their RPM setup. This may mean not only different values for the macros, but different macro names as well. Because of this, it is best to define your own local set of macros when building RPMs.

As much as possible, depend on your own RPM macros. You can define your macros in terms of vendor-specific macros using conditional statements in your spec files, a topic covered in Chapter 11. You can also read examples in the “Build Environment and Macros” section of this chapter.

This really boils down to creating a disciplined RPM build environment.

Making relocatable packages

You should aim to make your packages relocatable so that users can install your packages into any directory. This makes it easier to deal with the locations chosen by different Linux distributions, such as /usr, /usr/local, or /opt, for installing add-on software.

Cross Reference

Chapter 10 covers the spec file format. Chapter 11 covers making relocatable packages.

You can use the %{_bindir} macro in your spec files, which will help create per-distribution packages using the right settings.

In addition, you can define macros in your spec files that define the location for dependencies. You can then use the --define option to the rpmbuild command to define values for your macros that specify the locations for the dependencies.

Note

This technique of setting up Linux distribution-specific macros can help solve a lot of problems with cross-platform RPMs.

Creating an RPM build environment

If you start with the idea that you want to build RPMs for multiple versions of Linux, you can set up an RPM build environment that cleanly separates most vendor-specific issues.

The key issues with the build environment are:

*	Detecting the vendors

*	Using macros to define a clean build process

*	Handling different dependencies

Detecting Vendors

To make a clean build environment, you need to be able to detect the Linux vendor and make build settings based on this vendor. To help with this, many Linux vendors install a special file with the vendor name, or a special package with the vendor name. You can query for either of these.

For files, the convention follows:

/etc/vendor-release

For example:

$ more /etc/redhat-release

Red Hat Linux release 8.0 (Psyche)

For packages, the convention is vendor-release for a package name. For example:

$ rpm -q redhat-release

redhat-release-8.0-8

You can use either approach or simply define a macro for the vendor and use the --define option to set the macro. For example:

# rpmbuild –ba --define 'linuxVendor suse'

With this definition, you can use the macro %linuxVendor inside your spec files. It is generally easier, though, if your scripts can automatically detect the Linux vendor instead of having to define it manually. The manual approach works, though, if it becomes too much effort to detect the vendor automatically.

Build environment and macros

Once you can detect the Linux vendor, you can create macros based on the differences between Linux distributions that affect your applications.

Cross Reference

Chapter 21 covers RPM macros.

The macros that specifically help you with platform differences include the %if .. %endif conditional. You can use this in combination with special macros you define. In addition, command-line options such as --with, --without, and --target allow you to control features and the build target within an RPM.

The %if macro allows you to specify a condition within your spec file. For example:

%if %{old_5x} && %{old_6x}

%{error: You cannot build for .5x and .6x at the same time}

%quit

%endif

%if %{old_5x}

%define b5x 1

%undefine b6x

%endif

%if %{old_6x}

%define b6x 1

%undefine b5x

%endif

You can also use %if to control settings such as the Requires:, as shown in the following example:

%if %{build6x}

Requires: util-linux, pam >= 0.66-5

%else

Requires: util-linux, pam >= 0.75-37, /etc/pam.d/system-auth

%endif

The --with command-line option defines a special macro starting with _with_. For example, the following command-line option defines a feature to use:

$ rpmbuild –bc --with ssh filename.spec

This example defines the macro _with_ssh to --with-ssh. This format was specially designed to work with GNU configure. You can use this for conditional builds for platform-dependent issues.

The --without command-line option similarly defines a macro starting with _without_. The convention is that this option defines a feature the code should not use.

You can combine --with and --without to turn on and off features referenced in your spec files. For example:

./configure %{?_with_ssh}

This will pass the following command line if the _with_ssh macro is defined:

./configure --with-ssh

If this option is not defined, the command will be:

./configure

The --target option sets the spec file macros %_target, %_target_arch, and %_target_os . For example:

$ rpmbuild -bc --target ppc-ibm-aix /usr/src/redhat/SPECS/jikes.spec

Compatibility and Glue Packages

Not all Linux distributions are the same. Macros alone won’t provide work-arounds for all the differences. You can, though, get a lot of mileage from compatibility and glue packages.

A compatibility package provides a legacy API on newer systems that no longer support the legacy API. By convention, compatibility packages are named with a leading compat- to signify their purpose.

For example:

$ rpm -q --qf "%{description}" compat-libstdc++

The compat-libstdc++ package contains compatibility Standard C++

Using a compatibility package allows you to create programs that use a least-common-denominator approach, programming to the oldest but most common APIs. As some Linux distributions eliminate the old APIs, compatibility packages can provide the missing APIs.

Similarly, a glue package provides a dependency that exists on some Linux distributions but not others. It glues together your package with the Linux distribution that is missing an essential capability.

Note

A key point in both of these approaches is to separate the compatibility and glue packages from your main application packages. The application packages should be as clean of vendor issues as possible. Instruct your users to install the compatibility or glue packages as needed (based on their Linux distribution) along with the main application package or packages.

With all this discussion of RPM and Linux differences, you might think that Linux is one big mess. That’s not true. Linux maintains a high degree of compatibility among Linux distributions as well as among processor architectures. Most programs originally created for Linux on Intel-based architectures compile cleanly on Linux versions running on other processor architectures such as MIPS, SPARC, and ARM.

The main differences lie in how Linux vendors split up the huge number of files associated with Linux into RPM packages as well as which versions of tools like C compilers the vendors ship.

Dealing with Signatures

With SuSE Linux, or any Linux based on UnitedLinux 1.0, the RPM packages are signed with OpenPGP version 4, not 3, as used in RPM 4.1. This means that you must use some other, non-RPM means to extract the signatures from an RPM package, and then verify these signatures with gpg.

Dealing with Non-RPM-Based Linux Versions

The main Linux distributions that don’t support RPM are the Debian GNU/Linux family and Slackware Linux. To help with these distributions, you can use a package-conversion tool called alien.

Handling non-RPM packages with alien

Alien is a package that supports conversions between RPM and so-called alien package formats such as the dpkg (Debian GNU/Linux), slp (Stampede Linux), and tgz (Slackware Linux) formats.

You can use alien on your RPM-based Linux system to convert RPMs to some other format, such as the Debian dpkg. You can also use alien to convert other package formats into RPMs, depending on which way you need to go.

Standardizing RPMs

RPM is being considered as part of the Linux Standard Base, or LSB, 1.3. This will define a standard packaging format for Linux distributions, and over time reduce the RPM differences between distributions.

In addition, other efforts are underway to help unify the diverse Linux distributions, including the Filesystem Hierarchy Standard and the adoption of RPM by many Linux vendors.

Filesystem Hierarchy Standard

The FHS, or Filesystem Hierarchy Standard, defines the purpose of all the upper-level directories on Linux systems, such as /var and /usr/bin. This standard, along with the Linux Standard Base, or LSB, is driving Linux distributions to a greater degree of similarity.

The FHS helps by specifying where applications should get installed and which directories should be left to local administrators to manage. The FHS also defines the purpose of all Linux directories, giving vendors and application writers a better idea of where they should install their packages.

Cross Reference

See www.linuxbase.org for more on the LSB. See www.pathname.com/fhs/ for more on the FHS.

RPM adoption

RPM has been adopted by a large number of Linux distributions. In addition, standardization efforts, both for RPM and for filesystem locations, are making Linux systems less varied.

This means that over time, many of the RPM-related differences between Linux distributions will fade away, making it easier to create cross-platform RPMs.

Summary

This chapter covers differences in RPM versions between various Linux distributions, and techniques you can use to get around these differences. Each Linux vendor packages software differently, even if the vendor uses RPM. This can cause problems unless you write your spec files carefully.

Inside your RPM spec files, you can use conditional elements as well as platform-based macro definitions to help create RPMs for multiple packages.

Some of the best conventions are to split the software in your applications from any compatibility or glue packages, separate packages that provide missing features for various flavors of Linux.

Standardization efforts such as the Linux Standard Base and Filesystem Hierarchy Standard are bringing Linux vendors closer and closer together. Widespread adoption of RPM by most Linux distributions also helps.

While this chapter covers RPM on other Linux distributions, the next chapter tackles RPM outside of Linux.

Chapter 19

Chris Ricker

2003-01-24T09:12:00

Eric Foster-Johnson