rpms (packages)

RPMs are the key to a Red Hat based system. They make administration of packages simple elegant and very easy to maintain. Building RPMs is not a difficult task. If you maintain your software with packages rather than installing from source, your updates will be painless and you will be able to roll back to previous versions without pain also.

Ok, so you know you want to use rpms, how do you start?

The easiest way I think is to build an actual package. The example I usually do is tar, it's one of the easiest things to build.

Some notes before you proceed though, always create your RPMs as yourself or as a build user, never use root. Why, because when running as root you can place files into their final locations on the filesystem without knowing it (eg /usr/bin), this is strictly bad practice. The only things that should be placing files into folders like /usr/bin, /usr/sbin are packages, not package builds.

There are some other caveats to building packages, for now lets get started building a package. The first step is to download the source for the package we wish to build and start making a spec file for our package

getting started

In our example we'll build tar, so first off we'll download tar from gnu, the homepage for gnu tar is http://directory.fsf.org/project/tar/

[root@client11 ~]# useradd build
[root@client11 ~]# su - build
[build@client11 ~]$ wget http://ftp.gnu.org/gnu/tar/tar-1.22.tar.bz2
--20:37:37--  http://ftp.gnu.org/gnu/tar/tar-1.22.tar.bz2
Resolving ftp.gnu.org... 140.186.70.20
Connecting to ftp.gnu.org|140.186.70.20|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2094575 (2.0M) [application/x-tar]
Saving to: `tar-1.22.tar.bz2'

100%[=======================================>] 2,094,575   2.39M/s   in 0.8s   

16:32:16 (2.39 MB/s) - `tar-1.22.tar.bz2' saved [2094575/2094575]
The next thing I like to do is make a build directory for myself. On recent versions of fedora, rpm will build a directory called rpmbuild for you in your home directory. On older versions rpm will try and install files in /usr/src. It's probably better to just specify your build directory just in case. You can do that with the .rpmmacros file, the option to specify is %_topdir.
[build@client11 ~]$ mkdir rpmbuild
[build@client11 ~]$ cd rpmbuild
[build@client11 rpmbuild]$ mkdir -p BUILD RPMS/x86_64 SOURCES SPECS SRPMS
[build@client11 rpmbuild]$ cd
[build@client11 ~]$ cat .rpmmacros
%_topdir /home/build/rpmbuild
[build@client11 ~]$ rpmbuild
-bash: rpmbuild: command not found
If you haven't already done so, install the rpm-build rpm so you have access to the rpmbuild command.
[build@client11 ~]$ exit
[root@client11 yum.repos.d]# yum install rpm-build
Loading "installonlyn" plugin
...
=============================================================================
 Package                 Arch       Version          Repository        Size 
=============================================================================
Installing:
 rpm-build               x86_64     4.4.2-37.el5     Workstation       558 k
...
Installed: rpm-build.x86_64 0:4.4.2-37.el5
Dependency Installed: elfutils.x86_64 0:0.125-3.el5 elfutils-libs.x86_64 0:0.125-3.el5
Complete!
[root@client11 yum.repos.d]# su - build
[build@client11 ~]$ rpmbuild
rpmbuild: no spec files given for build
As rpmbuild has indicated, we need to make a spec file, lets start making one now.

spec

A spec file is where you specify all the information about your package. How to build the package, which files are installed the package, how to uninstall the package and what to do after installing or uninstalling the package.

There are several sections of a spec file.

header

In the header you specify the name of the package, the version, a summary of the package, any requirements the package may have (packages on which this one depends, either for building or running) as well as any licensing and source file information you may need.

To start our spec file, we'll create the SPECS directory to contain our spec files.

[build@client11 ~]$ cd rpmbuild
[build@client11 rpmbuild]$ mkdir SPECS
[build@client11 rpmbuild]$ cd SPECS
Now our package will be called tar, tar is "A GNU file archiving program". Like most GNU software it is released under the GPL. So we can put all that information into our spec file.
Summary: A GNU file archiving program
Name: tar
License: GPL
Our spec file should look like this at the end of this section. Summary: A GNU file archiving program
Name: tar
License: GPL
Version: 1.22
Source: http://ftp.gnu.org/gnu/tar/%{name}-%{version}.tar.bz2
Release: 1
Group: Applications/Archiving
BuildRoot: /tmp/rpm-buildroot-%{name}-%{version}
We downloaded version 1.22 of tar in the file tar-1.22.tar.bz2 from http://ftp.gnu.org. To tell rpm what the name of our source file is, we use a Source line, if we had more than one source file, we would add Source1, Source2, etc. Now we can add the Version and Source lines to the spec.
Version: 1.22
Source: http://ftp.gnu.org/gnu/tar/%{name}-%{version}.tar.bz2
In the source line instead of using tar and 1.22, we used the variables that we already defined of name and version. Any of the lines that you specify in your spec can be used as variables later in your spec file. The advantage to doing things this way is that when tar 1.23 comes out, you only have to change the version (assuming ftp.gnu.org names version 1.23 as tar-1.23.tar.bz2)

