Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Packaging software with RPM, Part 3: Accommodating software dependencies

Martin Streicher, Software Developer, Pixel, Byte, and Comma
author photo - martin streicher
Martin Streicher is a freelance Ruby on Rails developer and the former Editor-in-Chief of Linux Magazine. Martin holds a Master of Science degree in computer science from Purdue University, and has programmed UNIX-like systems since 1986. He collects art and toys.

Summary:  In this third article in a three-part series on the RPM Package Manager, discover the ins and outs of software dependencies, and learn how to control and customize your software packaging. (This series replaces an earlier series on RPM written by Dan Poirier.)

Share your expertise:  What are your favorite RPM tricks? Add your comments below.

View more content in this series

Date:  12 Jan 2010
Level:  Introductory PDF:  A4 and Letter (37KB | 9 pages)Get Adobe® Reader®
Also available in:   Japanese  Portuguese  Spanish

Activity:  32686 views
Comments:  

In the early days of computing, each piece of software was monolithic. Excluding the ROM used to boot a machine and the operating system itself, each application provided all the libraries and code required to run. This approach was appropriate, largely because the computers of the day could not multitask. Later, however, computers advanced by leaps and bounds to support both multiple simultaneous users (time sharing) and multiple simultaneous applications. With many users running the same application and sharing system resources such as the file system and RAM, sharing code became a necessity and an optimization.

Today, nearly every operating system separates library code from application code and marries the two at run time. But a shared library—the name for shareable code—has pros and cons. In the plus column, each application is smaller, because each need not be monolithic. Further, a bug fix or performance enhancement in a commonly used shared library benefits all applications. However, the separation of application and library code is something of a handcuff: The shared library must be available and compatible, or the application cannot run.

The tie between an application and a library is one kind of dependency. If you distribute source code and require a particular set of header files to compile the code, that too is a dependency. Your code may also require a specific tool, such as Bison or Yacc, to compile. If you distribute your software in an RPM, you must verify that the target system provides all dependencies before you install your code. After all, if a system isn't suitable, there's little reason to install the application.

Part 1 of this series demonstrated how to distribute your software via RPM. Part 2 described the installation and uninstallation process in detail and explained how to install components when a complementary package is installed at some later time. This article, the last in the series, explores another important topic—software dependencies—and discusses additional capabilities to control and customize your software packaging.

Defining dependencies

When you create an RPM package, you can declare four types of dependencies:

  • If your package requires a capability provided by another, define a requirement.
  • If other packages depend on or could eventually depend on a capability in your software, declare the capability your package provides.
  • If your software (or part of your software) cannot coexist simultaneously with another package, specify a conflict.
  • If your package deprecates another package or an older version of your own software, define what has become obsolete. If your package changes name, you should list the old name as obsolete.

Each dependency is listed separately in the RPM spec file. The syntax is Type: Capability, where Type is one of the four somewhat eponymous tags (Requires, Provides, Conflicts, or Obsoletes) and Capability is the name of an optional version number. If you have more than one Capability to list, enumerate all on the same line, delimited by a space or a comma.

For example, if your application required Perl to execute, you would specify that as follows:

Requires: perl

If your application required Perl and MySQL, you can write:

Requires: perl, mysql 

Oftentimes, an application depends on a specific version or a specific major release of a package. For example, if you write Ruby code compliant with version 1.9, you depend on that version of the interpreter. To express a version dependency, add the version number to the Capability:

Requires: ruby >= 1.9

You can specify version numbers for any of the four types of dependencies. The syntax is identical. For instance, if your application was incompatible with versions of the Bash shell newer than version 2.0, you would write:

Conflicts: bash > 2.0

There are six comparators for version number:

  • package < revision requires that the named package has a version number less than revision.
  • package > revision specifies a package newer than revision.
  • package >= revision asks for a package greater than or equal to revision.
  • package <= revision requires a package less than or equal to revision.
  • package = revision mandates a specific revision.
  • package asks for any revision of the named package.

In general, the information for Requires and Provides is generated automatically based on RPM's analysis of your code and your spec file, respectively. (You can approximate what RPM computes for Requires using the ldd utility.) However, you can amend those two lists, if needed. Conflicts and Obsoletes are typically provided by the software developer.


