Patch and Rebuild an RPM Package

The following describes how to derive a patch for a modification you need to make to the source code of a program, and apply that patch during the RPM building process.

1. Setup

By default, at least on a Red Hat box, rpm uses /usr/src/redhat as the location of the %_topdir macro, which specifies where most of the work involved in building an RPM takes place.

The BUILD directory is where sources will be extracted and compiled, and as such is more or less a temporary working directory. SOURCES is for source tarballs, patches, and additional files, which are extracted from SRPM packages you install, and used and included in packages you build. The RPMS and SRPMS directories are where packages you build will end up. The SPECS directory is where the specfile included with an SRPM will be placed.

2. Rebuilding an RPM from SRPM

If you just want to recompile, without making any changes to the source, all you have to do is run:

#rpmbuild --rebuild package-1.0.src.rpm

Your new package will be in %_topdir/RPMS/<arch>.

3. Installing the SRPM

The first thing you will need to do is install the source RPM (SRPM):

#rpm -ivh package-1.0.src.rpm

That will put a specfile in %_topdir/SPECS, and a source tarball (plus any other included patches or additional files) in %_topdir/SOURCES.

4. Changing 'configure' flags

If all you need to do is change the configure flags, just edit the specfile. You don't need to touch the source at all. There's usually a %configure section, where it should be fairly self-evident what to do. Then skip to "Rebuilding the package."

5. Patching the source

Since the rpmbuild process will delete the original extracted source and start from scratch when building packages, you'll want to do your work on a copy of the source with a different name. So if extracting package-1.0.tar.gz creates a directory named package-1.0/, make a copy named something like package-1.0.1a/ and make your changes there.

To create a patch containing your changes, cd to %_topdir/BUILD -- one directory above the source tree -- and use diff to create a patchfile in the SOURCES directory. There may be other patches to apply to this source, so give your patchfile a unique name to quickly describe the purpose of the patch. Run diff with "-u" to get the unified diff format that is standard for patches, "-N" to include any new files from your modified source, and "-r" to operate recursively, listing the original first, then your version:

#diff -uNr package-1.0/ package-1.0.1a/ > ../SOURCES/package-1.0-my.patch

The top of the patchfile will look something like this:

--- package-1.0/file Thu Aug 14 16:24:49 2004
+++ package-1.0.1a/file Mon Aug 18 01:24:17 2004

6. Adding the patch to the package

Next, add the patch to the specfile, so it will be applied when building the package. There may be other patches already, and they are applied in order of their number in the specfile, so number yours appropriately. Add to %_topdir/SPECS/package.spec, in the top section where the name, version, and source lines are:

Patch0: package-1.0-my.patch

Further down, there will be a section that deals with preparing for the build. Add a patch command that corresponds with the patch line above, typically right after %setup:

%prep
%setup ...
%patch0 -p1

The "-p1" in the patch command above is how many directories to strip off the beginning of the filenames listed in the patch. Since, at this stage of building an RPM, the current directory is the top level of the source tree -- one level lower than where the patch was made -- we need to strip off one directory level.

Again, there may be other patches already being applied to this package, so give yours a unique number in the specfile, and be careful that your patch doesn't break others, and that others don't break yours. Usually the next available number will work fine, and your patch will be applied after all others. If the package is already installed, make the version number of your package higher so it will be considered newer when you go to upgrade it, and update the changelog with a quick note on what you did.

7. Rebuilding the package

You should be able to rebuild tha package with your changes now:

#rpmbuild -ba SPECS/package.spec

That will patch, configure, and compile the source, build a binary RPM package in %_topdir/RPMS/<arch>/, and an SRPM package in %_topdir/SRPMS containing the original source (checksums for which can still be used), plus your additional patch and new specfile, so that the package can be rebuilt again on top of the work you've already done. Use "-bb" to make just a binary RPM, or "-bs" to make only an SRPM.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Good Post !!

Sanding, Thanks for the post. The article is precise and easy to follow.

Very helpful, thank you.

Very helpful, thank you.

RPM Build Environment Setup

Create a seperate account for building RPMs and set up the environment for it:

# su -
# useradd rpmbuild
# su - rpmbuild
# mkdir -p rpm/{BUILD,RPMS/$ARCH,RPMS/noarch,SOURCES,SRPMS,SPECS,tmp}

Replace "$ARCH" with the architecture(s) you plan to build packages.

Then create the minimal "~/.rpmmacros" file with the below contents:

%_topdir               /home/rpmbuild/rpm
%_tmppath              /home/rpmbuild/rpm/tmp

Now we are ready to build RPMs.

Comment