Next we need to identify the release of our package, since this is our initial build of the package, we'll set our release tag to 1. You could put in your name here or some other identifier. Dag Wiers sometimes has dag, Red Hat will put el[4|5] here, fedora will put f11 etc. If you aren't too grandiose, use a number.

Release: 1
Next is a bit of housekeeping, we need to tell rpm what this package contains, is it System software, a Game, or an Office or Productivity package, etc. In this case we'll use Applications/Archiving
Group: Applications/Archiving

One important thing to set at this point is the BuildRoot, this is the location where files created by this rpm should live temporarily during the build process. You need this set in order to make clean rpms that don't touch the system on which they are building.

BuildRoot: /tmp/rpm-buildroot-%{name}-%{version}

This should be enough of a header, some other things you can add in the header are:

Packager:
Requires:
Vendor:
BuildRequires:+
+We'll cover requires and buildrequires later.

%description

In this section you add a long description of the package. If your package has a README you can usually find a good description in there, otherwise maybe some snippet from the homepage of the project will do. In our case we'll use the description from the README.
[build@client11 ~]$ tar tjvf tar-1.22.tar.bz2 |grep README
-rw-r--r-- gray/users     2524 2008-04-14 08:03:13 tar-1.22/tests/star/README
-rw-r--r-- gray/users     9692 2007-06-27 09:30:31 tar-1.22/README
[build@client11 ~]$ tar xjvf tar-1.22.tar.bz2 tar-1.22/README
tar-1.22/README
[build@client11 ~]$ cat tar-1.22/README
README for GNU tar
See the end of file for copying conditions.
...
GNU `tar' saves many files together into a single tape or disk
archive, and can restore individual files from the archive.  It includes
multivolume support, the ability to archive sparse files, automatic archive
compression/decompression, remote archives and special features that allow
`tar' to be used for incremental and full backups.  This distribution
also includes `rmt', the remote tape server.  The `mt' tape drive control
program is in the GNU `cpio' distribution.
...
You end the %description section by starting another section (%pre, %post, %prep, %build), the usual layout is to do %prep next.

%prep

In the %prep section you expand archives (ironically tar files usually) and create any working directories you need for your %build section (which is next).

RPM provides a macro to expand archives, %setup. There are several options, without any options it will expand the archive and place the contents in the BUILD directory. I usually only use the quiet option (-q). Other options are occasionally necessary if the package you are building is nonconformist.

For our example spec file, the following will expand our archive and place the contents in the BUILD directory for us.

%prep
%setup -q
Our package will not build with this spec file, but we'll try anyway so we can see an error.
[build@client11 SPECS]$ rpmbuild -ba tar.spec
error: File /home/build/rpmbuild/SOURCES/tar-1.22.tar.bz2: No such file or directory
We need to move the source file we downloaded earlier into the SOURCES directory.
[build@client11 SPECS]$ mv ~/tar-1.22.tar.bz2 ../SOURCES
[build@client11 SPECS]$ rpmbuild tar.spec
[build@client11 SPECS]$ 
[build@client11 SPECS]$ rpmbuild -bb tar.spec Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.21480 + umask 022 + cd /home/build/rpmbuild/BUILD + cd /home/build/rpmbuild/BUILD + rm -rf tar-1.22 + /usr/bin/bzip2 -dc /home/build/rpmbuild/SOURCES/tar-1.22.tar.bz2 + tar -xf - + STATUS=0 + '[' 0 -ne 0 ']' + cd tar-1.22 + exit 0 Checking for unpackaged file(s): /usr/lib/rpm/check-files %{buildroot} [build@client11 SPECS]$ As you can see, rpm ran bzip2 to uncompress the file then piped it through tar to extract the files. RPM then cd'd to the directory tar-1.22, which is the name of our rpm - version. This is important, it is the directory you start in when you are at the build stage. We'll write our %build section now.

%build

The %build section is where anything that needs to be compiled should be compiled. Any file that has to be made on the machine or is architecture dependant should be created here. RPM provides convenient macros for this section. If your software is configure;make;make install (autoconf/automake) compliant, then this section will be very small also.
%build
%configure
make
For many packages, this is it. %configure is a macro that sends the appropriate defaults to configure. You can see what %configure expands to by stopping rpmbuild in the middle of the build and looking at the temp file in /var that rpm runs. Each section of the spec file is first parsed and expanded then cut up by rpm and placed into an executable file in /var/tmp. We'll run rpmbuild and look for a line that starts with Executing(%build). This will tell us the filename of the file in /var/tmp.
[build@client11 SPECS]$ rpmbuild -bb tar.spec 
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.61921
+ umask 022
+ cd /home/build/rpmbuild/BUILD
+ cd /home/build/rpmbuild/BUILD
+ rm -rf tar-1.22
+ /usr/bin/bzip2 -dc /home/build/rpmbuild/SOURCES/tar-1.22.tar.bz2
+ tar -xf -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd tar-1.22
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.21166
+ umask 022
+ cd /home/build/rpmbuild/BUILD
+ cd tar-1.22
+ CFLAGS='-O2 -g'
+ export CFLAGS
+ CXXFLAGS='-O2 -g'
+ export CXXFLAGS
+ FFLAGS='-O2 -g'
+ export FFLAGS
+ ./configure --host=x86_64-redhat-linux-gnu --build=x86_64-redhat-linux-gnu --target=x86_64-redhat-linux-gnu --program-prefix= --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/usr/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib --libexecdir=/usr/libexec --localstatedir=/usr/var --sharedstatedir=/usr/com --mandir=/usr/man --infodir=/usr/info
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... 
[1]+  Stopped                 rpmbuild -bb tar.spec
[build@client11 SPECS]$ cat /var/tmp/rpm-tmp.21166 
#!/bin/sh

  RPM_SOURCE_DIR="/home/build/rpmbuild/SOURCES"
  RPM_BUILD_DIR="/home/build/rpmbuild/BUILD"
  RPM_OPT_FLAGS="-O2 -g"
  RPM_ARCH="x86_64"
  RPM_OS="linux"
  export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS
  RPM_DOC_DIR="/usr/doc"
  export RPM_DOC_DIR
  RPM_PACKAGE_NAME="tar"
  RPM_PACKAGE_VERSION="1.22"
  RPM_PACKAGE_RELEASE="1"
  export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE
  
  
  
  set -x
  umask 022
  cd /home/build/rpmbuild/BUILD
cd tar-1.22

  CFLAGS="${CFLAGS:--O2 -g}" ; export CFLAGS ; 
  CXXFLAGS="${CXXFLAGS:--O2 -g}" ; export CXXFLAGS ; 
  FFLAGS="${FFLAGS:--O2 -g}" ; export FFLAGS ; 
  ./configure --host=x86_64-redhat-linux-gnu --build=x86_64-redhat-linux-gnu \
	--target=x86_64-redhat-linux-gnu \
	--program-prefix= \
 	--prefix=/usr \
	--exec-prefix=/usr \
	--bindir=/usr/bin \
	--sbindir=/usr/sbin \
	--sysconfdir=/usr/etc \
	--datadir=/usr/share \
	--includedir=/usr/include \
	--libdir=/usr/lib \
	--libexecdir=/usr/libexec \
	--localstatedir=/usr/var \
	--sharedstatedir=/usr/com \
	--mandir=/usr/man \
	--infodir=/usr/info
make
Ok, let rpmbuild complete or kill it, it won't do anything useful yet, because we didn't install any files, we need an %install section next.

%install

%install is where you create directories and move the compiled files into those directories. If your package has no build section, it is where you copy the files from your sources into the appropriate directories on the final system. A word on how this actually works though, you create a sandbox directory in which all the files will live. You never install files directly on the system, this is why you should never build rpms as root. When running rpmbuild as a regular user, a bad spec file will fail when it tries to write files where it shouldn't.

Again rpm provides a great macro in this section, but you can use whatever scripts you want to move the files. The root directory for your fake filesystem is in the variable $RPM_BUILD_ROOT. Consider this a blank canvas. If you want to put a file in /usr/bin, you have to create $RPM_BUILD_ROOT/usr/bin in your %install section. In our example, we only need use the %makeinstall macro. This macro do a make install with appropriate options, including setting the prefix and installdir variables for you.

%install
%makeinstall
When we run rpmbuild this time, we should see the files being built, and then installed into $RPM_BUILD_ROOT.
[build@client11 SPECS]$ rpmbuild -bb tar.spec 
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.14568
+ umask 022
+ cd /home/build/rpmbuild/BUILD
+ cd /home/build/rpmbuild/BUILD
+ rm -rf tar-1.22
+ /usr/bin/bzip2 -dc /home/build/rpmbuild/SOURCES/tar-1.22.tar.bz2
...
+ ./configure --host=x86_64-redhat-linux-gnu --build=x86_64-redhat-linux-gnu --target=x86_64-redhat-linux-gnu --program-prefix= --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/usr/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib --libexecdir=/usr/libexec --localstatedir=/usr/var --sharedstatedir=/usr/com --mandir=/usr/man --infodir=/usr/info
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
...
installing zh_TW.gmo as /tmp/tar-1.22/usr/share/locale/zh_TW/LC_MESSAGES/tar.mo
if test "tar" = "gettext-tools"; then \
	  /bin/mkdir -p /tmp/tar-1.22/usr/share/gettext/po; \
	  for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot   Makevars.template; do \
	    /usr/bin/install -c -m 644 ./$file \
			    /tmp/tar-1.22/usr/share/gettext/po/$file; \
	  done; \
	  for file in Makevars; do \
	    rm -f /tmp/tar-1.22/usr/share/gettext/po/$file; \
	  done; \
	else \
	  : ; \
	fi
make[1]: Leaving directory `/home/build/rpmbuild/BUILD/tar-1.22/po'
Making install in tests
make[1]: Entering directory `/home/build/rpmbuild/BUILD/tar-1.22/tests'
make[2]: Entering directory `/home/build/rpmbuild/BUILD/tar-1.22/tests'
make[2]: Nothing to be done for `install-exec-am'.
make[2]: Nothing to be done for `install-data-am'.
make[2]: Leaving directory `/home/build/rpmbuild/BUILD/tar-1.22/tests'
make[1]: Leaving directory `/home/build/rpmbuild/BUILD/tar-1.22/tests'
make[1]: Entering directory `/home/build/rpmbuild/BUILD/tar-1.22'
make[2]: Entering directory `/home/build/rpmbuild/BUILD/tar-1.22'
make[2]: Nothing to be done for `install-exec-am'.
make[2]: Nothing to be done for `install-data-am'.
make[2]: Leaving directory `/home/build/rpmbuild/BUILD/tar-1.22'
make[1]: Leaving directory `/home/build/rpmbuild/BUILD/tar-1.22'
+ exit 0
Checking for unpackaged file(s): /usr/lib/rpm/check-files /tmp/tar-1.22
error: Installed (but unpackaged) file(s) found:
   /usr/bin/tar
   /usr/info/tar.info
   /usr/info/tar.info-1
   /usr/info/tar.info-2
   /usr/libexec/rmt
   /usr/share/locale/bg/LC_MESSAGES/tar.mo
