Building RPM tips

Introduction

The following answers some questions around building RPM files for the sipX project on Fedora Core and CentOS. The process of creating RPM installation files is largely automated and part of the sipX build system. For basic information on building RPMs, see Building RPMs. The easiest way to build rpms is with Express Development Environment (EDE) using the -r argument: ede_build_devuser.sh -r.

What actually happens when I type make rpm for a typical sipX project ?

  1. autoconf creates a spec file from a spec file's *.in
  2. make rpm invokes make dist, creating a tarball including spec file
  3. The rpmbuild magic turns the tarball into a source RPM
  4. The rpmbuild magic extracts, builds and installs the tarball into the temp dir
  5. The rpmbuild magic grabs all files in temp dir after install and copies them into an RPM file
  6. make copies RPM from /usr/src/redhat dirs

Why do I get a permission denied error building my RPM? Do I need to be root ?

NO! You could be getting this for a couple of reasons.

  1. You do not have access to /usr/src/redhat and you should
  2. make install tries to install a file outside the ${prefix} directory. Inadvertant violations typically come from not using the $(DESTDIR) variable in your makefile. All paths used to place files into ${prefix} must prepend $(DESTDIR) to the path. (Java use ${dest.dir}). This is the #1 rpm build killer! NOTE: Variables ${bindir} still point to the eventual destination (e.g. /usr/bin) but if your makefile places a script into the $(bindir) then use $(DESTDIR)$(bindir). (Yes, it includes the trailing path separator and when not building RPMs this value is blank)

TIP:
Howto build in home directory as non-root

Do RPMs replace make install ?

NO! In fact they generally leverage it. RPM spec files include a number of scriptlet sections, some of which where used to build the RPM (as opposed to sections run during an RPM installation). In particular the %prep %build and %install sections are used to make and install the package into temporary directories. Then rpm build grabs all the files listed in respective %files sections and packages them into a binary RPM file.

Note: You unfortunately can't leverage make uninstall

What are Source RPMs ?

Source RPMs are very similiar to a tarball except that the configure, make and make install commands (generally speaking) are predetermined for you and you don't really get to see the contents (unless you rummage in the /usr/src/redhat/SOURCES directories). It's best used when you only want to compile a particular RPM for your machine. The rpm command will pass --with and --without that will get passed to the configure script but it's generally not meant to give you configuration options OR supply you with include headers.

I've installed package XYZ but I still cannot compile my package ?

You probably need the packageXyz-devel rpm. This is a standard packaging and file naming scheme to include things needed to develop with that package, such as include files. It may also include static libraries and libtool's .la files.

One of the RPMs I installed wasn't compiled w/ the right switches or had a bug that I fixed. What can I do ?

This is called patching an RPM and it's unfortunately a reality. There's a standard procedure to create patch files and list them in a section of the spec file. See RedHat RPM Guide, Chapter 14 for more info and best practices. See sipXbuild/rpms/cppunit for an example. Depending on the package, you may need to invent a whole new package name and might use "Conflicts:" in spec file to ensure your package gets installed.

TIP: Use gendiff when creating patches, which keeps you from having to keep two separate directory structures around. Also, you're encouraged to have each file change in a separate patch file.

A package I need isn't built as an RPM, what do I do ?

Create an RPM spec file for it and package it up.

How can I see/extract the contents of an RPM ?

Example to see a list of contents
 rpm2cpio packageXyz.rpm | cpio -it
Example to extract a file
 rpm2cpio packageXyz.rpm | cpio -imvd ./usr/packageXyz/randomfile

The most important things to remember about cpio are:
(1) The -i/--extract and -o/--create switches are based on the idea that cpio is inputting or outputting an archive tape, so -i is the extract operation.
(2) cpio won't create any subdirectories (or extract the files that go into them) unless the -d/--make-directories option is given.

What can I do to speed up the process ?

The time it takes between editing a spec file and testing my new RPM can be long. rpmbuild has a number of command line switches to help you. Namely --short-circuit is meant to be used in conjunction with -tc -tb. You may be able to make and test your edits in /usr/src/redhat/SOURCES; However, I personally have not tried this.

Why am I getting an error at RPM install time about a conflict with a file from another RPM ?

In your spec file, %files section, do not replace a file that is from another package. Your RPM will fail at installation time. You can patch, sed, awk, and/or backup (hopefully) that file in the %post section if you wish.

Is it bad to put a lot of script into my RPM spec file ?

YES!

  1. If it can go in as part of make install it should, so tarball users get it too.
  2. You want the RPM to install w/o glitches (theory: more code = more glitches).
  3. Other non-RPM package distributions (Debian, Gentoo) may need to do the same thing and it would be helpful to reuse that script code. Think about moving code into a separate shell script that runs after the installtion but is possibly kicked off by the RPM
  4. It can be hard to test consequently develop script within an RPM.
  5. Makes RPM updating and uninstalling messy.

I'm on Gentoo, can I still build RPMs ?

Yes, but you probably can't install it on your Gentoo system because of dependencies, and they probably won't install on any other Redhat system because filepaths (among other things) will be off. You can test the making of an RPM though.

I built my RPM on Fedora, will it work on Redhat Enterprise ? Or vice versa ?

It should, but in general you want to use it on the same system type and more importantly version of the OS though.

How can I see what a spec file macro resolves too ?

To list all macros:
  rpm --showrc
To resolve a particular macro:
 rpm --eval "%{_bindir}"

I discovered the "Prefix: variable". Can I change it ?

NO! This is set to fix all dirs to be inline with the Unix File Hierarchy standard. Changing it will cause untold pathing issues and violate sysadmin standard partitioning configurations, among many other problems.

If you're wondering if Apache overrides this, it doesn't. In fact it explicitly tells configure to install into the standard prefix and override the tarball's default prefix. You can extract the spec file to be sure and also list the final destination of the RPM installed files like this:

List destination directories
[#root] rpm -ql httpd
...
/etc/httpd/conf/magic
/etc/httpd/logs
/etc/httpd/modules
/etc/httpd/run
/etc/logrotate.d/httpd
/etc/rc.d/init.d/httpd
/usr/bin/ab
/usr/bin/htdbm
/usr/bin/htdigest
/usr/bin/htpasswd
/usr/bin/logresolve
...

In general, tarballs install into /usr/local and RPMS install into /usr. For general information see File Hierarchy System.

What's the undocumented 4th arg to %defattr ?

Undocumented default mode for directories.

I found an RPM for the package I'm looking for. Can I trust it as part of sipX's complete package dependencies ?

Take a look at the spec file. You may have to extract it via rpm2cpio. It helps if you can get the source RPM too. Be sure you have a method for making a fix if you need to post release w/o too much trouble. If the spec file is too complicated, be wary.

Some files are not getting built as part of the RPM. Why ?

Projects that include directories as part of EXTRA_DIST get more stuff than desired into the tarball. Sometimes it's harmless, but in the case of RPMs, these files may have been generated with the wrong conf settings. One quick way around this is to make the RPM target depend on clean and dist to trigger a clean first.