Библиотека сайта rus-linux.net
Chapter 12. rpm -b Command Reference
Table 12-1. rpm -b Command Syntax
rpm -b — What Does it Do?
When RPM is invoked with the -b option, the process of building a package is started. The rest of the command will determine exactly what is to be built and how far the build should proceed. In this chapter, we'll explore every aspect of rpm -b.
An RPM build command must have two additional pieces of information, over and above "rpm -b":
The names of one or more spec files representing software to be packaged.
The desired stage at which the build is to stop.
As we discussed in Chapter 10, the spec file is one of the inputs to RPM's build process. It contains the information necessary for RPM to perform the build and package the software.
There are a number of stages that RPM goes through during a build. By specifying that the build process is to stop at a certain stage, the package builder can monitor the build's progress, make any changes necessary, and restart the build. Let's start by looking at the various stages that can be specified in a build command.
rpm -bp — Execute %prep
The command rpm -bp directs RPM to execute the very first step in the build process. In the spec file, this step is labeled %prep. Every command in the %prep section will be executed when the -bp option is used.
|
|
First, RPM confirms that the cdplayer
package is
the subject of this build. Then it sets the umask and starts
executing the %prep section. At this point, the
%setup macro is doing its thing. It changes
directory into the build area and removes any old copies of
cdplayer
's build tree.
Next, %setup unzips the sources and uses tar to create the build tree. We've removed the complete listing of files, but be prepared to see lots of output if the software being packaged is large.
cdplayer
's build tree and changes ownership and
file permissions appropriately. The exit
0
signifies the end of the %prep
section, and therefore, the end of the %setup
macro. Since we used the -bp option, RPM stopped
at this point. Let's see what RPM left in the build area:
|
cdplayer-1.0
, we find the sources are ready to be
built:
|
We can see that %setup's chown and chmod commands did what they were supposed to — the files are owned by root, with permissions set appropriately.
If not stopped by the -bp option, the next step in RPM's build process would be to build the software. RPM can also be stopped at the end of the %build section in the spec file. This is done by using the -bc option:
rpm -bc — Execute %prep, %build
|
|
We see that prior to the make command, RPM changes
directory into cdplayer
's top-level directory.
RPM then starts the make, which ends with the
groff command. At this point, the execution of the
%build section has been completed. Since the
-bc option was used, RPM stops at this point.
The next step in the build process would be to install the newly built software. This is done in the %install section of the spec file. RPM can be stopped after the install has taken place by using the -bi option:
rpm -bi — Execute %prep, %build, %install
|
|
After the %prep and %build
sections, the %install section is executed.
Looking at the output, we see that RPM changes directory into
cdplayer
's top-level directory and issues the
make install command, the sole command in the
%install section. The output from that point until
the first exit 0
, is from
make install.
|
The line responsible is %doc README. The
%doc tag identifies the file as being
documentation. RPM handles documentation files by creating a
directory in /usr/doc
and placing all
documentation in it. The exit 0
at
the end signifies the end of the %install section.
RPM stops due to the -bi option.
The next step at which RPM's build process can be stopped is after the software's binary package file has been created. This is done using the -bb option:
rpm -bb — Execute %prep, %build, %install, package (bin)
|
After executing the %prep, %build, and %install sections, and handling any special documentation files, RPM then creates a binary package file. In the sample output, we see that first RPM performs automatic dependency checking. It does this by determining which shared libraries are required by the executable programs contained in the package. Next, RPM actually archives the files to be packaged, optionally signs the package file, and outputs the finished product.
The last part of RPM's output looks suspiciously like a section in the spec file being executed. In our example, there is no %clean section. If there were, however, RPM would have executed any commands in the section. In the absence of a %clean section, RPM simply issues the usual cd commands and exits normally.
rpm -ba — Execute %prep, %build, %install, package (bin, src)
The -ba option directs RPM to perform all the stages in building a package. With this one command, RPM:
Unpacks the original sources.
Applies patches (if desired).
Builds the software.
Installs the software.
Creates the binary package file.
Creates the source package file.
|
As in previous examples, RPM executes the %prep, %build, and %install sections, handles any special documentation files, creates a binary package file, and cleans up after itself.
The final step in the build process is to create a source package
file. As the output shows, it consists of the spec file and the
original sources. A source package may optionally include one or more
patch files, although in our example, cdplayer
requires none.
At the end of a build using the -ba option, the software has been successfully built and packaged in both binary and source form. But there are a few more build-time options that we can use. One of them is the -bl option:
rpm -bl — Check %files list
There's one last letter that may be specified with rpm -b, but unlike the others, which indicate the stage at which the build process is to stop, this option performs a variety of checks on the %files list in the named spec file. When l is added to rpm -b, the following checks are performed:
Expands the spec file's %files list and checks that each file listed actually exists.
Determines what shared libraries the software requires by examining every executable file listed.
Determines what shared libraries are provided by the package.
Why is it necessary to do all this checking? When would it be useful? Keep in mind that the %files list must be generated manually. By using the -bl option, the following steps are all that's necessary to create a %files list:
Writing the %files list.
Using the -bl option to check the %files list.
Making any necessary changes to the %files list.
It may take more than one iteration through these steps, but eventually the list check will pass. Using the -bl option to check the %files list is certainly better than starting a two-hour package build, only to find out at the very end that the list contains a misspelled filename.
|
|
Looking at this more verbose output, it's easy to see there's a great
deal going on. Some of it is not directly pertinent to checking the
%files list, however. For example, the output
extending from the first line, to the line reading *
Package: cdplayer
, reflects processing that takes
place during actual package building, and can be ignored.
Following that section is the actual %files list
check. In this section, every file named in the
%files list is checked to make sure it exists. The
phrase, ADDING:
, again reflects RPM's
package building roots. When using the -bl option,
however, RPM is simply making sure the files exist on the build
system. If the --timecheck option (described a bit
later, on the section called --timecheck <secs>
— Print a warning if files to be packaged are over
<secs>
old) is
present, the checks required by that option are performed here, as
well.
After the list check, the MD5 checksums of each file are calculated and displayed. While this information is vital during actual package building, it is not used when using the -bl option.
Finally, RPM determines which shared libraries the listed files
require. In this case, there are only two —
libc.so.5
, and
libncurses.so.2.0
. While not strictly a part of
the list-checking process, displaying shared library dependencies can
be quite helpful at this point. It can point out possible problems,
such as assuming that the target systems have a certain library
installed when, in fact, they do not.
|
/usr/bin/bogus
. In
this example we made the name obviously wrong, but in a more
real-world setting, the name will more likely be a misspelling in the
%files list. OK, let's correct the
%files list and try again:
|
|
Done! The moral to this story is that using rpm -bl and fixing the error it flagged doesn't necessarily mean your %files list is ready for prime-time: Always run it again to make sure!
--short-circuit — Force build to start at particular stage
Although it sounds dangerous, the --short-circuit option can be your friend. This option is used during the initial development of a package. Earlier in the chapter, we explored stopping RPM's build process at different stages. Using --short-circuit, we can start the build process at different stages.
One time that --short-circuit comes in handy is when you're trying to get software to build properly. Just think what it would be like — you're hacking away at the sources, trying a build, getting an error, and hacking some more to fix that error. Without --short-circuit, you'd have to:
Make your change to the sources.
Use tar to create a new source archive.
Start a build with something like rpm -bc.
See another bug.
Go back to step 1.
Pretty cumbersome! Since RPM's build process is designed to start with the sources in their original tar file, unless your modifications end up in that tar file, they won't be used in the next build. [1]
But there's another way. Just follow these steps:
Place the original source tar file in RPM's
SOURCES
directory.Create a partial spec file in RPM's
SPECS
directory (Be sure to include a valid Source line).Issue an rpm -bp to properly create the build environment.
|
Normally, the -bc option instructs RPM to stop the build after the %build section of the spec file has been executed. By adding --short-circuit, however, RPM starts the build by executing the %build section and stops when everything in %build has been executed.
There is only one other build stage that can be --short-circuit'ed, and that is the install stage. The reason for this restriction is to make it difficult to bypass RPM's use of pristine sources. If it were possible to --short-circuit to -bb or -ba, a package builder might take the "easy" way out and simply hack at the build tree until the software built successfully, then package the hacked sources. So, RPM will only --short-circuit to -bc or -bi. Nothing else will do.
What exactly does an rpm -bi --short-circuit do, anyway? Like an rpm -bc --short-circuit, it starts executing at the named stage, which in this case is %install. Note that the build environment must be ready to perform an install before attempting to --short-circuit to the %install stage. If the software installs via make install, make will automatically compile the software anyway.
|
RPM blindly started executing the %install stage,
but came to an abrupt halt when it attempted to change directory into
cdplayer-1.0
, which didn't exist. After giving a
descriptive error message, RPM exited with a failure status. Except
for some minor differences, rpm -bc would have
failed in the same way.
--buildarch <arch>
— Perform Build For the
<arch>
Architecture
|
i486
architecture, due to the inclusion of
the --buildarch option on the command line. We can
also see that RPM wrote the binary package in the
architecture-specific directory,
/usr/src/redhat/RPMS/i486
. Using RPM's
--queryformat option confirms the package's
architecture:
|
For more information on build packages for multiple architectures, please see Chapter 19.
--buildos <os>
— Perform Build For the
<os>
Operating
System
|
|
The package was indeed built for the specified operating system. For more information on building packages for multiple operating systems, please see Chapter 19.
--sign — Add a Digital Signature to the Package
|
The most obvious effect of adding the --sign option
to a build command is that RPM then asks for your private key's
passphrase. After entering the passphrase (which isn't echoed), the
build proceeds as usual. The only other difference between this and a
non-signed build is that the Generating
signature:
lines have a non-zero value.
|
The fact that there is a pgp in --checksig's output indicates that the packages have been signed.
For more information on signing packages, please see Chapter 17. Also, Appendix G contains information on obtaining and installing PGP.
--test — Create, Save Build Scripts For Review
|
Unlike a normal build, there's not much output. But the --test option has caused a set of scripts to be written and saved for you. The question is: Where are they?
rpmrc
file, the
scripts will be written to the directory specified by the
rpmrc
entry tmppath. If you
haven't changed this setting, RPM, by default, writes the scripts in
/var/tmp
. Here they are:
|
|
As we can see, this script contains the %prep section from the spec file. The script starts off by defining a number of environment variables and then leads into the %prep section. In the spec file used in this build, the %prep section consists of a single %setup macro. In this file, we can see exactly how RPM expands that macro. The remaining files follow the same basic layout — a section defining environment variables, followed by the commands to be executed.
|
only one script file, containing the %prep commands, would be written. In any case, no matter what RPM build command is used, the --test option can let you see exactly what is going to happen during a build.
--clean — Clean up after build
|
In this example, we see a typical %prep section
being executed. The line "+ echo Executing:
sweep
" indicates the start of
--clean's activity. After changing directory into
the build directory, RPM then issues a recursive delete on the
package's top-level directory.
As we noted above, this particular example doesn't make much sense. We're only executing the %prep section, which creates the package's build tree, and using --clean, which removes it! Using --clean with the -bc option isn't very productive either, as the newly built software remains in the build tree. Once again, there would be no remnants left after --clean has done its thing.
Normally, the --clean option is used once the software builds and can be packaged successfully. It is particularly useful when more than one package is to be built, since --clean ensures that the filesystem holding the build area will not fill up with build trees from each package.
Note also that the --clean option only removes the files that reside in the software's build tree. If there are any files that the build creates outside of this hierarchy, it will be necessary to write a script for the spec file's %clean section.
--buildroot <path>
— Execute %install using
<path>
as the root
The --buildroot option can make two difficult situations much easier:
Performing a build without impacting the build system.
Allowing non-root users to build packages.
Let's study the first situation in a bit more detail. Say, for
example, that sendmail
is to be packaged.
In the course of creating a sendmail
package, the software must be installed. This would mean that
critical sendmail
files, such as
sendmail.cf
and aliases
,
would be overwritten. Mail handling on the build system would almost
certainly be disrupted.
In the second case, it's certainly possible to set permissions such that non-root users can install software, but highly unlikely that any system administrator worth their salt would do so. What can be done to make these situations more tenable?
The --buildroot option is used to instruct RPM to
use a directory other than /
as a "build root".
This phrase is a bit misleading, in that the build root is
not the root directory under which the software
is built. Rather, it is the root directory for the install phase of
the build. When a build root is not specified, the software being
packaged is installed relative to the build system's root directory
"/
".
|
|
As the somewhat edited output shows, the %prep,
%build, and %install sections
are executed in RPM's normal build directory. However, the
--buildroot option comes into play when the
make install is done. As we can see, the
ROOT
variable is set to
/tmp/foonly
, which was the value following
--buildroot on the command line. From that point
on, we can see that make substituted the new build
root value during the install phase.
The build root is also used when documentation files are installed.
The documentation directory cdplayer-1.0-1
is
created in /tmp/foonly/usr/doc
, and the
README
file is placed in it.
The only remaining difference that results from using
--buildroot, is that the files to be included in
the binary package are not located relative to the build system's root
directory. Instead they are located relative to the build root
/tmp/foonly
. The resulting binary and source
package files are functionally equivalent to packages built without
the use of --buildroot.
Using --buildroot Can Bite You!
Although the --buildroot option can solve some problems, using a build root can actually be dangerous. How? Consider the following situation:
A spec file is configured to have a build root of
/tmp/blather
, for instance.In the %prep section [2] , there is an rm -rf $RPM_BUILD_ROOT command to clean out any old installed software.
You decide to build the software so that it installs relative to your system's root directory, so you enter the following command: "rpm -ba --buildroot / foo.spec".
The end result? Since specifying "/
" as the
build root sets $RPM_BUILD_ROOT
to
"/
", that innocuous little rm -rf
$RPM_BUILD_ROOT
turns into rm -rf
/! A recursive delete, starting at your system's root
directory, might not be a total disaster if you catch it quickly,
but in either case, you'll be testing your ability to restore from
backup… Er, you do have backups, don't
you?
The moral of this story is to be very careful
when using --buildroot. A good rule of thumb is
to always specify a unique build root. For example, instead of
specifying /tmp
as a build root (and possibly
losing your system's directory for holding temporary files), use the
path /tmp/mypackage
, where the directory
mypackage
is used only by the package you're
building.
--timecheck <secs>
— Print a warning if files to be packaged are over
<secs>
old
While it's possible to detect many errors in the %files list using rpm -bl, there is another type of problem that can't be detected. Consider the following scenario:
A package you're building creates the file
/usr/bin/foo
.Because of a problem with the package's makefile,
foo
is never copied into/usr/bin
.An older, incompatible version of
foo
, created several months ago, already exists in/usr/bin
.RPM creates the binary package file.
Is the incompatible /usr/bin/foo
included in the
package? You bet it is! If only there was some way for RPM to catch
this type of problem…
|
/usr/doc/cdplayer-1.0-1/README
is more than 3,600
seconds, or one hour, old. If we take a look at the file, we find
that it is:
[3]
|
In this particular case, the warning from
--timecheck is no cause for alarm. Since the
README
file was simply copied from the original
source, which was created November 10th, 1995, its date is unchanged.
If the file had been an executable or a library that was supposedly
built recently, --timecheck's warning should be
taken more seriously.
rpmrc
file:
|
This value can still be overridden by a value on the command line, if
desired. For more information on the use of
rpmrc
files, see Appendix B.
-vv — Display debugging information
|
Most of the output generated by the -vv option is
preceded by a D:
. In this example,
the additional output represents RPM's internal processing during the
start of the build process. Using the -vv option
with other build commands will produce different output.
--quiet — Produce as Little Output as Possible
|
This is the entire output from a package build of
cdplayer
. Note that warning messages (actually,
anything sent to stdout) are still printed.
--rcfile <rcfile>
— Set alternate rpmrc
file to
<rcfile>
The --rcfile option is used to specify a file
containing default settings for RPM. Normally, this option is not
needed. By default, RPM uses /etc/rpmrc
and a
file named .rpmrc
located in your login
directory.
This option would be used if there was a need to switch between
several sets of RPM defaults. Software developers and package
builders will normally be the only people using the
--rcfile option. For more information on
rpmrc
files, see Appendix B.
Notes
[1] | As we mentioned in Chapter 10, if the original sources need to be modified, the modifications should be kept as a separate set of patches. However, during development, it makes more sense to not generate patches every time a change to the original source is made. |
[2] | Or the %clean section, it doesn't matter — the end result is the same. |
[3] | It should be noted that the package was built substantially later than November of 1995! |