Development/Howto/RPM Advanced

From Mandriva Community Wiki

Jump to: navigation, search
RPM HOWTO, advanced section

Contents


This document covers several advanced topics not necessary to build your first RPM package. You should be familiar with the RPM package building basics before proceeding.

[edit] Menu system

The menu system is detailed on Menu System, while the new (as of Mandriva Linux 2007) XDG menu system is detailed here.

[edit] Naming a package

The basic rule is:

  • Only lowercase, words separated with '-'

e.g.: sound-wrapper (not soundwrapper or SoundWrapper)

[edit] Special cases

Mixed case can be accepted in some cases, when there is already a policy for a class of packages, for example perl packages, as the name reflects the CPAN module name.

When the name refers to an acronym, such as unixODBC. However, beginning the package name with a lower case letter should always be considered as a plus.

[edit] Mandriva tools

For Mandriva tools, use the 'drak' prefix.

e.g.: drakconf, drakpxelinux, drakstats

Some exceptions exist, such as rpmdrake, or harddrake, but mostly for historical reasons.

[edit] Renaming a package

Rpm renaming is not a perfect operation, due to cvs limitations. If you decide to rename an rpm, you will need to keep compatibility with the old for some releases (2 or 3 should be enough).

[edit] Changing a sub rpm name

This is the easiest thing to do. All you have to do is to rename the sub package, and then to add :

Provides:  oldname
Obsoletes: oldname

and everything should work. The old binary rpm should be removed by the upload script and everything will be fine.

[edit] Changing an rpm's (and srpm's) name

This one is a little less smooth, since you will loose cvs history. First, install the package, rename the spec file, and change the name inside the spec file. Then follow the previous step, and add the proper provides.

Check that nothing breaks on upgrade.

Once the package is here, try to remove or change packages that depend on the old name, in order to get rid of the Obsoletes and Provides one day, and in order to ease the dependancy solver job. And do not forget to add this in the release notes.

You should keep the Provides and Obsoletes for some releases, since people do not upgrade for each and every version of the distribution.

[edit] Library policy

Refer to the Library Policy

[edit] Deeper inside the specfiles

[edit] Tags

Here is a list of other tags that you might see, some that you will see often, some not.

  • Prefix: This is for package relocation. It should NOT be used if your package is not relocatable. Don't be fooled! Prefix: does not define where a package should go. To specify: you want the prefix to be /usr, all you need to do is put Prefix: /usr, and rpm will verify that every file's path in the package does start with /usr; if this verification succeeds, the package will be marked as relocatable.
  • Requires: What is required for the binary package to run. Be advised that RPM will compute the dependencies on dynamic libs and Perl modules automatically, so to keep the spec as clean as possible you should put only what RPM will not detect automatically.
  • BuildRequires: What is required by this package in order to be built. For example, for an ncurses-based application, you would probably want to put ncurses-devel. A package version can be specified using operators such as =, > or <. If a build requirement is missing, the package build will fail.
  • BuildConflicts: What should not be installed on the machine for the package to be built.
  • Provides: This is used to provide a symbolic name (also called "virtual" packages). For example, apache provides "webserver", wu-ftpd and proftpd provide "ftpserver" (so any package that requires an FTP server can list "ftpserver" in its Requires: field).
  • Conflicts: A list of packages that cannot be in the system at the same time as this package. Versions can be specified using operators.
  • BuildArchitectures: Specify specific arch to build this package, and let RPM bail out with errors if one of the Architectures is not the one specified in the list.
  • ExclusiveArch: Can only build on the specified architecture. Packages like MILO, the Alpha equivalent of LILO, will need this.
  • ExcludeArch: Exclude the specified archs.
  • ExclusiveOS: We really don't know why you would need to use this. This excludes a piece of software from a a particular operating system.
  • Epoch: (supersedes Serial) Sometimes, a naming scheme has been done the wrong way and the author goes back to an earlier version. In this case, you need the Epoch: tag with a number. This number will take over the versioning comparison, when rpm has to guess whether a given package is newer than another. Please see next section for how to name packages released via pre-versions.

[edit] Macros

There are also some interesting macros to note. Say, you wanted to do something, but not on every platform. You can do this within RPM with the conditional macros:

%ifarch alpha sparc ppc
%patch0 -p1
%endif

The explanation: only apply the patch if the architecture is alpha, sparc, or ppc. It is not limited to using it here. For example, you can include this in your %files section if you so wish.

Note: it is considered good behaviour to apply a platform specific patch to all platforms, unless it really breaks on another platform.

