C++ CSS HTML Java JavaScript MySQL Oracle PERL PHP SQL Unix VBScript XHTML XML Сети
Building a Relocatable Package
 

Building a Relocatable Package

For this example, we'll use our tried-and-true cdplayer application. Let's start by reviewing the spec file for possible problems:
…
%files
%doc README
/usr/local/bin/cdp
/usr/local/bin/cdplay
%doc /usr/local/man/man1/cdp.1
%config /etc/cdp-config
        

Everything looks all right, except for the %files list. There are files in /usr/local/bin, a man page in /usr/local/man/man1, and a config file in /etc. A prefix of /usr/local would work pretty well, except for that cdp-config file.

For the sake of this first build, we'll declare the config file unnecessary and remove it from the %files list. We'll then add a prefix tag line, setting the prefix to /usr/local. After these changes are made, let's try a build:
# rpm -ba cdplayer-1.0.spec

…
Binary Packaging: cdplayer-1.0-1
Package Prefix = usr/local
File doesn't match prefix (usr/local): /usr/doc/cdplayer-1.0-1
File not found: /usr/doc/cdplayer-1.0-1
Build failed.
# 
        

The build proceeded normally up to the point of actually creating the binary package. The Package Prefix = usr/local line confirms that RPM picked up our prefix tag line. But the build stopped — and on a file called /usr/doc/cdplayer-1.0-1. But that file isn't even in the %files list. What's going on?

Take a closer look at the %files list. See the line that reads %doc README? In the section called The %doc Directive in Chapter 13, we discussed how the %doc directive creates a directory under /usr/doc. That's the file that killed the build — the directory created by the %doc directive.

Let's temporarily remove that line from the %files list and try again:
# rpm -ba cdplayer-1.0.spec

…
Binary Packaging: cdplayer-1.0-1
Package Prefix = usr/local
Finding dependencies...
Requires (2): libc.so.5 libncurses.so.2.0
bin/cdp
bin/cdplay
man/man1/cdp.1
90 blocks
Generating signature: 0
Wrote: /usr/src/redhat/RPMS/i386/cdplayer-1.0-1.i386.rpm
+ umask 022
+ echo Executing: %clean
Executing: %clean
+ cd /usr/src/redhat/BUILD
+ cd cdplayer-1.0
+ exit 0
Source Packaging: cdplayer-1.0-1
cdplayer-1.0.spec
cdplayer-1.0.tgz
82 blocks
Generating signature: 0
Wrote: /usr/src/redhat/SRPMS/cdplayer-1.0-1.src.rpm
# 
        

The build completed normally. Note how the files to be placed in the binary package file are listed, minus the prefix of /usr/local. Some of you might be wondering why the cdp.1 file didn't cause problems. After all, it had a %doc/usr/local, there was no problem. A more complete discussion of the %doc directive can be found in the section called The %doc Directive in Chapter 13.

Tying Up the Loose Ends

In the course of building this package, we ran into two hitches:

  1. The config file cdp-config couldn't be installed in /etc.

  2. The README file could not be packaged using the %doc directive.

Both of these issues are due to the fact that the files' paths do not start with the default prefix path /usr/local if we chose a prefix of /usr instead of /usr/local, the README file could be packaged using the %doc directive, since the default documentation directory is /usr/doc. Another approach would be to use the %docdir directive to define another documentation-holding directory somewhere along the prefix path. [1]

This approach wouldn't work for /etc/cdp-config under /usr/local) and using the %post post-install script to move the file to /etc. Pointing a symlink at the config file is another possibility.

Of course, this approach has some problems. First, you'll need to write a %postun script to undo what the %post script does. [2] A %verifyscript reduces the utility of RPM's -c and -d options when issuing queries. Finally, if you actually move files around using the %post to erase them. If you have to resort to these kinds of tricks, it's probably best to forget trying to make the package relocatable.

Test-Driving a Relocatable Package

Looks like cdplayer

First, let's see if the binary package file's prefix has been recorded properly. We can do this by using the --queryformat option to RPM's query mode:
# rpm -qp --queryformat '%{DEFAULTPREFIX}\n' cdplayer-1.0-1.i386.rpm
/usr/local
#
          

The DEFAULTPREFIX tag directs RPM to display the prefix used during the build. As we can see, it's /usr/local, just as we intended. The --queryformat option is discussed in the section called --queryformat — Construct a Custom Query Response in Chapter 5.

