Print Logo

Roll Your Own RPM




<<  <   >  >>

Building from source is fun, but it's easier to distribute RPMs to a bunch of machines. You may recall that we recently built and installed the OpenTDS libraries and SQSH, a dandy little command line tool for use with MS SQLServer. These built nicely on my RedHat 7.3 system, and I have a bunch of other developer workstations running the same OS. So let's roll these tools into a couple of RPMS for easy distribution.

First, I must refer you to the excellent RPM HOWTO and its section on building RPMS. You really don't need me to tell you how to build RPMs, because this HOWTO is great. But sometimes it's nice to walk through a couple of examples together. We are building these RPMS on a Red Hat 7.3 workstation, using the default build directories provided by Red Hat under /usr/src/redhat.

[usr-3@srv-3 redhat]$ ls -l
total 20
drwxrwxr-x    3 root     wheel        4096 Apr 17 11:37 BUILD
drwxrwxr-x    8 root     wheel        4096 Dec 31  2001 RPMS
drwxrwxr-x    2 root     wheel        4096 Apr 17 12:16 SOURCES
drwxrwxr-x    2 root     wheel        4096 Apr 17 13:36 SPECS
drwxrwxr-x    2 root     wheel        4096 Apr 18  2002 SRPMS

Basically, when we build an RPM, we're scripting a source build and install. We resolve dependencies (or at least build an awareness of them into our package), we define build-time configuration options, and are able to add any additional tasks we desire, such as creating users, setting up rc scripts, adding cron jobs. This allows us to easily deploy a highly customized build/installation of a package.

The Spec File

All of the customizations mentioned above are defined in the spec file, which we will put in /usr/src/redhat/SPECS. The spec file should be named according to the following convention: package name-version number-release number.spec For our freetds RPM, we're going to create freetds-0.61-1.spec. Our file is going to be very simple, a bare bones build and install. We've already tested the build in our article about SQSH, so we can skip that step. Let's set up our spec file:

The header section:

Summary: FreeTDS libraries for Sybase/MSSQLSVR
Name: freetds
Version: 0.61
Release: 1   the version of the RPM
Copyright: GPL
Group: Development/Tools the group the package belongs to in Red Hat installer
Source: http://ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-0.61.tgz
note: this file name must be the same as you're using to build

The description is self-explanatory:

%description
Libraries for connecting to Sysbase/MSSQSVR DBs. Used by Perl DBD:Sybase
and sqsh.

The following sections define how the package is to be built and installed:

%prep  shell commands to be executed before build. also macros
are available for this section, see the HOWTO. This would be
the place for adding special users, patching the sources, etc.
%setup
./configure --prefix=/usr/local/freetds --enable-msdblib --with-tdsvr=7
%build
make
%install
make install
%clean

In the files section, you must list all of the files to be included in the package. There is really no way to come up with this list until you have built the package. There is also no easy way to generate the list. Luckily, in the case of freetds, every file is installed under the /usr/local/freetds directory.

%files
/usr/local/freetds

Changelog: list changes made with each modification of the RPM.

%changelog

Here's a link to the spec file in all its glory.

Building the RPM

Before we can build it, we need to put the tarball in /usr/src/redhat/SOURCES. OK, let's give it a whirl. We will use -b (build) a(both source RPM and binary RPM)

[root@srv-3 SPECS]# rpm -ba freetds-0.61-1.spec
--snipping profuse output from configure and make--
Processing files: freetds-0.61-1
Finding  Provides: (using /usr/lib/rpm/find-provides)...
Finding  Requires: (using /usr/lib/rpm/find-requires)...
Provides: libct.so.1 libsybdb.so.3 libtds.so.2 libtdssrv.so.1
PreReq: rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 
3.0.4-1
Requires(rpmlib): rpmlib(PayloadFilesHavePrefix) <= 4.0-1 
rpmlib(CompressedFileNames) <= 3.0.4-1
Requires: ld-linux.so.2 libc.so.6 libncurses.so.5 libnsl.so.1 libreadline.so.4 
libsybdb.so.3 libtds.so.2 libtdssrv.so.1 libc.so.6(GLIBC_2.0) 
libc.so.6(GLIBC_2.1) libc.so.6(GLIBC_2.1.2) libc.so.6(GLIBC_2.1.3)
Wrote: /usr/src/redhat/SRPMS/freetds-0.61-1.src.rpm
Wrote: /usr/src/redhat/RPMS/i386/freetds-0.61-1.i386.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.84503
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd freetds-0.61
+ exit 0

