You are here

March 2011

Building RPMs from SRPMs

Sometimes you run into a shortcoming in your Linux distribution and you find that a package you want doesn't exist. Perhaps there are is no package for the software available (for example, there is no rubygem-cucumber-nagios package available for CentOS 5). Perhaps the package available is too old (for example, there is no official PHP 5.3.x package for CentOS 5). Perhaps you need functionality built into the package that isn't normally there (for example, patching Apache httpd for mpm-itk). In these cases, you either need to find a package someone else has made or roll your own.

Before you think about installing directly from source, stop. This is a bad habit to get into. It will not scale.

Red Hat Enterprise Linux, Fedora Linux, SuSE, and their derivatives use RPMs for packaging. In this, I hope to show you how to build RPMs from source RPMs. In the future, I hope to show how to add patches to source RPMs to build customized packages.

(You may be able to follow these instructions to build your own RPMs from source. To do this, you will need to skip the step of "installing" the source RPM and will instead need to write your own spec file. I don't have any personal experience with this so I can't help you.)

Before you start anything, make sure you're not doing this as root. If you build RPMs as root, you run a risk of files ending up in system paths rather than in the RPM build path.

Doing it as a normal user? Good. Set up your build environment:

  1. mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
  2. echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros

(For more information, you may want to read the CentOS documentation on setting up the RPM build environment.)

On CentOS and other RHEL derivatives, you will need to install the rpm-build and redhat-rpm-config packages. On other distributions, you may need to install other packages.

Once you have your build directory set up, install your chosen source RPM:

  1. rpm -i rubygem-gem2rpm-0.6.0-1.el5.src.rpm

This will install the source files in ~/rpmbuild/SOURCES and the spec file in ~/rpmbuild/SPECS.

To build the RPM, you can simply run:

  1. rpmbuild -ba ~/rpmbuild/SPECS/rubygem-gem2rpm.spec

This will put the binary RPM under in architecture-dependent directory under ~/rpmbuild/RPMS/. For example, the RPM built for rubygem-gem2rpm is architecture dependent and rubygem-gem2rpm-0.6.0-1.noarch.rpm will be placed under ~/rpmbuild/RPMS/noarch/.

From here, you could simply install the rpm with sudo rpm -i ~/rpmbuild/RPMS/noarch/rubygem-gem2rpm-0.6.0-1.noarch.rpm. I don't recommend this approach. Instead, I recommend signing the RPMs and adding them to a central yum repository. I will cover both of these in the future so stay tuned.

Signing RPMs

So you've built a shiny new RPM, let's say rubygem-cucumber-0.10.0-1.noarch.rpm, and you want to install it on a system. You enter the command:1

sudo yum install -y ./rubygem-cucumber-0.10.0-1.noarch.rpm

and then get this:

(some output removed)
 
Dependencies Resolved
 
================================================================================
 Package          Arch   Version        Repository                         Size
================================================================================
Installing:
 rubygem-cucumber noarch 0.10.0-1       /rubygem-cucumber-0.10.0-1.noarch 3.3 M
Installing for dependencies:
 rubygem-builder  noarch 2.1.2-2.el5    epel                               81 k
 rubygem-diff-lcs noarch 1.1.2-3.el5    epel                              123 k
 rubygem-gherkin  x86_64 2.3.4-1        oberonproject                     1.2 M
 rubygem-json     x86_64 1.4.6-1        oberonproject                     469 k
 rubygem-term-ansicolor
                  noarch 1.0.5-1.el5    epel                               42 k
 
Transaction Summary
================================================================================
Install       6 Package(s)
Upgrade       0 Package(s)
 
Total size: 5.2 M
Downloading Packages:
 
 
Package rubygem-cucumber-0.10.0-1.noarch.rpm is not signed

Well, bummer. yum wants the RPM to be signed.2

To sign your RPM, you first need a GPG key. To create one, run gpg --gen-key and follow the instructions. Once it's created, you should be able to see it by running gpg --list-keys. (For the rest of this, I'm going to assume the key is named "Software Packager". Where you see this, replace it with the name for the key.)

In order for yum to allow using your key, you'll need to import it into the RPM database. First, export the key to a file:

gpg --export -a 'Software Packager' > RPM-GPG-KEY-packager

Now, import it into the RPM database:

sudo rpm --import RPM-GPG-KEY-packager

To tell rpmbuild to use this key, add the following lines to your .rpmmacros file:

%_signature gpg
%_gpg_name Software Packager

Since you have an RPM built, you can add a signature with rpm --addsign, like so:

rpm --addsign ./rubygem-cucumber-0.10.0-1.noarch.rpm

Now, when you run sudo yum install -y ./rubygem-cucumber-0.10.0-1.noarch.rpm, the RPM will install successfully.

If you want to sign RPMs automatically when you build them, which I suggest, add the --sign option to rpmbuild like so:

rpmbuild -ba --sign SPECS/rubygem-cucumber.spec

So now that you have signed RPMs, you surely want to put them in a local repository. I'll show you how to do that (or at least how I do it) in the near future.3

  • 1. You are doing this as a normal user and using sudo for anything that requires root privileges, right?
  • 2. Yes, you could just install it with sudo rpm -i ./rubygem-cucumber-0.10.0-1.noarch.rpm but then you have to manually install the dependencies as well. On a single machine, this may not be too bad, but this won't scale.

    You can also pass --nogpgcheck to yum install but this may be prohibited by your local security policies. For example, the NSA Guide to the Secure Configuration of Red Hat Enterprise Linux 5 recommends ensuring that all yum repositories check the GPG keys.)

  • 3. If you can't wait, check out the createrepo command.