From Fedora Project Wiki

No edit summary
Line 1: Line 1:
This is a tutorial on writing RPM files, suitable for someone familiar with  
This is a hands-on tutorial on writing RPM files, suitable for an impatient
the FOSS software building process, and with using pre-made RPM packages.
person who wants to quickly step up to create source and binary software packages. I assume familiarity with using pre-made RPM packages, and with  
the FOSS software building process. More in-depth information on using and building RPM
packages is available from, e.g.,
https://fedoraproject.org/wiki/Tools/RPM


This tutorial uses the GNU "Hello World". While 'Hello World" is a trivial program, the GNU project
This tutorial uses the GNU "Hello World". While 'Hello World" is a trivial program, the GNU project
Line 22: Line 25:
yum groupinstall development-tools
yum groupinstall development-tools
yum install rpm-build rpmdevtools
yum install rpm-build rpmdevtools
</pre>
If you want to test the build procedure in the context of Fedora anonymous package build
system, you need to configure your non-privileged account to be a member of the 'mock' group:
<pre>
usermod -a -G mock <yourAccountName>
</pre>
</pre>


Line 38: Line 47:
== Building a "Hello World" RPM==
== Building a "Hello World" RPM==


We need the source code of the project we are packaging in the <code>~/rpmbuild/SOURCE</code>
We need the source code of the project we are packaging, often referred
directory. We need a compressed tarball, which happens to be a preferred distribution form for most FOSS projects
to as the 'upstream' source. We will download it from the project's website  into the <code>~/rpmbuild/SOURCE</code>
 
directory. We are getting the compressed tarball archive, which happens to be a preferred distribution form for  
most FOSS projects.
<pre>
<pre>
cd ~/rpmbuild/SOURCE
cd ~/rpmbuild/SOURCE
Line 46: Line 56:
</pre>
</pre>


The RPM package is configured by a <code>.spec</code> file. We will create a  
The RPM package is configured by <code>.spec</code> files. We will create a template
template of such file in the appropriate directory:
file <code> hello.spec</code> in the appropriate directory:
 
<pre>
cd ~/rpm/SPECS
cd ~/rpm/SPECS
rpmdev-newspec hello
rpmdev-newspec hello
</pre>


This will create a skeleton spec file <code>hello.spec<code>. The fields in
=== Inside a <code>.spec</code> file ===
this file need slight editing as described below:


The fields in our <code>.spec</code> file need slight editing. Please follow the
[https://fedoraproject.org/wiki/How_to_create_an_RPM_package#Spec_file_pieces_explained
Fedora rules] for these fields. In our case, the file might start as follows:
<pre>
Name: hello
Name: hello
Version: 2.5 (the version is from upstream while Release is from Fedora)
Version: 2.5
Release: 1
Release: 1
Summary: should be short and precise. Only keywords, simple phrases
Summary: The "Hello World" program
e.g. "Widget management application". First letter uppercase to avoid
License: GPLv3
rpmlint complaints
URL: http://ftp.gnu.org/gnu/hello     
Group: from /usr/share/doc/rpm-4.6.0/GROUPS    but groups not used any more
Source0: http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz
License: GPLv3 (check the source for the license it is released under)
%description:
URL: http://ftp.gnu.org/gnu/hello    (The homepage of the program)
The "Hello World" program, done with all bells and whistles of a proper FOSS
Source0: http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz (the URL for
project, including configuration, build, internationalization, helpfiles, etc.
the source distribution files)
 
%changelog
* Tue Mar 30 2010 The Coon of Ty <Ty@coon.org> 2.5-1
- Initial version of the package%changelog
 
</pre>
 
The <code>Version</code> should mirror upstream while <code> Release</code> numbers our work
within Fedora. The first letter of the <code> Summary</code> should be uppercase to avoid
rpmlint complaints.
 
It is your responsibility to check the <code>License</code> status of the software, by
inspecting the source files and/or their LICENSE files, and/or by talking to the authors.


Now comment out BuildRequires and Requires with a # for now,
The <code> Group </code> tag is being phased out, but it doesn't hurt to classify it
in accordance to the list in <code>/usr/share/doc/rpm-4.6.0/GROUPS</code>.


