RPM is now part of Linux standards. For administrators, RPM packages allow easy, silent installation and removal. For developers, RPM provides separation of packaging and original source and working on different distributions and platforms with just recompilation.
In this tutorial, we package an example application 'wget'. We start from scratch, so we will also install everything needed to build it.
First, we'll manually compile target and install it to a test directory. We'll discard the resulting program binary, but remember how we got it built. Then we'll install and configure rpm-build. Finally, we'll package the target application.
Packaging a target program means automating the targets compiling and installation. Before automating, we must know how to do that manually.
First, we will get sources for our chosen target 'wget' from programs homepage. We can use a generic search engine like google.com or the biggest free software directory freshmeat.net to locate wget homepage http://www.gnu.org/software/wget/. After making sure this is the correct homepage for our target program, we locate and download the source code http://ftp.gnu.org/pub/gnu/wget/wget-1.9.1.tar.gz. It is the latest (biggest version number) tarball (.tar.gz or .tar.bz) in the download directory.
$ wget http://ftp.gnu.org/pub/gnu/wget/wget-1.9.1.tar.gz
Then extract the tarball
$ tar -zxvf wget-1.9.1.tar.gz
$ cd wget-1.9.1
Most programs automate compiling with GNU make and related tools. './configure' detects computer architechture and installed libraries and writes this information to "Makefile". 'make' run on this same directory does the compiling by running compiler with given arguments.
$ ./configure
configuring for GNU Wget 1.9.1
checking build system type... i686-pc-linux-gnu
..
$ make
cd src && make CC='gcc' CPPFLAGS='' DEFS='-DHAVE_CONFIG_H -DSYSTEM_WGETRC=\"/usr/local/etc/wgetrc\" -DLOCALEDIR=\"/usr/local/share/locale\"' CFLAGS='-O2 -Wall -Wno-implicit' LDFLAGS='' LIBS='-lssl -lcrypto -ldl ' prefix='/usr/local' exec_prefix='/usr/local' bindir='/usr/local/bin' infodir='/usr/local/info' mandir='/usr/local/man' manext='1'
..
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/tee/wget-1.9.1/windows'
After a while, compiling ends. Find and run the resulting binary to see that it works.
$ ./src/wget
Now we have successfully compiled the program from source.
To install it in a directory we choose, we must change some settings and compile it again. Clean up compiled binary and temporary files used in compiling.
$ make clean
Create a directory for installing wget, and a new makefile that tells 'make install' to use that directory. Use a path from your own system instead of /home/tero. You can see the current path with 'pwd'.
$ mkdir myinstall
$ ./configure --prefix=/home/tero/wget-1.9.1/myinstall
Compile wget again, and install it to the directory we just created. Do not run 'make install' as superuser root.
$ make
$ make install
Once compiling and installation is finished, you should have a working installation of wget in myinstall/. Try running the wget installed in myinstall/. To type the whole, absolute path, start with './'. If you don't start the path with a dot, you end up running the wget that came with your Linux distribution instead of the one you compiled.
$ ls myinstall
bin etc info man share
$ ./myinstall/bin/wget
wget: missing URL
..
If it says "wget: missing URL" instead of "No such file or directory" or "segfault", well done, we've compiled wget and installed it to a directory we have created. The compiled or installed wget is not needed. We need to remember how we got it compiled and installed, because soon we will automate this process by packaging wget.
Rpmbuild must be installed and configured before we can use it. Some old writings mistakenly guide users to compile rpms with root (superuser) priviledges. Here, we install and configure rpmbuild as root, but use it as a user - just like any other program.
# yum -y install rpm-build
# /etc/rpm/macros # (c) GPL 2003 Tero.Karvinen at-sign iki.fi %packager %(echo "$USER") %_topdir %(echo "$HOME")/rpmbuild %_rpmtopdir %{_topdir}/%{name} %_builddir %{_rpmtopdir}/BUILD %_rpmdir %{_rpmtopdir} %_sourcedir %{_rpmtopdir} %_specdir %{_rpmtopdir} %_srcrpmdir %{_rpmtopdir} %_tmppath %{_rpmtopdir}/TMP %_buildroot %{_tmppath}/%{name}-root # http://www.iki.fi/karvinen/rpm-build-as-user.html
If you are still root, exit.
Create directories as described in /etc/rpm/macros
$ mkdir -p $HOME/rpmbuild/wget/
$ cd $HOME/rpmbuild/wget/
$ mkdir TMP/ BUILD/
Create a spec file. Start with a template from teromplates. Modified lines marked with bold. %files part is copy-pasted from rpmbuild error message.
# $HOME/rpmbuild/wget/wget.spec # Minimum to get it to package as rpm # (c)2004 Tero Karvinen Summary : Does foo for bar. Name : wget Version : 1.9.1 Release : 1 License : check_COPYING Group : check_usr_share_doc_rpm_GROUPS URL : http://program.homepage.invalid Source : http://program.homepage.invalid/%{name}-%{version}.tar.gz BuildRoot : /var/tmp/%{name}-buildroot #Requires : requires_to_run %description Long description could be taken from README. %prep rm -rf BUILD/* TMP/* /var/tmp/%{name}-buildroot/ %setup -q %build %configure make %install %makeinstall %files %defattr(-,root,root) %doc README %{_bindir}/* /etc/wgetrc /usr/share/info/wget.info-1.gz /usr/share/info/wget.info-2.gz /usr/share/info/wget.info-3.gz /usr/share/info/wget.info-4.gz /usr/share/info/wget.info.gz /usr/share/locale/bg/LC_MESSAGES/wget.mo /usr/share/locale/ca/LC_MESSAGES/wget.mo /usr/share/locale/cs/LC_MESSAGES/wget.mo /usr/share/locale/da/LC_MESSAGES/wget.mo /usr/share/locale/de/LC_MESSAGES/wget.mo /usr/share/locale/el/LC_MESSAGES/wget.mo /usr/share/locale/es/LC_MESSAGES/wget.mo /usr/share/locale/et/LC_MESSAGES/wget.mo /usr/share/locale/fr/LC_MESSAGES/wget.mo /usr/share/locale/gl/LC_MESSAGES/wget.mo /usr/share/locale/he/LC_MESSAGES/wget.mo /usr/share/locale/hr/LC_MESSAGES/wget.mo /usr/share/locale/hu/LC_MESSAGES/wget.mo /usr/share/locale/it/LC_MESSAGES/wget.mo /usr/share/locale/ja/LC_MESSAGES/wget.mo /usr/share/locale/nl/LC_MESSAGES/wget.mo /usr/share/locale/no/LC_MESSAGES/wget.mo /usr/share/locale/pl/LC_MESSAGES/wget.mo /usr/share/locale/pt_BR/LC_MESSAGES/wget.mo /usr/share/locale/ro/LC_MESSAGES/wget.mo /usr/share/locale/ru/LC_MESSAGES/wget.mo /usr/share/locale/sk/LC_MESSAGES/wget.mo /usr/share/locale/sl/LC_MESSAGES/wget.mo /usr/share/locale/sv/LC_MESSAGES/wget.mo /usr/share/locale/tr/LC_MESSAGES/wget.mo /usr/share/locale/uk/LC_MESSAGES/wget.mo /usr/share/locale/zh_CN/LC_MESSAGES/wget.mo /usr/share/locale/zh_TW/LC_MESSAGES/wget.mo /usr/share/man/man1/wget.1.gz %changelog * Sat May 29 2004 Tero Karvinen tero.karvineniki.fi - Initial spec-file
$ rpmbuild -ba wget.spec
Tested with Fedora Core 1 and 2.
Copyright 2003-2004 Tero Karvinen. All Rights Reserved. Not yet valid XHTML Basic 1.0