And we're cool. The binary RPM will be written in RPMS under the directory corresponding to the build system's architecture. Check it out:

[root@srv-3 SPECS]# ls -l ../RPMS/i386/
total 2408
-rw-r--r--    1 root     root      2129073 May 22 15:31 freetds-0.61-1.i386.rpm

The source RPM will be located under SRPMS. No architecture specific directories there. Let's build an RPM for sqsh, then we'll install them both on another system to make sure they work.

Building Another RPM

Step 1. The spec file.
This one has a slightly more complicated %prep section:


%prep 
%setup -n sqsh-2.1
export SYBASE=/usr/local/freetds
./configure

We have to use a setup macro because of the way the tarball is named. In our SOURCES dir, we have a tarball called sqsh-2.1-src.tar.gz. But when this is expanded, the resulting directory is called sqsh-2.1, *not* sqsh-2.1-src as rpm would guess. So we use the "-n" setup macro to tell rpm that the build directory will be called sqsh-2.1. Also in this section, we must export the SYBASE environmental variable to get a good build. Step 2. Build it:
Note: this time we're just going to build the binary RPM.

[root@srv-3 SPECS]# rpm -bb sqsh-2.1.spec 
--profuse output from configure and make--
Processing files: sqsh-2.1-1
Finding  Provides: (using /usr/lib/rpm/find-provides)...
Finding  Requires: (using /usr/lib/rpm/find-requires)...
PreReq: rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) 
<= 3.0.4-1
Requires(rpmlib): rpmlib(PayloadFilesHavePrefix) <= 4.0-1 
rpmlib(CompressedFileNames) <= 3.0.4-1
Requires: ld-linux.so.2 libc.so.6 libct.so.1 libdl.so.2 libm.so.6 
libtds.so.2 /bin/sh libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1)
Wrote: /usr/src/redhat/RPMS/i386/sqsh-2.1-1.i386.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.91986
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd sqsh-2.1
+ exit 0

Looks good. Now let's install them on some innocent, untouched system.

Testing

[root@victim1 src]# rpm -i freetds-0.61-1.i386.rpm 
[root@victim1 src]# rpm -i sqsh-2.1-1.i386.rpm 
[root@victim1 src]# sqsh -S mickey -U bb
sqsh-2.1 Copyright (C) 1995-2001 Scott C. Gray
This is free software with ABSOLUTELY NO WARRANTY
For more information type '\warranty'
Password: 
src/tds/login.c: tds_connect: 10.50.90.1:4000: Connection refused
Open Client Message
Layer 0, Origin 0, Severity 78, Number 41
Server is unavailable or does not exist.

Oops!! How did this happen? I did not take advantage of the power of RPM to tweak my automated install of the freetds package, which requires a configuration similiar to oracle's tnsnames for every SQLServer you connect to.

Building a Better RPM

Maybe we can rebuild the RPM, this time inserting a default server configuration into the freetds.conf file. I'm going to uninstall the RPMs from our victim system, clean up the build system, and try again. In cleaning up the build system, I will remove the already-existent /usr/local/freetds directory, to make sure that rpm doesn't use the files from the old install in making the new rpm. I am making a new spec file, freetds-0.61-2.spec, for the new version of the RPM. Here's what I'll include in the install section:

%install
make install
cat >> /usr/local/freetds/etc/freetds.conf << EOF
[MICKEY]
host = mickey.domain.com
port = 1433
tds version = 7.0
EOF

Now we'll try installing freetds and sqsh again on the victim.

Testing Again

[root@victim1 src]# rpm -i freetds-0.61-2.i386.rpm 
[root@victim1 src]# rpm -i sqsh-2.1-1.i386.rpm 
[root@victim1 src]# sqsh -S mickey -U usr-3            
sqsh-2.1 Copyright (C) 1995-2001 Scott C. Gray
This is free software with ABSOLUTELY NO WARRANTY
For more information type '\warranty'
Password: 
[2] mickey.tempdb.1> select count(*) from sysusers;
-----------
13
(1 row affected)
[3] mickey.tempdb.1> 

There's the joy. I think you'll agree that rolling your own is a lot of fun when you can put whatever you like inside.



This article comes from NetAdminTools:
http://www.netadmintools.com/

The URL for this story is:
http://www.netadmintools.com/art272.html

Copyright 1997-2009 NetAdminTools.com. Read our Terms of Use.