[edit] RPM command-line parameters

So you know that you can use rpm -ba to build a package. But you have more to play around with:

  • rpm -bp: stops after completion of the %prep section. Basically, it uncompresses the sources and applies the relevant patches.
  • rpm -bc: stops after completion of the %build section. Generally involves the equivalent of make.
  • rpm -bi: stops after completion of the %install section. Well, do you have to use -ba to build again? No! All is not lost. The Mandriva RPM system has been specially patched to allow the -bi option to work with --short-circuit, which will basically resume the process. So, let's say you screwed up your %files section, and now you have fixed it, you don't have to build again from -ba. You can just use rpm -bi --short-circuit file.spec, and then rpm -ba --short-circuit file.spec to build it. Bear in mind, this is for advanced users ONLY as it is very easy to build a broken spec if you do that.
  • rpm --eval %macroname can evaluate a particular RPM macro. This seems to be an undocumented feature in the RPM 3.0.x series. For example, if you would like to find what the %packager macro stands for, do: rpm --eval %packager.

[edit] Dependency issues

[edit] Automatic Requires

rpmbuild will add automatically some Requires to some of the packages you compile; e.g. for perl packages, it will try to find dependencies on other modules and add them as perl(Some::Other::Module). If you want to avoid some of these automatic dependencies to be added, use the _requires_exceptions macro.

For example:

%define _requires_exceptions perl(Foo::Bar)\\|perl(Acme::Buffy)

[edit] Releasing pre-versions

Sometimes, program naming schemes are good, but rpm is lost. For example, with Proftpd, Pre-releases are named with the version followed by the suffix pre and then the pre version number, like so: 1.2.0pre5. Because of string comparisons, rpm thinks that 1.2.0pre5 is newer than 1.2.0 (we know that this is not true).

To permit upgrades to newer packages, we must help rpm to know which packages are newer than others. We could use the Epoch: tag (superseding the Serial: tag) but this is dirty. You have to use another naming convention, putting the "pre" stuff in the release tag; in our example you will call the package "1.2.0-0.pre5.1mdv". Then, when 1.2.0 comes out, you'll release "1.2.0-1mdv", and this package will be able to upgrade the pre5.

[edit] Alternatives

update-alternatives is described on Using Update-Alternatives.

[edit] Signing your packages

Security-conscious people sign their packages as signing makes it possible to verify that the packages have not been altered, and to verify who created them. The GNU Privacy Guard (GPG) is already included in the standard distribution. We recommend that if you wish to sign your package you should use GPG to sign. But RPM supports PGP as well.

First you will need to install GPG . Now read the documentation. As with most *nix applications these come with good documentation. You may later regret not reading it if you value your security. See a very brief set of Docs/Desktop/MUA/Kmail#Creating.2C_backing-up.2C_and_publishing_your_key starting rules and GnuPG - A few tips & warnings.

Generate a key, and then extract the ASCII key to a plain text file:

$ gpg --gen-key

You will be prompted for key type, key size, name, e-mail address and passphrase (please see GnuPG - A few tips & warnings!).

Now, add 2 lines to your ~/.rpmmacros:

%_signature gpg
%_gpg_name "Your_Signature_Name"

(Do not forget the double quotes surrounding Your_Signature_Name.)

To sign your RPM packages while building, you can use the --sign argument. To add one to an existing RPM, do rpm --addsign file.rpm. To resign an existing one, use the --resign option.

For people to be able to verify the packages, they need a copy of your gpg public key. The easiest way to do this is to make an ascii-armored public key file, which you can do with:

$ gpg --list-secret-keys
[snip]
sec    1024g/1234ABCD 2006-06-24 [expires: 2011-12-13]
[snip]

$ gpg -ao abc-pub.asc --export 1234ABCD 

You should make this key available, by uploading to a public key server (gpg --send-keys...), or by publishing on an FTP/ web server. Remember it cannot be removed from public keyservers.

In order to make your new key known to rpm, you have to import it (as root): rpm --import abc-pub.asc

[edit] More on the files section

Sometimes setting the permissions of the installed files for RPM is not always %defattr(-,root,root). You can set individual permissions for files, with the %attr() macro. %attr follows a similar format to %defattr, except that %attr is put in front of the filename.

To tell RPM that a particular file is a configuration file, place a %config in the front of the filename. That way, RPM will upgrade the file, but save a copy of the old one (with the extension .rpmsave). Most of the time, it is NOT the desired behaviour, because you will lose (temporarily) your precious configuration but instead the default one which may be poorer than what you need. To address this issue, use %config(noreplace): it indicates that the file in the package should be installed with extension .rpmnew if there is already a modified file with the same name on the installed machine.