%description:
The <code> %changelog</code> should document the work on preparing the RPM , and should include the version string to avoid
Package summary; text starts on next line, ends with empty line
rpmlint complains. Multi-line sections like <code> %changelog</code> or <code> %description</code> start on a line under
the directive, and end with an empty line.


BuildRoot is  the location where we are building the package,
Lines which aren't needed (e.g. <code>BuildRequires</code> and <code>Requires</code>) can be commented out with a hash ('#') for now.
temporary folder, default is OK


%prep is for preparing , eg. extracting the source and applying patches
Many lines in the template don't need to be changed at all in many cases, at least for the initial attempt:
if there are any


The actual build commands are specified in %build
<pre>
usually you run ./configure and  make.
BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
A recently popular 'make' replacement waf is sometimes used used for
builds; it automatically configures the build:
./waf build replaces %configure; make %{?_smp_mflags}


%prep
%setup -q


After that the files are installed to a temporary location during
%build
%install, usually 'make install'
%configure
make %{?_smp_mflags}


%install
%install
rm -rf $RPM_BUILD_ROOT remains as is for cleaning up old stuff
rm -rf $RPM_BUILD_ROOT
from a previous build that failed
make install DESTDIR=$RPM_BUILD_ROOT
"make install DESTDIR=$RPM_BUILD_ROOT" or
"DESTDIR=$RPM_BUILD_ROOT ./waf install"


%clean remains as is
%clean
rm -rf $RPM_BUILD_ROOT


The template %changelog is as follows (include the version to avoid
</pre>
rpmlint complains)
 
* Sun Apr 05 2009 Foo Bar <foo@bar.com> - 0.3.1-1
=== Building the package ===
- Initial attempt


We are ready for the first  run to build source,  binary and debugging packages:
We are ready for the first  run to build source,  binary and debugging packages:


<pre>
rpmbuild -ba hello.spec
rpmbuild -ba hello.spec
</pre>
It will complain and list the unpackaged files, i.e. the files that would be
installed in the system that weren't  declared as belonging to the package. We need to declare them in the
<code>%files</code> section. Do not hardcode names like
<code>/usr/bin/</code>, but use macros, like <code>%{_bindir}/hello</code> instead.
The manual pages should be declared in the <code>%doc</code> subsection:
<code>%doc %{_mandir}/man1/hello.1.gz</code>.
This is an iterative process: after editing the <code>.spec</code> file, rerun rpmbuild.


It will probably complain about unpackaged files. We need to declare them in the
Since our program uses translations and internationalization, we are getting a lot of
%files section. When you add them, do not hardcode /usr/bin/, but use
undeclared i18 files. The recommended method to declare them is explained in
%{_bindir}/hello instead
https://fedoraproject.org/wiki/Packaging/Guidelines#Handling_Locale_Files:
After editing, rerun rpmbuild.


If the program uses translations, use %find_lang ${name}
* find the filenames in the <code>%install</code> step: <code> %find_lang ${name}</code>
in %install and BuildRequires: gettext , and %files -f ${name}.lang as
* add the required build dependencies: <code>BuildRequires: gettext</code>
explained in
* use the found filenames <code>%files -f ${name}.lang</code>
https://fedoraproject.org/wiki/Packaging/Guidelines#Handling_Locale_Files


If the program uses GNU info files, you need to do some magic:
If the program uses GNU info files, you need to do some magic:
- delete the 'dir' file in %install:  rm -f $RPM_BUILD_ROOT/usr/share/info/dir
* delete the 'dir' file in %install:  <code>rm -f $RPM_BUILD_ROOT/usr/share/info/dir</code>
- Requires(post): info and Requires(preun): info
* <code>Requires(post): info</code> and <code>Requires(preun): info</code>
- add postinstall and preuninstall steps to configure info:
* add postinstall and preuninstall steps to configure info.
 
=== A complete .spec file ===
 
After few iterations, we could end up with the following initial version of a .spec file:
 
<pre>
Name:          hello
Version:        2.5
Release:        1%{?dist}
Summary:        The "hello world" program from GNU
 
Group:          Applications/Text
License:        GPLv3
URL:            http://ftp.gnu.org/gnu/hello
Source0:        http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
BuildRequires: gettext
# Requires:     
Requires(post): info
Requires(preun): info
 