...
RPM build errors:
    Installed (but unpackaged) file(s) found:
   /usr/bin/tar
   /usr/info/tar.info
   /usr/info/tar.info-1
...
We haven't defined any files installed by this package, but our %install section created many files. We can look at them by looking in the BuildRoot directory.
[build@client11 SPECS]$ find /tmp/tar-1.22/ |head
/tmp/tar-1.22/
/tmp/tar-1.22/usr
/tmp/tar-1.22/usr/sbin
/tmp/tar-1.22/usr/share
/tmp/tar-1.22/usr/share/locale
/tmp/tar-1.22/usr/share/locale/pl
/tmp/tar-1.22/usr/share/locale/pl/LC_MESSAGES
/tmp/tar-1.22/usr/share/locale/pl/LC_MESSAGES/tar.mo
/tmp/tar-1.22/usr/share/locale/ky
/tmp/tar-1.22/usr/share/locale/ky/LC_MESSAGES
We need to tell rpm what we want done with these files, we'll do that next.

%files

The main thing to remember in this section is to always define config files as %config. There are subtleties to the way you define directories, but for the most part as long as you define a set of default owner and permissions (%defattr), your RPMs should turn out fine.

I usually start with a default attribute setting and then look for files that should be marked as documentation (%doc). Files marked with %doc are placed in /usr/share/doc/%{name}-%{version}. Populating this directory with files is very useful to the users of your package, most problems can be solved by looking in the /usr/share/doc directory.