So it looks like we have a relocatable package. Let's try a couple of installs and see if we really can install it in different locations. First, let's try a regular install with no prefix specified:
# rpm -Uvh cdplayer-1.0-1.i386.rpm
cdplayer    ##################################################
#
          

That seemed to work well enough. Let's see if the files went where we intended:
# ls -al /usr/local/bin
total 558
-rwxr-xr-x   1 root     root        40739 Oct  7 13:23 cdp*
lrwxrwxrwx   1 root     root           18 Oct  7 13:40 cdplay -> /usr/local/bin/cdp*
…
# ls -al /usr/local/man/man1
total 9
-rwxr-xr-x   1 root     root         4550 Oct  7 13:23 cdp.1*
…
#
          

Looks good. Let's erase the package and reinstall it with a different prefix:
# rpm -e cdplayer
# rpm -Uvh --prefix /usr/foonly/blather cdplayer-1.0-1.i386.rpm
cdplayer    ##################################################
#
          

(We should mention that directories foonly and blather didn't exist prior to installing cdplayer.)

RPM has another tag that can be used with the --queryformat option. It's called INSTALLPREFIX and using it displays the prefix under which a package was installed. Let's give it a try:
# rpm -q --queryformat '%{INSTALLPREFIX}\n' cdplayer
/usr/foonly/blather
#
          

As we can see, it displays the prefix we entered on the command line. Let's see if the files were installed as we directed:
# cd /usr/foonly/blather/
# ls -al
total 2
drwxr-xr-x   2 root     root         1024 Oct  7 13:45 bin/
drwxr-xr-x   3 root     root         1024 Oct  7 13:45 man/
#
          

So far, so good — the proper directories are there. Let's look at the man page first:
# cd /usr/foonly/blather/man/man1/
# ls -al
total 5
-rwxr-xr-x   1 root     root         4550 Oct  7 13:23 cdp.1*
#
          

That looks ok. Now on to the files in bin:
# cd /usr/foonly/blather/bin
# ls -al
total 41
-rwxr-xr-x   1 root     root        40739 Oct  7 13:23 cdp*
lrwxrwxrwx   1 root     root           18 Oct  7 13:45 cdplay -> /usr/local/bin/cdp
#
          

Uh-oh. That cdplay symlink isn't right. What happened? If we look at cdplayer's makefile, we see the answer:
install: cdp cdp.1.Z
…
ln -s /usr/local/bin/cdp /usr/local/bin/cdplay
          

Ah, when the software is installed during RPM's build process, the make file sets up the symbolic link. Looking back at the %files list, we see cdplay software.

Fortunately, this problem isn't that difficult to fix. All we need to do is change the line in the makefile that creates the symlink from:
ln -s /usr/local/bin/cdp /usr/local/bin/cdplay
          

To:
ln -s ./cdp /usr/local/bin/cdplay
          

Now cdplay will always point to cdp, no matter where it's installed. When building relocatable packages, relative symlinks are your friend!

After rebuilding the package, let's see if our modifications have the desired effect. First, a normal install with the default prefix:
# rpm -Uvh cdplayer-1.0-1.i386.rpm
cdplayer    ##################################################
# cd /usr/local/bin/
# ls -al cdplay
lrwxrwxrwx   1 root     root           18 Oct  8 22:32 cdplay -> ./cdp*
# 
          

Next, we'll try a second install using the --prefix option (after we first delete the original package):
# rpm -e cdplayer
# rpm -Uvh --prefix /a/dumb/prefix cdplayer-1.0-1.i386.rpm
cdplayer    ##################################################
# cd /a/dumb/prefix/bin/
# ls -al cdplay
lrwxrwxrwx   1 root     root           30 Oct  8 22:34 cdplay -> ./cdp*
#
          

the actual modifications are straightforward.

In the next chapter, we'll cover how packages can be built in non-standard directories, as well as how non-root users can build packages.

Notes

[1]

For more information on the %docdir directive, please see the section called The %docdir Directive in Chapter 13.

[2]

Install and erase-time scripts have an environment variable, RPM_INSTALL_PREFIX, that can be used to write scripts that are able to act appropriately if the package is relocated. See the section called Install/Erase-time Scripts in Chapter 13 for more information.

Главная