Signing your RPM

Many developers choose RPM because it's easy to use and widely supported. However, simplicity also makes it easy for a bad actor to install the RPM, modify its contents, and repackage and redistribute the software as authentic. Mirror sites and torrents only hasten such "bootlegging." To protect yourself and those who choose to use your software, sign your RPM with a unique signature to guarantee its authenticity. Signing precludes modification: Any change in the file alters the signature, revealing a counterfeit.

There are three ways to sign your package. You can sign the package when it is built. You can re-sign a package that's already been signed. And you can sign an existing RPM that has no signature. The latter two options build on the technique of the former, so let's focus on signing an RPM when it's built.

To begin, you must have a GPG private key-public key pair. If you lack one, such a key is simple to generate. The first step is to launch gpg-agent, which manages secret keys. (Systems typically run a single gpg-agent for all users. Check with your system administrator to determine whether this step is required. If the systems already runs the agent, ask how to connect to it.)

$ gpg-agent --daemon --enable-ssh-support \
  --write-env-file "${HOME}/.gpg-agent-info"

gpg-agent creates the file .gpg-agent-info in your home directory. The file contains shell environment settings required to connect to the running agent. Load the information with the following command. (Type the entire command at the prompt or, for convenience, add it to your shell startup file.)

$ if [ -f "${HOME}/.gpg-agent-info" ]; then
  . "${HOME}/.gpg-agent-info"
  export GPG_AGENT_INFO
  export SSH_AUTH_SOCK
  export SSH_AGENT_PID
fi

Finally, set an additional variable to point to the terminal device you are currently using. (Again, you can add these two lines to a shell startup file to be available to every interactive session.)

$ GPG_TTY=$(tty)
$ export GPG_TTY

You are now ready to generate a key. Run the command gpg --gen-key, and answer the prompts. An example key-generation session is shown in Listing 1. Data entry is shown in bold.


Listing 1. Example key-generation session
	
$ gpg --gen-key
gpg (GnuPG) 1.4.9; Copyright (C) 2008 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) DSA and Elgamal (default)
   (2) DSA (sign only)
   (5) RSA (sign only)
Your selection? 1
DSA keypair will have 1024 bits.
ELG-E keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 1024
Requested keysize is 1024 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)  0
Key does not expire at all
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Martin Streicher
Email address: martin.streicher@example.com
Comment: Example key for RPM
You selected this USER-ID:
    "Martin Streicher (Example key for RPM) <martin.streicher@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

Enter passphrase: ******
Retype passphrase: ******

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
+++++++++++++++++++.+++++.++++++++++++++++++++.+++++>.+++++.+++++..>+++++.+++++

The first prompt chooses the type of key (the default is the preferred option). The next prompt sets the size of the key in bits. Here, the more bits, the better, although longer keys take additional time to generate. If you'd like, you can set an expiry on the key at the next prompt. The next three queries ask for information to identify this key. It is customary to provide your name and e-mail address to allow users to contact you for your public key. Finally, you are prompted twice for a passphrase to add an additional layer of security. No one can sign an RPM with your key without the proper passphrase. Depending on how busy your system is, key generation can take seconds or minutes.

Upon completion, the key generator creates a new directory named $HOME/.gnupg and populates it with files that represent your private and public keys. To see the keys you have available, run gpg --list-key. Take note of the value of uid: It contains the name of the key you should use to sign your RPM.

$ gpg --list-key
/home/strike/.gnupg/pubring.gpg
-------------------------------
pub   1024D/1811A3E4 2009-11-23
uid                  Martin Streicher (Example key for RPM) <martin.streicher@example.com>
sub   1024g/15BBCF06 2009-11-23	

To continue, you must now set options for RPM to sign the package. Create or open the file $HOME/.rpmmacros, and add three lines:

%_signature gpg
%_gpg_path /home/strike/.gnupg
%_gpg_name Martin Streicher (Example key for RPM) <martin.streicher@example.com>