%files
%defattr(-,root,root,-)
%defattr sets the default permissions for files using octal notation. The first parameter is the file mode, the permissions applied to files, a '-' means to keep the existing permissions. The last parameter is the directory mode, you can omit this completely and just put %defattr(-,root,root). root,root are the file owner and group respectively.

I usually look in the BUILD directory at this point to see which files should be included in doc, the general rule is anything marked Readme, README, README.txt or similar plus any files that are all CAPS. If there is a doc or html directory, just include the whole directory.

[build@client11 SPECS]$ ls ../BUILD/tar-1.22/
ABOUT-NLS   ChangeLog    configure.ac  lib          NEWS    rmt      THANKS
aclocal.m4  ChangeLog.1  COPYING       m4           po      scripts  TODO
AUTHORS     config.hin   doc           Makefile.am  PORTS   src
build-aux   configure    INSTALL       Makefile.in  README  tests
[build@client11 SPECS]$ 

In the above we should include ABOUT-NLS AUTHORS ChangeLog COPYING doc INSTALL NEWS PORTS README scripts THANKS TODO

%doc ABOUT-NLS AUTHORS ChangeLog COPYING doc INSTALL NEWS PORTS README scripts THANKS TODO 
Next we look in the install directory for the files that were installed by our %makeinstall.
[build@client11 SPECS]$ pushd /tmp/rpm-buildroot-tar-1.22/
/tmp/rpm-buildroot-tar-1.22 ~/rpmbuild/SPECS
[build@client11 rpm-buildroot-tar-1.22]$ cd usr
[build@client11 usr]$ ls
bin  doc  info  libexec  sbin  share
[build@client11 usr]$ ls doc/tar-1.22/
ABOUT-NLS  ChangeLog  doc      NEWS   README   THANKS
AUTHORS    COPYING    INSTALL  PORTS  scripts  TODO
[build@client11 usr]$ ls bin
tar
[build@client11 usr]$ ls libexec
rmt
...
Looking through the directory we see that the usr/doc directory has all the files we specified as %doc in it. tar itself is in usr/bin and rmt is in usr/libexec. There are some localisation files in share/locale that we should include. sbin is empty. We continue looking through directories until we come up with a files section and test it out. If we missed anything, rpm will be sure to tell us.
%files
%defattr(-,root,root)
%doc ABOUT-NLS AUTHORS ChangeLog COPYING doc INSTALL NEWS PORTS README scripts THANKS TODO
/usr/bin/tar
/usr/info/tar.*
/usr/share/locale/*
We omitted a file on purpose to see the error, running rpmbuild will fail because rmt is not listed.
RPM build errors:
    Installed (but unpackaged) file(s) found:
   /usr/libexec/rmt
If we now add rmt into our files, section, the rpm will build.
Checking for unpackaged file(s): /usr/lib/rpm/check-files /tmp/rpm-buildroot-tar-1.22
Wrote: /home/build/rpmbuild/RPMS/x86_64/tar-1.22-1.x86_64.rpm
We aren't finished though, we should really add a %changelog section to our spec file, so we can track the changes we make to it as the package is updated. But, before we do that, I should mention variables. There are many variables available to you when writing your spec files. Variables like %{name} and %{version} we've already seen, but there are variables for directories on the system. If you use these variables your rpm can more easily be ported to another rpm based system. Also, if your system ever decides to move directories you won't have to rewrite your spec file.

You can view all the variables available to you by running rpm --showrc |grep -- ^-14:. One important variable is _prefix, _prefix is used as a prefix for many of the other variables. On my system _prefix is /usr, on some systems it may be /opt or something different. The other 'usual suspects' when trying to use variables are _bindir, _datadir (which is /usr/share), _sbindir and _mandir. Using variables, our new files section is below.

%files
%defattr(-,root,root)
%doc ABOUT-NLS AUTHORS ChangeLog COPYING doc INSTALL NEWS PORTS README scripts THANKS TODO
%{_bindir}/tar
%{_infodir}/tar.*
%{_libexecdir}/rmt
%{_datadir}/locale/*
This version is more portable and maintainable, but also looks cooler and all your friends will be impressed by your use of variables.

%changelog

The changelog is often forgotten, but is very useful. In it you put your name, the date, the version you are working on and then freeform, the changes you made. I usually start with - initial build or similar when starting the log. In this case I'm going to put a fake email, but you should really put your real email here (provided you aren't going to post the spec file in it's raw form on the web anywhere, gotta love spammers don't ya?)

%changelog
* Tue Sep 22 2009 Thomas Howard Uphill  - 1.22
- initial build, example spec file
Now, when version 1.23 of tar is released, you would come back and insert a new entry before this one. The most recent modification should come at the top of the changelog (as with all good changelogs). Adding the version to your entry is useful later when you are trying to remember when you made a change to the spec file and for what version you did it.

The spec file is complete and this package will install cleanly on any system. There are several other sections to a spec file that we did not cover. I'll briefly describe them next.

other sections

I omitted several sections in the simple example. There are sections to run commands before you install the package, after you install the package, after you uninstall the package, before you install the package, and before you build the package. These sections are executed as bash scripts. You have access to the rpm variables as %{_variable} in most cases, you also have some other variables as bash variables $VARIABLE. Notably %{buildroot} is usually used as $RPM_BUILD_ROOT in these sections.

%pre

This is where you place anything you need to do before the package is installed on the system.

%post

This is where you place anything you need to do after installing the package. Typically you install users or start services in this section. If you installed libraries you would run ldconfig here. The kernel uses this section to setup grub and build initrd images for example.

%preun

pre-uninstall section is where you do things you need to do before you uninstall the package. You would stop a service here if you are uninstalling it. You would chkconfig --del the service to remove the symlinks in /etc/rc.d/runlevel. If your package uses alternatives, you would run alternatives --remove here.

%postun

post-uninstall is where you do things after the package is removed. If you added users in %pre, you remove them in %postun. The most typical thing to run here is ldconfig. If your package had installed desktop icons you would run update-desktop-database here and possibly gtk-update-icon-cache. You can't use anything that was in your package at this point, it's already gone.

%clean

This is an important section for builders. It is run before building the rpm. Typical use is to delete the working directory and install directory (%{buildroot}). If your package made some change during build that you wanted to make sure it did every time, you would undo the change here. For example, if your package requires an selinux boolean be set, you would unset it here to make sure your package is setting it correctly. Removing the buildroot directory is the only legitimate use I've found for this, you shouldn't really need to do more. You should be installing your packages in a sandbox after building them.

options for rpmbuild

It's a good idea to build a source rpm for your spec file. You'll keep the source rpm so that when you need to make a change to the package, you have everything you need readily available. To build a source rpm you use the unfortunate argument of bs.
[build@client11 SPECS]$ rpmbuild -bs tar.spec
Wrote: /home/build/rpmbuild/SRPMS/tar-1.22-1.src.rpm
If you are only building the source rpm, you don't need to bother with dependencies, so a good option here is to say nodeps.
[build@client11 SPECS]$ rpmbuild --nodeps -bs tar.spec
Wrote: /home/build/rpmbuild/SRPMS/tar-1.22-1.src.rpm
The build options for rpmbuild are as follows One nice thing you can do when you are building your rpms and having trouble is to skip the prep sections and just go straight into building, you would do that like this
[build@client11 SPECS]$ rpmbuild --short-circuit -bc tar.spec
Or if you have just built a package and it fails because you missed a file, you can just verify the files section again after making your change.
[build@client11 SPECS]$ rpmbuild --short-circuit -bl tar.spec
Processing files: tar-1.22-1
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: libc.so.6()(64bit) libc.so.6(GLIBC_2.2.5)(64bit) libc.so.6(GLIBC_2.3)(64bit) libc.so.6(GLIBC_2.4)(64bit) librt.so.1()(64bit) librt.so.1(GLIBC_2.2.5)(64bit) rtld(GNU_HASH)
Checking for unpackaged file(s): /usr/lib/rpm/check-files /tmp/rpm-buildroot-tar-1.22
I don't think I'll have time to cover some advanced topics, but something we use a lot is --target. --target allows you to specify the architecture for which you are building. We typically build on x86_64 and then specify --target to build the i386 rpm. You need to use the program setarch in front of rpmbuild to achieve a true i386 package.
[build@client11 SPECS]$ setarch i386 rpmbuild --target i386 -bb tar.spec 
Building target platforms: i386
Building for target i386
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.85806
...
configure: error: C compiler cannot create executables
See `config.log' for more details.
error: Bad exit status from /var/tmp/rpm-tmp.85806 (%prep)


RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.85806 (%prep)
There's a lot more to that problem though...you need a full i386 system installed so that you can compile i386 binaries on an x86_64 system. That means compilers, libraries, etc. The solution to that problem is beyond scope but I can summarize it with one word, mock.

It's doubtful you'll need any other options to rpmbuild, read the man page, but the rest are all margin case options.

nested packages

working on this...

kernel modules

this is a big topic...I'm still writing this.