RPM spec file syntax

From Rosalab Wiki
Jump to: navigation, search
This is the policy covering RPM spec files in ROSA Linux.

ROSA Linux uses the RPM package format for packages, however everyone seems to have their own style as to the formatting of the .spec files and it can make it confusing for other developers or maintainers to work on these packages.

As a result, we encourage packagers to use the following .spec template when writing or modifying .spec files to make it simple for others to take over or do work on the packages. If everyone follows the same format, there are never any surprises.

More specific policies, such as library policy, alternatives policy, etc can be found in the Packaging Policies section.

Contents

Spec Header

The rpm .spec header contains the important version, source, patch, requires, and buildrequires information for the particular package(s) to be built.


Macros definition

The first part of the spec should contains macros definitions, as illustrated below:

%define major		0
%define libname		%mklibname aide %{major}

All %define statements should be made here, with comments as appropriate. They should be tabbed so as to align properly, as noted above (use two tab widths after the 'name' definition, or column 25 (third tab stop), as this allows for longer definition names). If a definition name is longer and the next tab stop would carry beyond column 26.

Note: defining explicit macros for name, version and release is useless, as those are implicitly defined from corresponding tags.


Name, Version and Release

The first section should contain standard name, version and release tags:

Name:    aide  
Version: 0.13.1
Release: 1

In addition, it can contain Epoch tag which is not reflected in package name but is used when comparing package versions (and is considered to have the highest priority - if two packages have different epoch values, the one with newer epoch is considered to be newer, regardless of version/release or distepoch).

Summary, Name, Sources and Patches

The next section of the header would look as follows:

Summary:        Advanced Intrusion Detection Environment  
License:        GPLv2+
Group:          Monitoring
URL:            http://sourceforge.net/projects/aide
Source0:        http://prdownloads.sourceforge.net/aide/%{name}-%{version}.tar.gz
Source1:        http://prdownloads.sourceforge.net/aide/%{name}-%{version}.tar.gz.asc
Source2:        aide.conf
Source3:        aidecheck
Source4:        aideupdate
Source5:        aideinit
Source6:        aideinit.8
Patch0:         some.patch

As can be seen, everything in is a very linear order:

  1. Summary tag -- a brief one-line description of the package
  2. License tag -- refer to the Licensing policy
  3. Group tag -- the Packaging group this package belongs to
  4. URL -- the home page of the software package
  5. Source0... -- the source files
  6. Patch0... -- the patch files

Source files must begin with Source0, do not use Source: and then Source1:; if a package has exactly one source file, still use Source0 as it may not always continue to have exactly one source file. Likewise for the Patch0 keyword; always begin with Patch0:, and never just Patch:. If a source file has a downloadable URL that it came from, it must be included.

Tab stops here are one shorter than the defines, largely because defines can, and often are, longer but Source, Name, etc. tags tend not to. Instead of progressing to column 25, use column 17, or the second tab stop. It is important that everything is left-aligned for the "second column" or keyword values as it maximizes readability.


Patch Naming

Patches must be named in a very explicit manner to make it very clear to what version it was originally applied against and where it came from. To that end, a patch needs to follow the convention of [package_name]-[version]-[source]-[description].patch:

  • [package_name] is the name of the package it applies against, such as 'shadow-utils' or 'gnupg'
  • [version] is the version of the program this patch was developed against, such as 1.0. If a patch is rediffed because the old patch does not apply to a new version, a new patch must be created with the appropriate name -- it is inappropriate to rediff foo-1.0-rosa-fix.patch against foo-1.2 and continue to use the same patch name. The new patch must be named foo-1.2-rosa-fix.patch.
  • [source] is the upstream source of where the patch comes from. Patches developed by ROSA should have that [source] as 'rosa'. A patch taken from Fedora, but rediffed to work with a ROSA package would use 'rosa-fdr' as the [source] field. A patch taken from upstream CVS would use 'cvs'. This makes it very obvious where a patch has come from and who has made modifications to it; a foo-1.0-rosa-avx-owl-tmpfix.patch would indicate the patch originated from Openwall (owl), was modified at some point by Annvix (avx), and further modified by ROSA (rosa).
  • [description] is a short description of the patch's purpose


Build Root, Requires, etc.

BuildRoot in ROSA Linux is set automatically, there is no need to define it in the spec.

The next part of the RPM spec are the build requirements and this is perhaps one of the messiest and potentially inconsistent part of any spec. BuildRequires should be listed one per line for maximum readability; instead of cramming multiple BuildRequires on a single line, use one BuildRequires tag per dependency. While RPM may be able to quickly "view" that really long line of BuildRequires, humans cannot and while this may make the spec longer, it makes it easier to read.

BuildRequires:  flex
BuildRequires:  glibc-devel
BuildRequires:  glibc-static-devel
BuildRequires:  mhash-devel
BuildRequires:  zlib-devel
BuildRequires:  bison

Requires, Obsoletes, Provides, Conflicts, etc.

The last set of tags in the RPM header are for Requires, Obsoletes, Provides, Conflicts, etc. and they should be defined one per line as with BuildRequires.

Requires:       gnupg
Requires(pre):  foo
Requires(postun): foo
Conflicts:      tripwire
Provides:       AIDE+gpg
Obsoletes:      bar

Again, keep the tab stops in mind. When using "Requires(postun)" you will progress beyond the tab stop at column 17; in these instances use a single space.

Also note the ordering. Instead of mixing Requires and Provides, keep them in a distinct order:

  1. Requires, Requires(pre), Requires(post), etc. -- all requires should come first, one per line
  2. Conflicts -- all conflicts come second
  3. Provides and Obsoletes -- all provides and obsoletes come third, and may be intermixed as they tend to be closely related


Description

The %description comes last, and provides the description of the package.

Note: Lines of summary and description should be wrapped at 80 characters.

A final RPM spec header would look like:

Name:			aide
Version:		0.13.1
Release:		1

%define major		0
%define libname		%mklibname aide %{major}
%define somereallylongname foo

Summary:        Advanced Intrusion Detection Environment
License:        GPLv2+
Group:          Monitoring
URL:            http://sourceforge.net/projects/aide
Source0:        http://prdownloads.sourceforge.net/aide/%{name}-%{version}.tar.gz
Source1:        http://prdownloads.sourceforge.net/aide/%{name}-%{version}.tar.gz.asc
Source2:        aide.conf
Source3:        aidecheck
Source4:        aideupdate
Source5:        aideinit
Source6:        aideinit.8
Patch0:         some.patch

Buildrequires:  flex
BuildRequires:  glibc-devel
BuildRequires:  glibc-static-devel
BuildRequires:  mhash-devel
BuildRequires:  zlib-devel
BuildRequires:  bison

Requires:       gnupg
Requires(pre):  foo
Requires(postun): foo
Conflicts:      tripwire
Provides:       AIDE+gpg
Obsoletes:      bar

%description
AIDE (Advanced Intrusion Detection Environment) is a free alternative to
Tripwire. It does the same things as the semi-free Tripwire and more.  It
is a file system integrity monitoring tool.

For packages that create multiple sub-packages, follow the guidelines above for each one.

 %prep

The %prep section follows all package definitions. There should be at least two blank lines to separate the end of the last %description from %prep. A simple %prep section would look like:

%prep
%setup -q

Note: You don't have to write "%setup -n %{name}-%{version} -q", it's the same as "%setup -q"

 %clean

There is no need in %clean section in RPM5.

Other Conventions

Here is a list of other conventions that must be observed in ROSA Linux spec files:


System Macros vs. User-Definable Macros

System macros are those defined in /etc/rpm/macros.d/ files and include ie. %_install_info, among others. A system macro is something that does something, or calculates something. It is not a simple definition, like %{_tmppath} which merely translates to a path. System macros must be written without curly braces; i.e. as %_install_info and not %{_install_info}. User-definable macros, which include %{_tmppath} or %{_bindir} must be written with curly braces; i.e. as %{_tmppath} and not %_tmppath. This makes reading the spec easier as everyone will be using a similar "curly braces" convention.

If you're unsure of which to use, keep in mind that a macro like %{_libdir} provides a value (in this case, /usr/lib), whereas a macro like %_install_info actually executes code of some sort.

  • Use %{_libdir}, not %_libdir
  • Use %_install_info, not %{_install_info}
  • Consistently use this mechanism and all spec files will be much easier to read

Standard macros

Keeping constistent macros names across spec files enhance readability.

  • %{upstream_name} when upstream name differs from the package one
  • %{upstream_version} when upstream version differs from the package one


Variables

Variables which are really definitions, such as $RPM_OPT_FLAGS or $RPM_BUILD_ROOT must not be used. Macros like %{optflags} and %{buildroot} must be used instead. Keep "$*" variables strictly limited to shell constructs and not RPM-based definitions.


Changelogs

Changelogs are stored in the Git commit logs, but should still be considered as part of the final spec when committing to svn (as the svn commit logs produce the RPM changelog upon build). Make changelogs verbose enough that those coming later do not need to look at a diff of changes to see what actually happened. A bad example would be:

- fixed foo

This tells no one anything and after a year, whomever made the commit likely has no idea what they did in that commit. Instead, write something like:

- rediffed description.patch to fix foo
- added foo-manpages.tar.bz2 to provide such and such for foo
- dropped cvsfix32.patch; merged upstream

The above is far more telling as to what was actually done. Note that source files must be referred to by their full name (in the above, foo-manpages.tar.bz2, not "S23" or something similar). Patches do not need to be referred to by their full names, but can be referred to by the "description" portion of the patch. For instance, the first comment is "rediffed description.patch to fix foo", where description.patch is noted. The patch could in reality be named foo-1.2-rosa-description.patch; the prefix (foo-1.2-rosa) can be dropped as it should be fairly straightforward to determine what patch has modified/added/removed based on the unique description of the patch. If the patch name is not unique (i.e. there is foo-1.2-rosa-description.patch and foo-1.0-cvs-description.patch), then one of the patch names can (and probably should) be changed or the entire patch name should be noted in the changelog.

Do not refer to source files or patch numbers numerically (i.e. using S23 or P12) as patches and source files may be renumbered from time to time and a patch number is not guaranteed to remain consistent.


Source handling

Source files have typically be handled by using %{SOURCExx} macros, but this is inefficient for a few simple reasons:

  • no need to jump up and down in the spec to figure out what %{SOURCE12} is
  • source files can be easily renumbered without making multiple changes

Instead, using %{_sourcedir}/foo in the spec is preferred as it makes things easier to read and easier to work with. For instance, compare:

Source12:	something
...
install -m 0644 %{SOURCE12} %{buildroot}%{_sysconfdir}/pam.d/

to:

Source12:	something.pam
...
install -m 0644 %{_sourcedir}/something %{buildroot}%{_sysconfdir}/pam.d/

Source files must not contain the macros %{version} or %{name} unless they are the original upstream source files.

Patch files must not contain the macros %{version} or %{name} ever.


Resources


Note:
This page is based on the Mandriva RPM Spec File Syntax.