%description
The "hello world" program from GNU, with bells and whistles
 
 
%prep
%setup -q
 
 
%build
%configure
make %{?_smp_mflags}
 
 
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
%find_lang %{name}
rm -f $RPM_BUILD_ROOT/usr/share/info/dir


%post
%post
Line 128: Line 202:
fi
fi


With this spec file, you should be able to successfully recreate the
%clean
RPMs. Next you should check them for conformance with RPM design
rm -rf $RPM_BUILD_ROOT
rules, by running rpmlint
 
on the spec file and all RPMs: rpmlint hello.spec ../SRPMS/hello*
 
../RPMS/*/hello*
%files -f %{name}.lang
%defattr(-,root,root,-)
%{_bindir}/hello
%doc %{_mandir}/man1/hello.1.gz
%doc %{_infodir}/%{name}.info.gz
 
%changelog
* Tue Mar 30 2010 The Coon of Ty <Ty@coon.org> 2.5-1
- Initial version of the package
</pre>
 
With this spec file, you should be able to successfully complete the
build process, and create the source and binary RPM packages.  
 
Next you should check them for conformance with RPM design
rules, by running <code>rpmlint</code> on the spec file and all RPMs:  
 
<pre>
rpmlint hello.spec ../SRPMS/hello* ../RPMS/*/hello*
</pre>
 
If there are no warnings or errors, we've succeeded.
If there are no warnings or errors, we've succeeded.
=== The <code>mock</code> builds ===


To check that the package build will succeed in the Fedora restricted
To check that the package build will succeed in the Fedora restricted
build environment, check it with mock. Your account needs to be in the
build environment, check it with mock.
'mock' group for
mock to work, so you may need to do one-time setup, like so:
 
sudo usermod -a -G mock przemek
 
and then run mock:


<pre>
mock -r fedora-12-i386 --rebuild ../SRPMS/hello-2.5-1.fc12.src.rpm
mock -r fedora-12-i386 --rebuild ../SRPMS/hello-2.5-1.fc12.src.rpm
</pre>

Revision as of 21:43, 5 April 2010

This is a hands-on tutorial on writing RPM files, suitable for an impatient person who wants to quickly step up to create source and binary software packages. I assume familiarity with using pre-made RPM packages, and with the FOSS software building process. More in-depth information on using and building RPM packages is available from, e.g., https://fedoraproject.org/wiki/Tools/RPM

This tutorial uses the GNU "Hello World". While 'Hello World" is a trivial program, the GNU project contains most of the usual peripheral components associated with a typical FOSS software project, such as the configuration/build/install environment, documentation, internationalization, etc., so it is a reasonable vehicle to practice building RPMs on.

I wrote this tutorial after reading Christoph Wickert's IRC class on building RPMs. Rahul Sundaram suggested using GNU "Hello World" as a test case, and it turns out that Christian Lyder Jacobsen also had this idea in 2009. Christian is not intending to update his website, so I decided to publish my version in this wiki.

Development environment

To build RPMs we need a set of development tools. This is a one-time-only setup, installed by running those commands from a system administration (root) account:

yum groupinstall development-tools
yum install rpm-build rpmdevtools

If you want to test the build procedure in the context of Fedora anonymous package build system, you need to configure your non-privileged account to be a member of the 'mock' group:

usermod -a -G mock <yourAccountName>

Those are the only commands requiring root privileges. All the remaining work should be done from your regular, non-privileged account. Modern RPM-based systems, including Fedora, are set up to build and test RPM packages purely from within a non-privileged account. The command

rpmdev-setuptree

sets up a RPM build area in your ~/rpmbuild. This directory will contain several subdirectories, for the project source code, RPM configuration files and for the resulting source and binary packages.

Building a "Hello World" RPM

We need the source code of the project we are packaging, often referred to as the 'upstream' source. We will download it from the project's website into the ~/rpmbuild/SOURCE directory. We are getting the compressed tarball archive, which happens to be a preferred distribution form for most FOSS projects.

cd ~/rpmbuild/SOURCE
wget  http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz

The RPM package is configured by .spec files. We will create a template file hello.spec in the appropriate directory:

cd ~/rpm/SPECS
rpmdev-newspec hello

Inside a .spec file