The %_signature line selects the type of signature. Here, it's set to gpg. The %_gpg_name specifies the ID of the key to sign with. During key generation, the name was set to Martin Streicher (Example key for RPM) <martin.streicher@example.com> (the user ID [UID] value above), so that is repeated here. Finally, %_gpg_path defines the path to your keys.

With keys and configuration in place, signing an RPM requires one additional option, --sign.

$ rpmbuild -v --sign -bb --clean SPECS/wget.spec
Enter pass phrase: 
Pass phrase is good.
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.46786
+ umask 022
...

The rpmbuild command shown is the same one used in Part 1—the only addition is --sign. When prompted for your password, enter the same passphrase you provided during key generation. The RPM build continues and signs the resulting package.

You can verify your signature to ensure that your package is pristine. To verify the signature of an RPM, run rpm -K on the file itself:

$ rpm -K wget-1.12-1.i386.rpm
wget-1.12-1.i386.rpm: (SHA1) DSA sha1 md5 (GPG) OK

If the command reads OK, the file is legitimate. If you download another developer's RPM, consider verification before you install the package.


Additional tools for RPM development

If you use RPM frequently for packaging, spec files become second nature. Nonetheless, a wide variety of tools is available to make spec file authoring easier. Here's a sample (see Resources for links to each):

  • rpmlint validates RPM files. The tool catches a good number of mistakes—installing a binary in /etc and a configuration file in /usr are two common pitfalls rpmlint can detect—and you can extend it with custom modules. rpmlint is written in Python and requires a handful of libraries to perform its functions.
  • Easy RPM Builder is a K Desktop Environment (KDE)-based tool for assembling packages. The tool provides a number of templates to help jump-start your RPM development and provides a graphical user interface (GUI) to portions of the spec file. Easy RPM Builder does not replace rpmbuild, and some familiarity with RPM is required to use it effectively.
  • If you don't use KDE or prefer to work with the spec file directly, you can extend both Vim and Emacs to include a special spec mode, which highlights spec file syntax and directs the creation and maintenance of a spec file.
  • Although not a tool per se, the Fedora Project's RPM Guidelines page provides a vast list of best practices. Indeed, if you intend to distribute your software on Fedora, pay particular attention to the requirements for new packages. In addition, the guidelines describe how to package applications based on a number of popular platforms, including Eclipse, Perl, and Ruby. Packaging software for a particular interpreter is especially involved, because packaged software can include scripts, binaries, and source that must be rebuilt during installation directly on the target machine. For example, a Perl module may be part Perl and part C code. You can also find a version of the official RPM software guide on the Fedora site (see Resources below for a link) .

Additional tools help install and manage RPMs. In general, these tools are intended for systems administrators, but you may find them useful to help validate your installations and manage the software of you own development system. If you use your own development system for testing, you may find the tools helpful to purge defunct packages.


Conclusion

RPM is actively maintained. You can keep track of the efforts at the project's new home page (see Resources). RPM tools exist for most Linux distributions, including Debian. The latest version of RPM is 5.2.0, which was released in July 2009. The goals of the RPM project remain the same: "Make it easy to get packages on and off the system. Make it easy to verify a package was installed correctly. Make it easy for the package builder. Make it start with the original source code. Make it work on different computer architectures."

RPM development can be complex, because installing software is equally complex. This series touched on but a few topics. You can find a great deal of information about RPM development on the Web. There are tutorials, forums, and even an IRC channel dedicated to the topic (visit #rpm.org on Freenode). Moreover, you can find hundreds if not thousands of other RPMs online. If you face an especially knotty problem, find another RPM package with similarities and probe its spec file to deduce a solution.

If you're a software developer or a system administrator, providing your application as a package makes installations, upgrades, and maintenance much easier. Again, if you build it and package it with RPM, they will come.


Resources

Learn

Get products and technologies

Discuss

  • Get involved in the My developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

About the author

author photo - martin streicher

Martin Streicher is a freelance Ruby on Rails developer and the former Editor-in-Chief of Linux Magazine. Martin holds a Master of Science degree in computer science from Purdue University, and has programmed UNIX-like systems since 1986. He collects art and toys.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=461497
ArticleTitle=Packaging software with RPM, Part 3: Accommodating software dependencies
publish-date=01122010
author1-email=martin.streicher@gmail.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers