Policies/RpmSpecProposal

From Mandriva Community Wiki

Jump to: navigation, search
Mandriva Linux RPM Spec File Policy

This is the policy covering RPM spec files in Mandriva Linux. It is currently a work-in-progress proposal, based loosely off the Annvix Spec Files policy.

Mandriva 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 the library policy, alternatives policy, etc can be found in the Packaging Policies section.

Contents

[edit] Spec Header

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

[edit] Defines

The next section of the spec should be for all defines, as illustrated below:

Name:                   aide
Version:                0.13.1
Release:                %mkrel 1

%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, use a single space, such as:

Name:                   aide
Version:                0.13.1
Release:                %mkrel 1

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

and not:

Name:                   aide
Version:                0.13.1
Release:                %mkrel 1

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

The %{name}, %{version}, and %{release} information should not be handled with %define, but should appear as above, at the top of the spec, to clearly identify the package's name, version, and release.

[edit] 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 Mandriva 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.

[edit] 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-mdv-fix.patch against foo-1.2 and continue to use the same patch name. The new patch must be named foo-1.2-mdv-fix.patch. For historical purposes, patches should be moved in svn; instead of doing "svn rm foo-1.0-mdv-fix.patch" and "svn add foo-1.0-mdv-fix.patch", the original patch should be moved and then the newly-derived patch copied and committed; i.e. "svn mv foo-1.0-mdv-fix.patch foo-1.2-mdv-fix.patch; svn commit; cp ~/foo-1.2-mdv-fix.patch ."
  • [source] is the upstream source of where the patch comes from. Patches developed by Mandriva should have that [source] as 'mdv'. A patch taken from Fedora, but rediffed to work with a Mandriva package would use 'mdv-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-mdv-avx-owl-tmpfix.patch would indicate the patch originated from Openwall (owl), was modified at some point by Annvix (avx), and further modified by Mandriva (mdv).
  • [description] is a short description of the patch's purpose

[edit] Build Root, Requires, etc.

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.

Likewise, the BuildRoot tag is largely inconsistent. It should be defined as "%{_tmppath}/%{name}-%{version}"; there is no need to specify a "-root" or "-buildroot" suffix. This should remain consistent across specs. For instance:

Buildrequires:  flex
BuildRequires:  glibc-devel
BuildRequires:  glibc-static-devel
BuildRequires:  mhash-devel
BuildRequires:  zlib-devel
BuildRequires:  bison
BuildRoot:      %{_tmppath}/%{name}-%{version}

[edit] 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

[edit] Description

The %description comes last, and provides the description of the package. Lines should be wrapped at 76 characters.

A final RPM spec header would look like:

Name:                   aide
Version:                0.13.1
Release:                %mkrel 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
BuildRoot:      %{_tmppath}/%{name}-%{version}

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.

[edit] %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


[edit] Other Conventions

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

[edit] %mkrel

The %mkrel macro is to be used at all times, and should be done in the Release definition:

Release:                %mkrel 1

Any use of the %{subrel} macro must be done immediately prior to the Release definition:

Name:                   aide
Version:                0.13.1
%define subrel          1
Release:                %mkrel 1

[edit] System Macros vs. User-Definable Macros

System macros are those defined in /etc/rpm/macros.d/ files and include %mkrel and %_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 %mkrel and not %{mkrel}. 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

[edit] 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.

[edit] Changelogs

Changelogs are stored in the SVN 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-mdv-description.patch; the prefix (foo-1.2-mdv) 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-mdv-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.

[edit] 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.

[edit] Resources

  • Fedora's RPM Guide - this is a killer anything-having-to-do-with-rpm resource
  • Mandriva RPM HOWTO - the Mandriva RPM HOWTO (dated, but contains good information and should be seen as supplemental to this policy)

[edit] Possible Changes/Suggestions Based on Proposal

This section details some technical changes that are not part of the proposal but may need to be implemented to make the proposal most effective:

  • Create a macro (%cleanbuildroot) to automatically clean the buildroot, or have %install or %clean automatically clean the buildroot without having to be specified explicitly
  • Drop BuildRoot from spec file (works since mdv2008.0, in mdv2008.1 it uses %defaultbuildroot). nb: this breaks compatibility with other/older distros
Personal tools