The fields in our .spec file need slight editing. Please follow the [https://fedoraproject.org/wiki/How_to_create_an_RPM_package#Spec_file_pieces_explained Fedora rules] for these fields. In our case, the file might start as follows:

Name: hello
Version: 2.5
Release: 1
Summary: The "Hello World" program
License: GPLv3
URL: http://ftp.gnu.org/gnu/hello    
Source0: http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz
%description:
The "Hello World" program, done with all bells and whistles of a proper FOSS 
project, including configuration, build, internationalization, helpfiles, etc.

%changelog
* Tue Mar 30 2010 The Coon of Ty <Ty@coon.org> 2.5-1
- Initial version of the package%changelog

The Version should mirror upstream while Release numbers our work within Fedora. The first letter of the Summary should be uppercase to avoid rpmlint complaints.

It is your responsibility to check the License status of the software, by inspecting the source files and/or their LICENSE files, and/or by talking to the authors.

The Group tag is being phased out, but it doesn't hurt to classify it in accordance to the list in /usr/share/doc/rpm-4.6.0/GROUPS.

The %changelog should document the work on preparing the RPM , and should include the version string to avoid rpmlint complains. Multi-line sections like %changelog or %description start on a line under the directive, and end with an empty line.

Lines which aren't needed (e.g. BuildRequires and Requires) can be commented out with a hash ('#') for now.

Many lines in the template don't need to be changed at all in many cases, at least for the initial attempt:

BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

%prep
%setup -q

%build
%configure
make %{?_smp_mflags}

%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT

%clean
rm -rf $RPM_BUILD_ROOT

Building the package

We are ready for the first run to build source, binary and debugging packages:

rpmbuild -ba hello.spec

It will complain and list the unpackaged files, i.e. the files that would be installed in the system that weren't declared as belonging to the package. We need to declare them in the %files section. Do not hardcode names like /usr/bin/, but use macros, like %{_bindir}/hello instead. The manual pages should be declared in the %doc subsection: %doc %{_mandir}/man1/hello.1.gz.

This is an iterative process: after editing the .spec file, rerun rpmbuild.

Since our program uses translations and internationalization, we are getting a lot of undeclared i18 files. The recommended method to declare them is explained in https://fedoraproject.org/wiki/Packaging/Guidelines#Handling_Locale_Files:

  • find the filenames in the %install step: %find_lang ${name}
  • add the required build dependencies: BuildRequires: gettext
  • use the found filenames %files -f ${name}.lang

If the program uses GNU info files, you need to do some magic:

  • delete the 'dir' file in %install: rm -f $RPM_BUILD_ROOT/usr/share/info/dir
  • Requires(post): info and Requires(preun): info
  • add postinstall and preuninstall steps to configure info.

A complete .spec file

After few iterations, we could end up with the following initial version of a .spec file:

Name:           hello
Version:        2.5
Release:        1%{?dist}
Summary:        The "hello world" program from GNU

Group:          Applications/Text
License:        GPLv3
URL:            http://ftp.gnu.org/gnu/hello
Source0:        http://ftp.gnu.org/gnu/hello/hello-2.5.tar.gz
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

BuildRequires: gettext
# Requires:       
Requires(post): info
Requires(preun): info

%description 
The "hello world" program from GNU, with bells and whistles


%prep
%setup -q


%build
%configure
make %{?_smp_mflags}


%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
%find_lang %{name}
rm -f $RPM_BUILD_ROOT/usr/share/info/dir

%post
/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :

%preun
if [ $1 = 0 ] ; then
/sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
fi

%clean
rm -rf $RPM_BUILD_ROOT


%files -f %{name}.lang
%defattr(-,root,root,-)
%{_bindir}/hello
%doc %{_mandir}/man1/hello.1.gz
%doc %{_infodir}/%{name}.info.gz

%changelog
* Tue Mar 30 2010 The Coon of Ty <Ty@coon.org> 2.5-1
- Initial version of the package

With this spec file, you should be able to successfully complete the build process, and create the source and binary RPM packages.

Next you should check them for conformance with RPM design rules, by running rpmlint on the spec file and all RPMs:

rpmlint hello.spec ../SRPMS/hello* ../RPMS/*/hello*

If there are no warnings or errors, we've succeeded.

The mock builds

To check that the package build will succeed in the Fedora restricted build environment, check it with mock.

mock -r fedora-12-i386 --rebuild ../SRPMS/hello-2.5-1.fc12.src.rpm