Chapter 35
Creating Your Own RPM Packages
|
|
|
|
|
![](gif/black.gif) |
In this chapter: |
|
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Organizing the build process
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Learning how to prepare the source code for a RPM Package
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Integrating software into the SuSE Linux Distribution
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Learning to create a Patch-File
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Learning about Spec-Files and how to create them
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Building a sample package
|
|
|
|
![](gif/black.gif) |
|
The last chapter explained how to compile and install the source
packages included in the SuSE distribution. This is useful when you
want to change something in the source code, such as apply a bug fix
or change application defaults. But what if you want to create your
own RPM because you found some interesting piece of software that is
not yet included in the SuSE distribution? The answer is that this is
nearly the same procedure as we saw in chapter 34, when we
used an SRPM to build a package. The difference is that you have to
create the spec and the patch file yourself. Usually it's no big deal
to create an RPM package. Sometimes it can be tricky. If you only want
to give the new software a test drive, you are probably better of with
just compiling and installing it as explained in the documentation
that (hopefully) comes with the source. However, if you want to give
the package to friends, or you want to use it for other machines
running SuSE Linux, the overhead for building the RPM pays off
quickly.
|
![NOTE](gif/icon_note.gif) |
This chapter is not intended to teach you how to compile sources and
how to install software on a Linux system. You should have experience
with this before and be familiar with make and similar
utilities like configure et. al. We will talk about
creating an RPM package instead of simply installing the software on a
single system. If you have no experience in building software from the
source, you may have difficulties following the instructions given
here.
|
|
|
35.1 | Roadmap |
|
If you decide to build an RPM package for SuSE Linux, you should know
about a couple of important points about integrating applications into
the SuSE Linux distribution. Integrating software into a system often
means more than just creating the binaries from the source and then
copy them to a directory where everybody can use it. Most software
comes with some kind of configurations file. There is documentation to
be installed. There may be something to initialize when the system is
booted. Regular scheduled maintenance or clean up scripts may be
needed. If there are environment variables needed for this package,
they should be included into the users standard environments. We saw
in other chapters of this book that SuSE covers all these tasks with
custom designed mechanisms. In this chapter we will see how we can use
these mechanisms for our new software package.
So what tasks are needed in order to create an RPM package?
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Get the source code
If you don't write the source yourself, you'll probably need to
download a tgz file from an FTP server.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Change the source code or the makefile to adopt it for SuSE Linux
Most software assumes a certain type of file system layout. This may
or may not be the layout of the SuSE Linux system you envision the
software to run on. In most cases no drastic changes are
necessary. Seldomly can you use the source "as-is".
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Create a patch file containing your changes
Remember that in chapter 34 we learned that RPM keeps the
original sources and has a patch file reflecting the changes?
We're actually about to put this into action.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Create additional scripts to integrate the package
Again, you may have to write rc-scripts to be executed at
boot time to start a new service or create a maintenance script to be
scheduled by cron.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Edit system files to ingrate the package
If you need a rc-script, you may want to use /etc/rc.config
to set configuration variables. You also may need entries in
/etc/inetd.conf to alert inetd on your new
service. Users may need a special environment variable which you may
want to include in their standard environment.
All these issues affect system configuration files. You should make
these changes and test them. We will see later in this chapter how
you can use scripts triggered by RPM during the installation to
automate these changes.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Create a list of all files that belong to the package
RPM needs to have this list. We will see how to create this list
and how to mark configuration and documentation files in it.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Create the spec file
If all of the previously listed tasks are done, we can continue and create a
spec-file to automate the whole process of packaging the software.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Use RPM to build the package
This is the last step. If we have the sources, the patch file, and
the spec-file, we can use them to build the package as discussed
in chapter 34.
|
|
|
You see there are quite a few steps to be done. It sounds a lot worse
than it actually is. Depending on the kind of software you want to
create a package for, you don't have to perform all of these
steps. And even if you have to, it's not an impossible task.
|
![NOTE](gif/icon_note.gif) |
No matter how hard you try, there are certain aspects that can't be
done with RPM in the SuSE distribution. The most obvious one is that
you can't include any package into the SuSE distribution, meaning you
can't make it transparent whether the package comes from SuSE or from
a third party, in this case from you. YaST uses its own database of
packages that are contained in the distribution. SuSE doesn't provide
tools to modify this database. Unfortunately, there is no way to
include your package into YaST's native package selection
mechanism. If you want to see it there, you will have to mail the
package to SuSE and hope that they can include it in their next
release. The other issue which is more directly related, concerns
dependency. Since SuSE doesn't use the dependency features of RPM, you
can't rely on them either. YaST has its own dependency database but
doesn't provide tools to change it.
|
|
|
35.2 | Preparing the Source Code |
|
Just as in the last chapter, we will use an example to walk through
the build process. This time we will pick some software that is not
yet part of the SuSE distribution, a utility that controls digital
cameras based on Sierra Imaging firmware: photopc.
To begin, you can download the source from
http://www.average.org/digicam. You'll also find more
information on this software on the Web site. Obviously, right now our
focus is to build the package, not to explore it's functionality.
This package doesn't need a lot of customization. The only thing we
will add is the automatic creation of a soft link in the
/dev directory. PhotoPC uses a serial connection to
control the camera. It's default device is
/dev/photopc. You can easily guess that this file doesn't
exist in SuSE Linux. What we'll do is add a variable to
/etc/rc.config [to set the device for] the camera. Then
we'll create a script to be called by SuSEconfig, which
will read the variable and create the link accordingly. It's pretty
simple, and demonstrates how you can integrate new functionality into
SuSE's setup structure.
|
35.2.1 | Unpacking the Sources |
|
Enough of the introduction, let's get started. The first step is to
get the sources to the proper place and check if they need any changes
in order to build them properly. We assume that you downloaded the
source archive to the /tmp directory. We'll start by
copying them to /usr/src/packages/SOURCES, and unpacking
the archive in /usr/src/packages/BUILD:
|
| # cd /usr/src/packages/SOURCES/
# cp /tmp/photopc-3.01.tar.gz .
# cd ../BUILD/
# tar xzvf ../SOURCES/photopc-3.01.tar.gz
photopc-3.01/
photopc-3.01/a12scan.c
photopc-3.01/a12scan.h
[... file list skipped ...]
photopc-3.01/usleep.c
photopc-3.01/usleep.h
|
|
|
35.2.2 | Compiling the Sources |
|
Now we have to find out how to build the package. Usually you find a
file called README or INSTALL in the source
hierarchy, which tells you what to do. In this case it is the
README file. The instructions are:
|
| ...
On Unix, first run "./configure". Then, type `make' which will
build the library and executables in the current directory.
`make install' will install the executables and manual pages.
`make install.lib' will install the library and the .h file.
...
|
|
OK, now let's see if everything works as it's supposed to:
|
| # cd /usr/src/packages/BUILD/photopc-3.01
# ./configure --prefix=/usr/local
creating cache ./config.cache
checking for gcc... gcc
checking whether we are using GNU C... yes
[... configure output skipped ...]
creating ./config.status
creating Makefile
creating config.h
|
|
Looks great -- configure had no problems creating the
Makefile.
|
![NOTE](gif/icon_note.gif) |
Note that we called configure with the option
--prefix=/usr/local. For most packages this the default,
but sometimes it isn't and it's a good idea to set it in order to
avoid nasty surprises. The --prefix options tells
configure where the software should be installed. We
learned in chapter 2 that software which is not part of the
distribution itself, should go to the /usr/local
hierarchy. To ensure that we don't violate the FHS, we use this
parameter for configure. In case the package you want to
build doesn't support autoconfiguration using configure,
you should inspect the Makefile to ensure that the
installation path is set accordingly.
|
|
Next is the compilation. Calling make should create the binaries:
|
| # make
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_read.c
eph_read.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_iob.c
eph_iob.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_err.c
eph_err.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_cmd.c
eph_cmd.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_io.c
eph_io.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_open.c
eph_open.c:2: warning: `rcsid' defined but not used
/usr/bin/ar r libeph_io.a eph_read.o eph_iob.o eph_err.o eph_cmd.o eph_io.o eph_open.o
ranlib libeph_io.a
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c photopc.c
photopc.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c a12scan.c
a12scan.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c fnames.c
fnames.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c ctimez.c
ctimez.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c filetime.c
filetime.c:2: warning: `rcsid' defined but not used
gcc -o photopc photopc.o a12scan.o fnames.o ctimez.o filetime.o -L. -leph_io
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c epinfo.c
epinfo.c:2: warning: `rcsid' defined but not used
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c exifscan.c
exifscan.c:2: warning: `rcsid' defined but not used
gcc -o epinfo epinfo.o a12scan.o exifscan.o fnames.o ctimez.o filetime.o
|
|
And again, everything looks fine. There are some warnings but nothing
that should worry us.
|
35.2.3 | Installing the new Software |
|
Installation is the next step. Here we need to proceed more carefully,
since we need to get a list of all installed files. We need to put
that list in the spec file later on. The README file told
us to do make install and make install.lib to
start the installation:
|
| # make install
/usr/bin/ginstall -c -d -m 755 /usr/local/bin
/usr/bin/ginstall -c -m 755 photopc /usr/local/bin
/usr/bin/ginstall -c -m 755 epinfo /usr/local/bin
/usr/bin/ginstall -c -d -m 755 /usr/local/man/man1
/usr/bin/ginstall -c -m 644 photopc.man /usr/local/man/man1/photopc.1
/usr/bin/ginstall -c -m 644 epinfo.man /usr/local/man/man1/epinfo.1
# make install.lib
/usr/bin/ginstall -c -d -m 755 /usr/local/lib
/usr/bin/ginstall -c -d -m 755 /usr/local/include
/usr/bin/ginstall -c -m 644 libeph_io.a /usr/local/lib
/usr/bin/ginstall -c -m 644 eph_io.h /usr/local/include
|
|
If you look at the output, you see that six files have been installed:
|
| /usr/local/bin/photopc
/usr/local/bin/epinfo
/usr/local/man/man1/photopc.1
/usr/local/man/man1/epinfo.1
/usr/local/lib/libeph_io.a
/usr/local/include/eph_io.h
|
|
|
![TIP](gif/icon_tip.gif) |
Unlike this example, it's not always easy to figure this out. Some
packages have a tremendous number of files to install, but lack a
clear output of make install to help sort the files out.
In those cases the find utility can help. After you run
the make install command, perform a find for
all files that have changed in the last five minutes. The list will
include some files which don't belong to the package, like log-files
and files someone else may have changed at the same time. But it
should be obvious which files belong to the new software and which
don't. Save this list, we'll refer to it later.
|
|
|
35.2.4 | Pit Stop #1 |
|
So far we've been really lucky. There was no need to do any
customization.
|
![TIP](gif/icon_tip.gif) |
What if you had to patch some files to get to this point? Nothing
dramatic happens. Just make sure you know which files were changed and
that you have copies of those files. Store those copies somewhere
outside the of the build tree. We'll come back to them later when we
create the patch file.
|
|
At this stage you should have reached the following milestones:
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
The source package gets installed in its own subdirectory in /usr/src/packages.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
The sources compile without errors.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Install the binaries, libraries, configuration files, etc. in the /usr/local hierarchy.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
In case there were changes to any files in the source tree, have copies of the changed files at a separate location.
|
|
|
|
![NOTE](gif/icon_note.gif) |
One thing we didn't talk about at all, because it's simply too obvious
- You should check if the installed binaries actually work. It doesn't
interfere with the process of creating the RPM, but it also doesn't
make sense to create an RPM for a piece of software that doesn't
work. So do your self a favor and take some time to test the installed
binaries.
|
|
If all this is true, we can go on to the next step and think about the
additional tasks we need to integrate the software into the SuSE setup
scheme.
|
35.3 | Integration into the SuSE Setup Scheme |
|
The photopc utility connects to the digital camera using
a serial device. The default device it looks for is
/dev/photopc. In earlier discussions, we talked about
creating this device in conjunction with a variable in
/etc/rc.config by using a script automatically called by
SuSEconfig. We have two points to cover:
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Adding a variable to /etc/rc.config
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Creating a script that reads /etc/rc.config and creates the
device according to the specifications in /etc/rc.config
|
|
|
|
35.3.1 | Adding entries to existing configuration files |
|
The first point seems trivial, but it is the more difficult of the two
tasks. It is trivial to edit /etc/rc.config manually and
add variables to it. We want to do it automatically during the
installation of the package. This could still be an easy issue, but we
want to make sure that an entry that already exists will be recognized
and remain unchanged by the installation procedure. A possible
scenario is that someone installed the software, modified the
settings, and for whatever reason decided to remove it again.
|
![NOTE](gif/icon_note.gif) |
Entries in /etc/rc.config remain unchanged, even if the
software is removed. This is questionable behavior, but it's the SuSE
way of doing things. We just have to accept this and work with it.
|
|
So what if the administrator in the scenario we describe decides that
he wants to install the package again? He should be able to reuse the
configuration he's customized for his system. In our example this
configuration is rather trivial, but it's one possibility. There are
other packages which use more than one variable, where it is much more
desirable not to void the old configuration.
SuSE created a tool that merges configuration files:
fillup. It's comprised of two files, a
basefile and a
newfile. Fillup reads both files and
checks on whether variables in the new file are not contained in the
basefile. New variables are appended to the basefile
including comments preceding the variable definition, the variable
name, the assignment delimiter, and the variables value.
The documentation for fillup is included in the SuSE
Linux distribution as info file, GNU's new standard
for documentation. So instead of the old standby man,
use info fillup to get more information on this tool.
So what we have to do is to write the settings we want to add to
rc.config into a file and call fillup
accordingly. In this case it's just one variable, which we'll call
DIGITAL_CAMERA_DEVICE and it should be set to the device
the camera it connected to. We create a file to store the setting,
photopc.tmpl. We'll add this to
/etc/rc.config:
|
| #
# Digital Camera Device for PhotoPC Application
#
DIGITAL_CAMERA_DEVICE="/dev/ttyS1"
|
|
The name used here was selected at random. SuSE uses the naming
convention packagename.tmpl for its packages, so
we've used the same. To see how fillup works, we will
call it manually. Later this will be done by the post-install script
of the RPM package. To add this variable to
/etc/rc.config, all you have to do is go to the directory
where you stored the template file and call:
|
| # fillup /etc/rc.config photopc.tmpl
|
|
If you look at the end of the file /etc/rc.config, you
will see that the new variable and the comment are added, just as
specified in the template file. To see if fillup really
respects entries which are already in /etc/rc.config,
call it again. Try this and you will find out that
/etc/rc.config remains unchanged. Even if you move the
variable definition around within /etc/rc.config, fillup
will find it and not replace it or add a second copy.
|
![TIP](gif/icon_tip.gif) |
In our example we used fillup to modify
/etc/rc.config. You can use it to modify any configuration
file. For example, if you want to make entries to /etc/inetd.conf or
/etc/inittab, fillup is a good tool to use. Refer to
the info page to learn about options to change the variable/value delimiter,
the comment character, and more.
|
|
|
35.3.2 | Extending the SuSE Setup Mechanism |
|
The second issue is much easier. It involves a script that uses this
entry to create the file. All we need to do is write the script and
put in the right place. In chapter 2 we learned that the
directory /sbin/conf.d contains scripts which are called
by SuSEconfig every time it runs. SuSEconfig
takes care of a lot of tasks by itself. When it's finished doing this,
it looks in the directory /sbin/conf.d and calls every
script that it finds in the file. This mechanism enables it to add
functionality to SuSEconfig easily. All you have to do is
put a script into /sbin/conf.d. So all we have to do in
our script is to read the setting from /etc/rc.config,
check if the variable DIGITAL_CAMERA_DEVICE is set, and
if so, we create the appropriate link in /dev:
|
| #
# /sbin/conf.d/SuSEconfig.photopc
#
# Read settings from /etc/rc.config
test -f $ROOT/etc/rc.config || {
echo "No $ROOT/etc/rc.config found."
exit 1
}
. $ROOT/etc/rc.config
# Create link
if test -n $DIGITAL_CAMERA_DEVICE ; then
echo "Creating link for PhotoPC: $DIGITAL_CAMERA_DEVICE -> /dev/photopc"
rm -f $ROOT/dev/photopc
ln -sf $DIGITAL_CAMERA_DEVICE $ROOT/dev/photopc
fi
|
|
|
![CAUTION](gif/icon_caution.gif) |
Note that we prefixed every path in the script with
$ROOT. This is done to keep the script
relocatable. Remember when we used a different root directory for the
installation of the diskless client in chapter 31? In
order to make this feature work reliably, the current installation
root is passed to every script involved in the installation. 'If you
don't follow this convention, the script may fail in situations like
the one discussed in chapter 31.
|
|
To test this, copy the script to /sbin/conf.d and run
SuSEconfig. Don't forget to set the executable flag for
the script, otherwise it won't be executed:
|
| # chmod u+x /sbin/conf.d/SuSEconfig.photopc
|
|
You should see the output of the echo command we inserted in the
script during the SuSEconfig execution:
|
| # SuSEconfig
Started the SuSE-Configuration Tool.
Running in full featured mode.
Reading /etc/rc.config and updating the system...
Executing /sbin/conf.d/SuSEconfig.gdm...
Executing /sbin/conf.d/SuSEconfig.groff...
Executing /sbin/conf.d/SuSEconfig.kdm...
Executing /sbin/conf.d/SuSEconfig.l2h...
l2h: Checking installation... Done.
Executing /sbin/conf.d/SuSEconfig.perl...
Executing /sbin/conf.d/SuSEconfig.photopc...
Creating link for PhotoPC: /dev/ttyS1 -> /dev/photopc
Executing /sbin/conf.d/SuSEconfig.sendmail...
Executing /sbin/conf.d/SuSEconfig.susehilf.add...
Executing /sbin/conf.d/SuSEconfig.tetex...
Processing index files of all manpages...
Finished.
|
|
|
35.3.3 | Pit Stop #2 |
|
At this point we've fully integrated the new software package into the
SuSE Linux system. Up till now we've done it manually, which helped us
figure out which tasks are needed and to make sure they work. We
collected more files to add to the software package. The add-ons to
the configuration files (photopc.tmpl in our example),
and scripts to expand the functionality of the SuSE tools (this is
SuSEconfig.photopc for this example). Now we can go on
and automate these steps, so that they are executed during the
installation without the need for manual interaction.
|
35.4 | Creating the Patch-File |
|
Now that we have completed all the preparations, we can continue and
create the patch file for the new package. Why do we need a patch file
if the software build just fine without any changes? There are two
reasons. We created additional files that should be contained in the
package. Another way of getting them in there would be to have a
separate tgz file, which we unpack from within the spec
file. This would work perfectly and is actually a reasonable way to
go. The second reason is that we created the patch-file for
educational purposes. Since this chapter explains how to build an RPM
package, it would be incomplete without explaining the patch
mechanism.
|
35.4.1 | Creating two trees |
|
To create the patch file, we need two directory trees. One represents
the original source tree and the other one includes all changes that
has been made to this source tree. The patch file will only contain
these changes. The obvious intention of the patch file is to be able
to restore the revised tree by using the original archive and the
patch file.
The original source tree is basically the unpacked tgz
file. Besides unpacking the file, you must rename it. You can choose
whatever new name you'd like. Common practice is to add
.orig to the original directory name:
|
| # cd /usr/src/packages/BUILD
# tar xzf ../SOURCES/photopc-3.01.tar.gz
# mv photopc-3.01 photopc-3.01.orig
|
|
Now we have to unpack the tgz archive again and then
apply all changes we need to build the package to this copy of the
sources. For this example this means we will create a subdirectory and
store the two files we used to integrate the software into the SuSE
Linux System in this directory:
|
| # cd /usr/src/packages/BUILD
# tar xzf ../SOURCES/photopc-3.01.tar.gz
# cd photopc-3.01
# mkdir SuSE
# cd SuSE
# cp /tmp/photopc.tmpl .
# cp /sbin/conf.d/SuSEconfig.photopc .
|
|
The commands we've shown only work for the example illustrated. For
any other software there may be additional changes to the actual
sources, more files to add, etc. In case, there are two different
trees at this point.
|
35.4.2 | Finding the difference |
|
To create the actual patch file, the command diff is
used. In the simplest case, diff compares the contents of
two files. If two directories are given as arguments,
diff compares corresponding files in both directories, in
alphabetical order. Diff never compares the actual
contents of a directory as if it were a file. And of course that's
what we want to do here- compare the two trees we just created:
|
| # cd /usr/src/packages/BUILD
# diff -ruN photopc-3.01 photopc-3.01.orig > ../SOURCES/photopc.diff
|
|
Issuing the diff command will create the file
/usr/src/packages/SOURCES/photopc.diff. If you look at
this file, you will see that diff found the additional
directory and the two files we copied in there:
|
| diff -ruN photopc-3.01.orig/SuSE/SuSEconfig.photopc photopc-3.01/SuSE/SuSEconfig
--- photopc-3.01.orig/SuSE/SuSEconfig.photopc Wed Dec 31 16:00:00 1969
+++ photopc-3.01/SuSE/SuSEconfig.photopc Fri Jul 16 13:34:25 1999
@@ -0,0 +1,18 @@
+#
+# /sbin/conf.d/SuSEconfig.photopc
+#
+
+# Read settings from /etc/rc.config
+test -f $ROOT/etc/rc.config || {
+ echo "No $ROOT/etc/rc.config found."
+ exit 1
+}
+. $ROOT/etc/rc.config
+
+# Create link
+if test -n $DIGITAL_CAMERA_DEVICE ; then
+ echo "Creating link for PhotoPC: $DIGITAL_CAMERA_DEVICE -> /dev/photopc"
+ rm -f $ROOT/dev/photopc
+ ln -sf $DIGITAL_CAMERA_DEVICE $ROOT/dev/photopc
+fi
+
diff -ruN photopc-3.01.orig/SuSE/photopc.tmpl photopc-3.01/SuSE/photopc.tmpl
--- photopc-3.01.orig/SuSE/photopc.tmpl Wed Dec 31 16:00:00 1969
+++ photopc-3.01/SuSE/photopc.tmpl Fri Jul 16 13:34:15 1999
@@ -0,0 +1,4 @@
+#
+# Digital Camera Device for PhotoPC Application
+#
+DIGITAL_CAMERA_DEVICE="/dev/ttyS1"
|
|
The options we gave to diff mean that it should scan the
directories given as argument recursive (-r), create a
patch file in unified format (-u) and
that new files and directories should be treated as present but empty
in the original tree (-N). These options are needed to
recreate the status quo using the original source tree as reference
later on, when we build the package with RPM.
|
35.4.3 | Final Pit Stop |
|
At this point we are almost done. We created the patch file containing
the differences of our source tree to the original tree. All that's
missing is the spec file which contains the instructions on how to
build the package.
|
35.5 | Creating the Spec-File |
|
In chapter 34 we saw that the spec file is the central
source of information for building RPM packages. We learned how to use
spec files to build binaries from source RPM packages. In this chapter
we want to create a source RPM package. This means we will have to
create the spec file ourselves.
|
35.5.1 | Spec File Sections |
|
A spec file contains different sections which reflect the different
build stages such as those discussed in chapter 34, plus an
additional framework:
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Preamble
Basic information about the package as a result of calling
rpm-qi. It's simply a brief description of the the
package, author, copyright, version, release number, etc.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Prep Section
All steps needed to build the package are defined in this
section. This includes unpacking the sources, applying the patch file,
running the configure script, and other similar tasks. The
prep-section is basically a shell script (bash) which
performs these tasks.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Build Section
Another shell script that performs the package build
operations. Usually a single make command that starts the
build process.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Install Section
A shell script which performs the installation. Here you either
specify where to put each file, call make install,
or both.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Install and Uninstall and Verify Scripts
The sections prior to these contained scripts that were executed
during the build process of the package. However, the scripts in these
sections run on the system the package is installed on. You can
specify scripts to be executed:
| |
![*](gif/bullet.gif) ![](gif/clear.gif) |
Prior to the package being installed
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
After the package has been installed
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Prior to the package being erased
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
After the package has been erased
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Or whenever RPM is used to verify the package
|
|
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Clean Section
You can use this section to specify a script that cleans up after the
build. Rarely used, as you can use RPM to do this.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
File List
Here you list all files that should go into the package. This is also
the location where you specify which files are documentation and which
are configuration files.
|
|
|
We'll walk through each section and develop the spec file for our example as we move along.
|
35.5.2 | The Preamble |
|
In general, the preamble consists of one line entries. Every line
starts with a tag followed by a colon and the actual information. You
can put the lines in any order, but most of them are required, so make
sure you don't forget an entry. The preamble for the PhotoPC example
is shown below:
|
| # ===========================================================================
# Spec File for Package PhotoPC
# ===========================================================================
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Preamble
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Name: photopc
Summary: Tool to Communicate with Digital Cameras
Version: 3.01
Release: 0
Copyright: Free Freely distributable
Group: bb/graphics/digicam
Provides: digicam-download
Autoreqprov: yes
Source: photopc-3.01.tar.gz
Patch: photopc.diff
Vendor: Bodo Bauer
Distribution: Bodo's Tools
Packager: Bodo Bauer <bb@ricochet.net>
%description
This is a library and a command-line front-end to manipulate digital
still cameras based on Fujitsu's chip set and Sierra Imaging firmware. The
program is known to work with Agfa, Epson, Olympus, Sanyo and Nikon (at
least CoolPix 900, but not CoolPix 600!) cameras.
The cameras typically come with software for Windows and for the Mac, but no
description of the protocol. With this tool, they are manageable from a
Unix box.
|
|
Most tags have obvious meanings, but others are a little obscure, so lets define each tag:
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Name - The package name
This entry determines what the package will be called. For ease of use,
the name should be related to the software you're packaging. You will
find the software under this name in the RPM database once it's
installed.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Summary - Short description of the software
A one line description of the software package. It should
give an overall idea of what this package is about. A more detailed
description will be given later in the preamble.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Version - Version of the software
This entry contains the version number of the software being
packed. This number is used to compute if the software in one package
is more recent than the version in another package for upgrade
issues. This version also becomes part of the package label.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Release - Release number of the package
The release number should be increased every time you package the same
version of this software. The release number is used to differentiate
different builds of the same software version. The release number also
is part of the package label.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Copyright - Copyright Information
The intention of this entry is to hold the package's copyright
information, to make is easy to see which packages are freely
distributable and which are covered by a proprietary license. However,
in most cases, SuSE uses this field to hold the author's name.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Group - Group information
A slash (/) separated list of strings that is used to set the
package in relation to other software packages. The list of
groups should become more specific from the left to the
right. In the example I chose bb as the most general group and
then became more specific in sorting it into graphics and
digicam as most specialized relation.
|
![NOTE](gif/icon_note.gif) |
SuSE has unsorted as entry in almost all their packages. They don't use this feature.
|
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Provides - Virtual package information
To resolve dependencies, RPM supports virtual
packages. I.e., your system may require that a
mail-reader be installed. This dependency would be
resolved if any package that has mail-reader is
installed. The thought behind virtual packages is that there may be
more than one package providing the same functionality. SuSE
doesn't use this feature.
|
![NOTE](gif/icon_note.gif) |
YaST has it's own dependency database, which is not reflected in the SuSE spec files.
|
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Autoreqprov - Automatic dependency processing
RPM can automatically create a list of provided binaries and shared
libraries along with a list of shared libraries which is required by the
packages. This tag allows you to turn this feature on (yes) or off
(no).
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Source - Name of the source archive
With this tag you specify the tgz file containing the original
source tree. In the example we used here, we have a local file as
source archive. RPM also supports FTP servers that you may use as a repository for
source archives. You could use something like
ftp://ftp.server.com/pub/sources/xyz.tgz as the specification of
the source file.
You have the flexibility to support multiple source files. To specify additional
source files use the tags Source1:, Source2:, and so
on.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Patch - Specification of the patch file
Like the Source tag, this tag is used to specify the patch file
for this package. There also can be more than one patch file,
specified with the same convention as multiple source files, by adding
consecutive numbers to the original tag; Patch1, Patch2, ...
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Vendor - Packager of the software
The name of the person or organization responsible for packaging the
software should be specified with this tag.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Distribution - Name of package group
The name of this tag is somewhat confusing. Contrary to its name, it
doesn't denote the Linux distribution this package was built for. The
tag should be used to define a group of packages that this particular
package is a part of. With a Linux distribution, this tag would
indicate the distribution's name. But it also could be your personal
tool selection, or a complete set of software that is packaged in a
large number of separate RPMs.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Packager - Package builder
This is the place where your name and e-mail address should be
listed. This tag specifies the person who built the package.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Description - Package description
A detailed description of the package. Unlike the other tags, the
description can span more than one line. This description should
give a short, but not too brief overview of the software's purpose.
|
|
|
These are the tags often found in the preamble. There are more tags
available. For example, you can specify an icon for the package which
graphical RPM tools may use or a URL to the software's home
page. Refer to the RPM documentation for a full list of all package
tags. In general the tags I've described should be sufficient to build
most packages. Most of the tags contain information that are meant to
provide information about the packaged software for users who are
about to install the package or want to find out more about what they
already have on their system. Only the tags listed are actually needed
for the automated package build.
|
35.5.3 | The Prep Section |
|
The prep section doesn't contain any information meant for "human
consumption". It is entirely focused on automating the preparation
stage of the build process. The line %prep starts the
prep-section. After that, shell commands which perform the preparation
are given. In chapter 34 we saw that this includes
unpacking the archive, applying the patch file, and probably running a
configure script:
|
| # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Prep-Section
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%prep
%setup -n photopc-3.01
%patch -p1
./configure --prefix=/usr/local
|
|
You see the use of two macros in the prep-section above --
%setup and %patch. In addition to shell
commands, these two macros are provided by RPM to make life easier for
the package builder.
|
| The 'setup' Macro |
|
To simplify the unpacking of the source archive, the %setup
macro combines a bunch of shell commands into one call. The line
|
| %setup -n photopc-3.01
|
|
triggers the following tasks:
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Reverts to the BUILD directory
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Removes the old build tree of the package, if there is one
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Decompresses and unpacks the source archive
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Becomes the source tree
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Sets owner and group of all files to root
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
Sets sane permissions for all files in the source tree
|
|
|
The directory name of the source tree inside the BUILD
directory is given with the -n parameter. It defaults to
the name of the source archive, after the tgz extension
has been stripped. Another frequently used option is -a
number. You use this to set up additional source
files. For example, if you specified a second source file using the
Source1: tag in the preamble, you would use %setup -a1 to unpack this source tree.
There are more options to this macro which are often not needed, but
sometimes very useful. If you have special issues, refer to the RPM
documentation to get a description of those options.
|
| The 'patch' Macro |
|
As you may have guessed, this macro is used to apply patch files to
the source tree. There are two important options for this macro. The
-p number options used to strip the
smallest prefix containing number leading slashes
from each file name found in the patch file. A sequence of one or more
adjacent slashes is counted as a single slash. This controls how file
names found in the patch file are treated.
The other option worth mentioning, -P
number, has the same function as -a to
%setup, it tells %patch which patch-file
to use. A patch-file listed as Patch1: in the preamble
will be applied using %patch -P 1.
There are more options to this macro too, which again can be found in
the RPM documentation.
|
35.5.4 | The Build Section |
|
After preparing the source tree, it's time to compile the
sources. This is controlled by the build-section of the
spec-file. This section begins with the keyword %build
and contains shell command to initiate the build process. In most
cases a simple make will do the job, just as it is the
case in our example:
|
| # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Build-Section
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%build
make
|
|
|
35.5.5 | The Install Section |
|
All commands needed to install the files that belong to this package
belong to this section. Often a make install is all you
need. But if you have additional documentation or custom created files
to install you will need to do some additional work here, like we had
to do for our example package:
|
| # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Install-Section
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%install
make install
# copy additional docs to /usr/doc/packages/photopc
mkdir -p /usr/doc/packages/photopc
cp README protocol.htm readme.dos /usr/doc/packages/photopc
# check if this is a SuSE Linux system and install the custom parts
if test -d /sbin/conf.d ; then
cp SuSE/SuSEconfig.photopc /sbin/conf.d
if test -d /var/adm/fillup-templates ; then
cp SuSE/photopc.tmpl /var/adm/fillup-templates
fi
else
echo "Not a SuSE Linux system?"
fi
|
|
You see the first command is make install which runs the
install routine of the package itself. Then the documentation files
included in the sources are copied to
/usr/doc/packages/photopc.
|
![NOTE](gif/icon_note.gif) |
SuSE's convention is to install README files, license information, and
pretty much any other kind of documentation to the directory hierarchy
/usr/doc/packages. If you look into this directory,
you'll find a separate subdirectory for each installed package
containing these files. It's a good habit to follow this convention --
create a new directory with the package name and copy all interesting
files to it.
|
|
The last step in the install-section in this example is copying the
files we created to integrate the package into the SuSE setup scheme
to their desired locations. You see we do some simple checks to make
sure that the target system is in fact a SuSE Linux installation
before we copy the files.
|
35.5.6 | Scripts |
|
All tasks listed in the prep-, build-, and install-sections are
executed during the building of the actual package. As mentioned in
the overview section at the beginning of this chapter, we have the
ability to specify scripts to be executed when the package is
installed or erased too. RPM offers four possibilities to execute
command during the installation:
|
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
pre-install-script: %pre
Commands following the %pre keyword are executed before
the package is installed.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
post-install-script: %post
Commands following the %post keyword are executed after
the package is installed.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
pre-uninstall-script: %preun
Commands following the %preun keyword are executed before
the package is erased.
|
![*](gif/bullet.gif) ![](gif/clear.gif) |
post-uninstall-script: %postun
Commands following the %postun keyword are executed after
the package is erased.
|
|
|
Looking at this list, it becomes obvious that we need a
post-install-script to call the fillup utility to modify
/etc/rc.config when the package is installed:
|
| # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Post-Install-Script
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%post
if test -f /etc/rc.config -a -x /bin/fillup ; then
/bin/fillup /etc/rc.config /var/adm/fillup-templates/photopc.tmpl
echo "**"
echo "** Please run SuSEconfig to create the camera device"
echo "**"
else
echo "Not a SuSE Linux system?"
fi
|
|
The script does exactly what we have done manually when we assembled
the package contents. The only thing I added is a simple check that
verifies if the file /etc/rc.config and the
fillup utility are present.
We don't need any other script for our PhotoPC example. If you run
into a situation where it would be handy to have a pre-install or,
pre/post-uninstall script, just create one as shown here, but replace
%pre with the appropriate keyword from the list given
above.
|
35.5.7 | The File List |
|
Last but not least in the spec file is the list of all files contained
in the package. Only the files listed here will end up in the RPM
package, so be very careful that you don't miss anything when you
compile this list, or it'll be missing in the resulting package.
The file is also the place where you mark configuration and
documentation files. To mark a file as documentation, place the
keyword %doc in front of the file path and name. The
keyword %config is used to mark configuration files. The
list for the PhotoPC example looks like this:
|
| # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# File-List
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%files
# binaries
/usr/local/bin/photopc
/usr/local/bin/epinfo
# library
/usr/local/lib/libeph_io.a
# include file
/usr/local/include/eph_io.h
# man pages
%doc /usr/local/man/man1/photopc.1
%doc /usr/local/man/man1/epinfo.1
# docu
%doc /usr/doc/packages/photopc
# config files
%config /var/adm/fillup-templates/photopc.tmpl
%config /sbin/conf.d/SuSEconfig.photopc
|
|
|
![TIP](gif/icon_tip.gif) |
If you list a directory name, as was done for
/usr/doc/packages/photopc, then the whole file tree, starting
with this directory, will become part of the package. You can use this
feature to avoid listing hundreds of files separately if they all
part of the same hierarchy.
|
|
|
![CAUTION](gif/icon_caution.gif) |
But be sure not to include any file in the list that is
already part of another package. RPM will report a conflict at
installation time and refuse to install the package if there are
overlapping between packages.
|
|
|
35.5.8 | The finish line |
|
If you take the single section and put them in a file in the order
shown, then you have the spec file for our PhotoPC package. This was
the last piece and makes the example complete. We have the source
package, the patch-file, and finally the spec-file. That's all we need
to build the RPM and the SRPM packages. The actual build process works
exactly as discussed in chapter34 for source packages
coming from the SuSE CDs.
|
![TIP](gif/icon_tip.gif) |
To make your life easier, you can use the spec-file shown, or
any spec file from the SuSE SRPMs as a template for your own
package. It's always easier to modify a working example than to
create one from scratch.
|
|
The process of creating a spec file is usually done by multiple
passes of trial and error. Having a working version on the first try
is the exception. Usually it takes some time until you are satisfied
with the results and everything works as you intended.
|
35.6 | Build the RPM and SRPM packages |
|
To make the example complete, we'll build the package by calling
rpm -ba photopc.spec:
|
| # rpm -ba photopc.spec
Executing: %prep
+ umask 022
+ cd /usr/src/packages/BUILD
+ cd /usr/src/packages/BUILD
+ rm -rf photopc-3.01
+ /bin/gzip -dc /usr/src/packages/SOURCES/photopc-3.01.tar.gz
+ tar -xvvf -
drwxr-xr-x crosser/group 0 1999-04-28 01:45 photopc-3.01/
-rw-r--r-- crosser/group 2941 1999-04-28 01:44 photopc-3.01/a12scan.c
-rw-r--r-- crosser/group 1371 1999-04-28 01:44 photopc-3.01/a12scan.h
-rw-r--r-- crosser/group 16024 1999-04-28 01:44 photopc-3.01/comio.c
-rw-r--r-- crosser/group 1244 1999-04-28 01:44 photopc-3.01/comio.h
[... output skipped ...]
-rw-r--r-- crosser/group 12833 1999-04-28 01:44 photopc-3.01/usage.htm
-rw-r--r-- crosser/group 6825 1999-04-28 01:44 photopc-3.01/usleep.c
-rw-r--r-- crosser/group 947 1999-04-28 01:44 photopc-3.01/usleep.h
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd photopc-3.01
+ chown -R root .
+ chgrp -R root .
+ chmod -R a+rX,g-w,o-w .
+ echo 'Patch #0:'
Patch #0:
+ patch -p1 -s
+ ./configure --prefix=/usr/local
creating cache ./config.cache
checking for gcc... gcc
[... output skipped ...]
creating Makefile
creating config.h
+ exit 0
Executing: %build
+ umask 022
+ cd /usr/src/packages/BUILD
+ cd photopc-3.01
+ make
gcc -g -O -Wall -DHAVE_CONFIG_H -DUNIX -c eph_read.c
[... output skipped ...]
gcc -o epinfo epinfo.o a12scan.o exifscan.o fnames.o ctimez.o filetime.o
+ exit 0
Executing: %install
+ umask 022
+ cd /usr/src/packages/BUILD
+ cd photopc-3.01
+ make install
/usr/bin/ginstall -c -d -m 755 /usr/local/bin
[... output skipped ...]
/usr/bin/ginstall -c -m 644 epinfo.man /usr/local/man/man1/epinfo.1
+ mkdir -p /usr/doc/packages/photopc
+ cp README protocol.htm readme.dos /usr/doc/packages/photopc
+ test -d /sbin/conf.d
+ cp SuSE/SuSEconfig.photopc /sbin/conf.d
+ test -d /var/adm/fillup-templates
+ cp SuSE/photopc.tmpl /var/adm/fillup-templates
+ exit 0
Processing files: photopc
Finding provides...
Finding requires...
Provides: digicam-download
Prereqs: /bin/sh
Requires: ld-linux.so.2 libc.so.6
Wrote: /usr/src/packages/SRPMS/photopc-3.01-0.src.rpm
Wrote: /usr/src/packages/RPMS/i386/photopc-3.01-0.i386.rpm
|
|
Nothing new here. We discussed the build process in chapter 34.
The listing above shows how all the steps discussed there are
performed for the new software package. As a result we get two files,
the RPM and the SRPM package. You can use the RPM to install it on any
SuSE Linux system. It should even work on non-SuSE systems, because in
the spec file we made sure that we checked that the SuSE mechanisms we
used are actually present.
Save the SRPM, since you may need it when a new version of the
software is released.
|
![TIP](gif/icon_tip.gif) |
In this case you probably don't have to do anything but to change the
Source: and Version: tag of the spec-file to
build the new release. This is the greatest advantage for using patch
files. You don't have to make your changes over and over again. Simply
use the patch file to apply them to the new version.
|
|
|
![](gif/black.gif) |
Summary: |
|
In this chapter we used an example to see the steps needed to create a
RPM package for the SuSE Linux distribution. We broke down the build
process into single steps and performed these steps one by one until
we had the desired RPMs.
We started by manually manually through the build process and
carefully noted all modifications needed to adopt the software to the
SuSE Linux system. These modifications were collected in a patch file
which was used to automate the build process. We created a spec-file
to control this process and finally ended up with an RPM and a SRPM
package ready to install on any SuSE Linux system.
|
![](gif/black.gif) |