The %config(missingok) indicates that the file need not exist on the installed machine. The %config(missingok) is frequently used for files like /etc/rc.d/rc2.d/S55named where the (non-)existence of the symlink is part of the configuration in %post, and the file may need to be removed when this package is removed. This file is not required to exist at either install or uninstall time.

The %ghost tag on a file indicates that this file is not to be included in the package. It is typically used when the attributes of the file are important while the contents is not (e.g. a log file).

[edit] More on subpackages

To split off into a subpackage you can specify %package foo where "foo" is the suffix that will be added to the main package name.

For example, if your main package name is fred, and you have a %package alice line , then your subpackage will be called fred-alice. You will need to add in the corresponding name in the %description and %files, for example, %description alice, %files alice.

If you don't wish to have RPM inherit the name of your main package as the prefix of the subpackage, you can specify the -n argument to %package, like so: %package -n mysubpackage. You will need to add -n for all other relevant RPM entries as well, such as %description, %files and the RPM scripts. One such application of this would be the library policy mentioned earlier.

[edit] What to avoid

This subsection is for experienced RPM builders -- to be sure that they do not miss the point.

  • Avoid any reference to $RPM_SOURCE_DIR. When using multiple sources, some people tend to reference these sources using this tag. This should be avoided and replaced by %{SOURCE2} for the Source2: source, for example.
  • Avoid to do tricky/clever/strange things in the specfile without documenting it. Most of the time, putting a comment on the line before, with your initials, is very helpful for future re-packagers, in the following style:
# (gc) I want to grab the xmms-config built in .., for bootstrapping nicely
export PATH=".:$PATH"

[edit] Locale specific packages

Some packages are only meant to be used together with special localization(s). For example cttex, a Thai word separator program, will be useless when you don't use your system in Thai.

For such packages, you need to put an explicit Requires: on the corresponding locale package (here, locales-th ). With this information, the installer will be able to change the rates of the packages according to the selected internalization configuration, so that the necessary packages get installed.

[edit] Hacking rpm macros

If you understand what is a macro, you understand how to ask to rpm to do what you want. Here I report some more or less internal macros you can overwrite for some hacking stuff

[edit] Predefined macros

[edit] Building macros

  • %_topdir: The dir for building rpms, user should always define it in ~/.rpmmacros. Default value is %_usr, aka /usr/src/RPM.
  • %_rpmdir: where binary rpms will be stored, default value is %{_topdir}/RPMS,
  • %_srpmdir: where source-rpms will be stored, default value is %{_topdir}/SRPMS,
  • %_sourcedir where the sources files are located, default value is %{_topdir}/SOURCES,
  • %_builddir: where the build will be made, i.e. the dir where source files are expanded and built, default is %{_topdir}/BUILD,
  • %_specdir: where the spec file is located when a source rpm is installed, default is %{_topdir}/SPECS,
  • %_tmppath: where temporary files will be written, it is used for build scripts and in mdv scripts. It is used to set %buildroot. The default value is %{_var}/tmp.
  • %_rpmfilename: Define the filename to use for binary rpms, default is %{ARCH}/%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm. This file will be stored in %_rpmdir. NB: there is no macro for source rpms. Internally rpm will always source using NAME-VERSION-RELEASE.src.rpm.
  • %__build_cmd: This macro defines programs which will run building scripts. rpm will evaluate %__build_cmd SCRIPT_FILE and exec it. Default is "/bin/sh -e".

[edit] rpmdb macros

  • %_dbpath: the location of the rpm database in the system. This macro is hardcoded at build time in the rpm binary. The default value for Mandriva Linux (and other distros) is /var/lib/rpm. You can overwrite it to create and use another database. NB: Do not change it if you plan to prepare a system inside a chroot, using --root is better.

[edit] Adding your own macros to rpm

Since rpm 4.4, it is possible to use jokers in the rpm macro files search path. This give us the possibility to inject new macros simply by creating a file in the proper directory.

Currently there are two ways to add a new macro:

  • asking rpm-mandriva-setup maintainers to add or modify the macros in the basic configuration,
  • providing yourself a new macros file.

The first solution speaks for itself. I will explain the second:

If you plan to make an rpm that provides macros, you must first understand that:

  • your macros will exist only when the rpm providing them is installed,
  • you must avoid macros overlaping; i.e. do not provide a macro that is already provided by another package

In practice, you have to create a file with .macros' extension in the /etc/rpm/macros.d/ directory. Even the name of the file does not matter, a good practice is to use as name: %name.macros.

This file will look like all macros files:

# a comment
%macro_name macro_body

The next step is to put this file into your package, that's all !

Above is a complete example from postgresql, the goal is to make easier the packaging of tools linked to postgres:

mkdir -p %buildroot/%_sys_macros_dir
cat > %buildroot/%_sys_macros_dir/%{name}.macros <<EOF
%%postgresql_version %{version}
%%postgresql_major   %{current_major_version}
%%postgresql_minor   %{current_minor_version}
%%pgmodules_req Requires: %{name}-server-ABI = %{current_major_version}
EOF

Explanation:

  • %_sys_macros_dir is a macro provided by rpm for the /etc/rpm/macros.d path
  • don't forget to use double "%" (i.e. "%%") or the macro will be evaluated (which is not what you want)
  • %{current_major_version} and %{current_minor_version} are defined in the spec itself
  • %pgmodules_req allows to add a require on the postgresql module to avoid breakage on ABI changes. postgresql-server has a corresponding provide

[edit] The %check section

If the source comes with self-tests (i.e. "make test" or "make check" targets) you can put them in a fake %check section between %build and %install (its place is important). Then, to rebuild the rpm without executing checks, you can do :

rpm -ba --define 'check exit 0' foobar.spec

[edit] Packages maintained in CVS

Some packages are maintained in CVS and cannot be uploaded with the usual procedure. For these packages the .spec file starts with the following 2 lines to warn the packager that a different procedure must be used:

# Changed by Makefile of cvs.
# Please change this file only in cvs!

To update this package, please use the procedure described on RPM From CVS Guidelines

[edit] Easy handling of differences between two RPM packages

The urpmdiff tool, available in contribs, allows to produce a report of differences between two rpms. The manpage has more information.

[edit] Using switches in specfiles

This section details how to use switch in specfiles to ease the building of an alternate rpm, with less or more features.

[edit] Rebuilding an rpm with a switch activated

Rebuilding an rpm is simple. All you need is to download the srpm and run rpm --rebuild myrpm.src.rpm.

To see if a package can be rebuilt with options, you can either see the description or documentation, or look at the spec. There is no built-in mechanism to do that, but it is common practice to put it in the description and add a file called README.mdk to explain the option and what is chosen by default.

If the package is rebuildable (like postfix for example), all you have to do is: rpm --rebuild --with option myrpm.src.rpm.

[edit] Adding options to the spec files

An option requires a few macros in the specfiles.

# define the default values
%define  with_FEATURE 1

# if --without switch is used
%{?_without_feature: %{expand: %%global with_FEATURE 0}}

# if --with switch is used
%{?_with_feature: %{expand: %%global with_FEATURE 1}}

Then you can use the following construct in your spec file:

%if %{with_FEATURE}
# do something to enable the feature
%endif

[edit] Some examples

Here is a list of a few Mandriva Linux rpms that use switches, where you could look for proper implementation :

  • postfix
  • samba
  • openssh

[edit] Switch naming

If you plan to add a switch, please look to this list to keep the naming consistent (and please add yours too):

  • mysql
  • ldap
  • sasl
  • pgsql (postgresql support)
  • pam
  • tls (ssl)

[edit] Describing the changes

In order to help users who intend to rebuild, you should describe the changes in the package description (http://archives.mandrivalinux.com/cooker/2005-01/msg02836.php). The format has not yet been decided, but it should provide options that should be built, description of options, and what were the options used by the current rpm (http://archives.mandrivalinux.com/cooker/2005-01/msg02837.php).

You can also add them in a file placed in %doc ( something like README.mdk, but the name is yet undecided ).

[edit] Past discussion about the subject

[edit] To become a Jedi, use Emacs. You have to

In a nutshell, Emacs can automate much of the work, with an appropriate configuration file. A good start is rpm-spec-mode.el which is now provided by the package rpm-build (it used to be Chmouel's one).

Once installed, in addition to nice syntax highlighting, you'll increase the release tag with C-c r, add a new changelog entry (with your name, email address, correct version and release tag) with C-c e; you will even visit the bzipped patches (granted you have jka-compr and ffap) with minimal pain! M-x rpm-change-group allows to add/modify a group by browsing the list of available groups. And much more...

You can customize Emacs a lot when you know a little bit of Emacs-Lisp: see RPM Spec Mode Customization for some useful functions.

Personal tools
In other languages