Building RPMs - Quick Start

From Rosalab Wiki
Revision as of 21:08, 6 November 2014 by CaptainFlint (Talk | contribs) (typos)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
This document contains a brief but complete overview of RPM package creation for ROSA Desktop distributions. The document doesn't reflect all aspects of packaging, for more details please take a look at the documents mentioned at the bottom of this page.

Getting ready for the build and overview of the spec file

First, let's check what do we need in our system to build an rpm package. It is necessary to install rpm-build package that provides the rpmbuild command. Along with it, a bunch of other packages will be automatically installed that are used during the build. In ROSA we normally don't mention C/C++ compiler as explicit build requirement for every package, so it is not installed automatically and sooner or later you will have to install gcc and gcc-c++ packages. All other packages required to build particular package should be required by the spec file of the package being built. Surely, there can be error in build requirements and during the build you will notice that missed something, but such issues easy to fix.

And what is an RPM package? One should distinguish RPM packages with sources (src.rpm) and packages with compiled programs tha are ready to be installed to the user's system %{arch}.rpm. Src.rpm packages contain tarball with program source code, patches and spec file that controls the build process. All this files are archived using cpio. You can see this archive if you enter inside rpm package using mc file manager. The package can also contain some otheradditional files.

%{arch}.rpm packages contains cpio archive with program files that will be placed to proper folders during package instalation, different metadata and installation scripts.

You can also meet packages without source code inside. They are usually created for proprietary software which cannot be included into distribution (sources are not availavble, and the binary files should be preliminary adopted for particular system or it is just prohibited to out them to the distribution mirrors). Such a package often contain only a spec file. Binaries are downloaded from upstream during the package installation process (for example, inside a post script, which will be discusse later).

One can build packages under any user. However, it is not recommended to build packages under the root account, since there is a little chance that erroneous installation will use root folder (/) as installation root and then commands like rm -rf %{buildroot} will destroy the whole system. It also happens that malformed packages incorrectly install their packages not in the temporary folder, but somewhere in %{_prefix} (/usr). This will lead to a system pollution and can even lead to loss of important files.

What should user do to be able to build packages? First, it is necessary to go to the home folder and create rpmbuild folder there with the following structure:

~/rpmbuild
|-- BUILD
|-- BUILDROOT
|-- RPMS
|   |-- i586
|   |-- x86_64
|   `-- noarch
|-- SOURCES
|-- SPECS
`-- SRPMS

You should create BUILD, RPMS, SOURCES, SPECS, and SRPMS folders manually, RPMS subfolders will be created automatically during the package build.

In ROSA it is not recommended to explicitely mention packager and vendor in the spec; these tags are set automatically by the ABF build system. ABF also automatically signs every package that goes to official repository. So we won't consider package signing here.


Now let's take a look at the main file of the package - spec-file. Let's take a spec from the stardict package which is a good example, since it contains several tarballs (files with program soruces archived with tar), produces several subpackages and has some additional scripts. Usually spec file has the same name as the package itself- (stardict.spec). Though you can add package version if you are going to maintain several versions at once - (stardict-2.spec). Actually you can use any name, but this is not convenient and not recommended.

Content of the stardict.spec is shown below. We will insert our comments directly after each section of the spec, but if you simply join all the sections into a single files, you will get a complete stardict.spec.

Spec-file contains several sections and heading:

Summary:        StarDict dictionary
Name:           stardict
Version:        2.4.8
Release:        4
License:        GPL
URL:            http://stardict.sourceforge.net
Group:          User Interface/Desktops
Source0:        %{name}-%{version}.tar.bz2
Source1:        %{name}-tools-%{version}.tar.bz2
Patch0:         %{name}-2.4.8-desktop.patch

Tag names are self-explanatory. You can easily get access to the Name, Version and Release tags anyhwhere in the spec using corresponding macros - %{name} , %{version} , %{release} . Name and Version are usually reflected in the tarball name. If they are not, you will have to use some tricks inside your spec to unpack the tarball. If you build a package on the basis of snapshot of CVS, SVN or other VCS, then it is recommended to define a variable equal to the snapshot date in the beginning of the file %define date 20070422 and form the Release tag in the following way:

Release: 0.git%{date}.4

Next we see a License as specified by software vendor, URL of a program site and a software Group the package belongs to. To choose a group, you can look at similar packages and check which group they use, or just choose a group from the groups used in ROSA.

Source* — files with source code (either tarballs or regular files). In our example we have two tarballs with different programs; this significantly complicates the build. Regular files )(e.g., configs) can be simply copied to the destination in the %%install section by means of install command. It has a vert straightforward syntax: install -m file_mask_in_chmod_style src dst. It can be used to create folders, as well. We don't use this command in our example; you can read more about it in its man page.

Patch — patches that should be applied to the original source code. It isn't acceptable to modify the code of the program itself and pack it back to the tarball - this will really complicate program updates. Standalone patches are used instead. They can be made in the following way. Unpack the source tarball (stardict-2.4.8 in our case) and copy stardict-2.4.8 to stardict-2.4.8.orig. After this, make necessary changes in the stardict-2.4.8 folder, leave it and launch diff -ur stardict-2.4.8.orig stardict-2.4.8 > stardict-2.4.8-patch_name.patch. As one can see, the patch hash %{name}-%{version} prefix - this is the recommeded way of patch naming. In the spec file it is recommended to type patch name without macros (at least do not use version). Otherwise after vesion update you will get an updated version macro and rpmbuild will look for a new patch name, while it's likely that the patch canbe applied to a new version without any changes. If the patch fails to apply to the new version, you should find the reasons and either update for the new program or just drop it.

In spec files of many distribution you can also meet definition of BuildRoot - a folder that should be used for the build. In ROSA, there is no need to define BuildRoot, its name is formed automatically.

BuildRequires:  libgnomeui-devel >= 2.2.0
BuildRequires:  scrollkeeper
BuildRequires:  gettext
Requires(post):   GConf2
Requires(post):   scrollkeeper
Requires(postun): scrollkeeper

BuildRequires section lists packages that are required to build our program. You can create such a list on the basis of README or INSTALL files from the program (though they rarely contain anything useful for this), from the configuration script (usually configure) and tfrom the build process itself (it happens that configure misses checks for some deopendencies and build fails).

Requires — this section lists packages and files that should exist in the system for successful package installation. Rpmbuild automatically detects and sets dependencies on libraries, but you can also add dependencies manually. Rpm also automatically adds dependencies on perl, python, mono and some other staff (to be sure, these dependencies are added to the package itself, not to the spec). If you don't want dependencies to be added automatically, you should add AutoReq: no to your spec. It is often used for proprietary programs with a lot of internal libraries, since rpm may erroneously add dependency on something which is built into the program itself.

In our example we use Requires(post) and Requires(postun) to indicate dependencies necessary for post-install and post-uninstall scripts. It would also work to simply write Requires, but these dependencies are not needed for StarDict istelf, tey are required only to install/uninstall it. So this is just a matter of neatness.

There are some other useful tags which we haven't used in our example.

Provides: name1, name2

- other names besides %{name} that can be used to reference this package. This is convenient if you change the package name but there are other packages requiring the old name.

Obsoletes: name1, name2

— indicates that these packages can be removed after instalation of this package, since it provides the same functionality, set of files, etc. One can use limitation on versions of packages that are obsoleted - name <. Hopefully this is self-explanatory.

Conflicts: name1, name2

— list of packages that conflict with the current one. Such packages should be removed in order for the current one to be installed. Here you can use name <, as well.

Suggests: name1, name2

- soft dependencies - packages that supply the current package with somme additional functionality (e.g., additional codecs for media players) but which are not obligatory to install and use the package.

Epoch: number

— usually not set or set to 0. The aim of this parameter is like the following. Assume that our stardict package has version 2.4.8 and there is an older package with version 2.4.5. However, if stardict 2.4.5 has %{epoch} equal to 1 and 2.4.8's epoch is equal to 0, then stardict-2.4.5 will be considered by RPM to be newer than stardict-2.4.8. This trick is used if one needs to downgrade the package in repository so it will be automatically downgraded by urpmi or rpmdrake in users' systems during the next update. If Epoch is set to zero, then the package is considered to be newer than the same package without Epoch.

BuildArch: architecture

— target hardware architecture. If this option is not set, the current system architecture will be used. Usually this option is used to indicate noarch packages that don't contain arch-specific binary files.

ExclusiveArch: architecture1 architecture2

— indicates that the package can be built only for these architectures. Often used when building kernel modules.

Here the heading ends. Let's proceed with different sections

%description
StarDict is an international dictionary written for the GNOME environment.
It has powerful features such as "Glob-style pattern matching," "Scan
seletion word," "Fuzzy search," etc.

Description of the main package which will be named as %{name}

%package tools
Summary:        StarDict-Editor
Requires:       %{name} = %{version}-%{release}
Group:          User Interface/Desktops

Here we define a subpackage named %{name}-tools. If you want to use a completely different name, you can define it like the following: %package -n tools-stardict. Subpackage versionis set from the Version macro. Note that we have a Requires record mentioning the main package - stardict. If it had %{epoch} , then it would be necessary to use Requires: %{name}-%{epoch}:%{version}-%{release} , otherwise the package would fail to update.

%description tools
A simple tool for StarDict.

Subpackage description

%prep
%setup -q -a1
%patch0 -p1

The %prep section contains preparation steps performed before the build. %setup unpacks the source code tarballs. -q option suppresses the output of unpacking process. -a1 forces unpacking of %{SOURCE1} inside(!) the folder extracted from the first tarball (a number after the option stands for the SOURCE number). Alternatively, -b option can be used to unpack second tarball to the same folder as the first one. If you have only one tarball then neither -a nor -b are used.

If name of the folder extrated from the first tarball differs from %{name}-%{version} then rpmbuild will fail to enter inside it. In this case you should modify %setup a little. If stardict-2.4.8.tar.bz2 the top-level folder is named stardict then setup should look like te following:

%setup -q -n %{name} -a1

Just after tarball unpacking and before invocations of the %patch macro you can copy additional files or launch some utilities to modify the program sources. For example, copy additional localization files or use sed to quickly fix some soure files. Just call cp, sed and other commands. Remember that the working folder for these operations is the one where the first tarball is unpacked (name of this folder is stored in the $RPM_BUILD_DIR variable, but it is used very rarely).

The %patch macro is used to apply patches. If you created a patch in the way we described above, then you should pass -p1 option to the macro. The -b .patch_name is also often used to create a backup copy of the patched files.

%build
pushd %{name}-tools-%{version}
%configure
%make
popd
%configure
%make

In the %build section the build itself takes place. Draw attention to the pushd and popd commands. They are used to enter the folder from the second tarball and leave it after the build. So after the pushd, that folder becomes current. popd returns us to the folder of the first tarball. If you have only one source tree, there is no need in these commands.

Since we have two programs in one package, we call %configure and make twice. If the program should be configured using autotools, then the %configure macro launches configure script from the unpacked tarball. It usually has a lot of parameters that can be viewed in command line by means of ./configure --help. You can pass necessary options just after the %configure macro. Note that invocation of %configure differs from direct launch of ./configure. In the first case some additional parameters will be passed automatically, such as installation paths, while in the second case default values will be used.

Successful configuration is followed by the build - the %make macro that calls a command with the same name and passes some additional parameters to it (in particular, on multicore systems parallel make is invoked using the -j option).

If the program doesn't use autotools, then %configure (and maybe %make) are not necessary; please refer to README and INSTALL files of the program for details. ROSA provides macros for some other common cases e.g., %cmake macro for the case when cmake should be used.

If the build is completed successfuly, rpmbuild proceeds with the %install section.

%install
pushd %{name}-tools-%{version}
%makeinstall_std
popd
%makeinstall_std
%find_lang %{name}

%%find_lang is used to look for localization files. It takes name of localization files as a parameter and looks for appropriate files in %{buildroot}/usr/share/locale/*/LC_MESSAGES/*.mo. Usually this name is equal to %{name} . If not, pass necesasry name to find_lang.


In many spec files you can see that rm -rf %{buildroot} or rm -rf $RPM_BUILD_ROOT is performed in the beginning of %install, as well as the %clean section with the same commands. In ROSA there is no need in such clean up, it is performed automatically.

%preun
%preun_uninstall_gconf_schemas %{name}

These are sections with installation scripts. There are four kinds of such scripts: %pre is launched before installation, %post — after installation, %preun — before removal, %postun — after removal. In our example we remove Gconf schema and assume that we the package has only one schema whose name is equal to the package name. Note that we use a special macro to remove schemas; this macro is expanded by rpmbuild in ROSA to a set of shell commands. Installation of schemas is performed automaticaly by RPM using the file trigger mechanism.

You can write usual Bash scripts in these sections (as well as in any other section of the spec). If you don't need to perform any actions of such kind, just omit pre/post sections in your spec.

In the %files sections one shoud declare which files should be included in every package or subpackage. Every installed file should be assigned to some package, otherwise rpmbuild will report unpackaged files and fail.

-f is used to specify a file with list of files to be included. In our case we specify a file with a list of localization files.

Specialized macros are used for system folders:

  • %{_prefix} /usr
  • %{_sysconfdir} /etc
  • %{_bindir} /usr/bin
  • %{_datadir} /usr/share
  • %{_libdir} /usr/lib or /usr/lib64, depending on system architecture
  • %{_lib} /lib or /lib64 corerspondingly
  • %{_libexecdir} /usr/libexec
  • %{_includedir} /usr/unclude
  • %{_mandir} /usr/share/man
  • %{_sbindir} /usr/sbin
  • %{_localstatedir} /var.
%files -f %{name}.lang
%defattr(-, root, root)
%doc AUTHORS COPYING INSTALL README NEWS
%{_sysconfdir}/gconf/schemas/stardict.schemas
%{_bindir}/stardict
%{_bindir}/stardict-editor
%{_libdir}/bonobo/servers/GNOME_Stardict.server
%{_datadir}/applications/*.desktop
%{_datadir}/stardict
%{_datadir}/locale/*/LC_MESSAGES/*
%{_datadir}/pixmaps/stardict.png
%{_datadir}/gnome/help/%{name}/*
%{_datadir}/idl/GNOME_Stardict.idl
%{_datadir}/omf/*
%doc %{_mandir}/man?/*

%doc marks files as documentation. The third line copies these files to the %{_datadir}/doc/%{name}-%{version} folder.

By default, files in the package will be owned by root and their access permissions will be the same as set during the installation. If owner or permissions should be changed, use %defattr.

After these lines, a simple enumeration of files follows.

%files tools
%{_bindir}/stardict-editor

The same for stardict-tools subpackage. If it were called tools-stardict then %files would look like the following:

%files -n tools-%{name}.

The last section in the spec is %changelog. It contains a list of changes with respect to the previous version and usually formatted in the following way:

%changelog
* Sun Apr 22 2007 Your Name <your@email> - 2.4.8-4
- update desktop patch


Macros

Now it's time to get familiar with macros and variables. For example, assume that we are building a package from SVN snapshot and want to include snapshot date to release. In order to do this, we define a variable in the beginning of the spec:

%define date 20070612

As you may see, variables are introduced through the %define macro. Now anywhere in spec file you can refer our variable as %{date} (braces are not obligatory, but in ROSA we have agreed to enclose variables with braces but leave macros without them, so so it is easier to distinguish variables from macros). In particular, definition of Version and relese will look like the following:

Version: 0.5
Release: 0.svn%{date}.3

Note that 0. is appended before the date, and only after the date we append a number which is incremented in case we want to increment the release. Why do we follow this way? The thing is that when the final version is released (0.5 in our case), revision number will be removed and release will be set to 1. Since 1 is literally greater than any string starting with 0, the resulting package will be considered to be newer than preliminary packages built from SVN snapshots.

One of the frequently used things is conditional operator:

%if condition
  action1
%else
  action2
%endif

Or the same without %else. This construction is straightforward - if condition is true, then action1 is executed, otherwise action2 is launched.

Assume again that we are building something from SVN snapshot. Very often archives created from SVN contains a folder named %{name}-%{version} , not %{name}-%{version} (the sim-0.9.5.tar.bz2 tarball has sim folder inside, since sim 0.9.5 is not released; tarball with the final release will contain a folder named sim-0.9.5). To avoid necessity to modify spec file every time, you can use the following construction:

%define svn 1
...
%prep
%if %{svn}
%setup -q -n %{name}
%else
%setup -q
%endif

If svn variable is not set, then instructions in the %else branch will be launched. One can use stricter conditions: (do not forget about commas):

%define svn 1
...
%prep
%if "%{svn}" == "1"
%setup -q -n %{name}
%else
%setup -q
%endif

Inside every section of the spec we can use any Shell command "as is", but it's not so easy for the spec heading. For example, assume that we need to detect Firefox version for some package (e.g., epiphany) to put it to the Requires:. This will look like the following:

Requires:       firefox = %(rpm -q firefox --qf "%%{version}")

Note that external command is laucnhed using %() (almost like in Bash - $()) in spec and parameters are passed using double %. You can execute any Linux command in this way.

One more popular macro is %ifarch .. %endif construction. Actions inside this block are executed only if architecture matches the one specified after %ifarch. Architectures include x86_64, %{ix86} (a macro that expands to a list of supported x86 platforms) and others

As we have already noticed, in every spec file section you can use all Shell commands such as for, while, if, etc.

Building a package

Now let's actually build a package. Tarballs with sources and patches should be put to the SOURCES file, a recommended places for spec files is the SPECS folder. After this you can simply type:

 rpmbuild -ba spec-file

and the build will be started. If it succeeds, then you will find resulting binary packages in the approrpiate subfolder of the RPMS directory and the source RPM in the SRPMS directory.

Often at the end of the build rpmbuild reports installed but unpackaged files. This means that you forgot to mention that files in the %files sections. Just add them there. But if you don't want these files to be included in the package, use one of the following tricks:

  • Add the followin line to the %files section:
%exclude path_to_file/file
  • Add the following line to the beginning of the spec:
%define _unpackaged_files_terminate_build 0

If you want to build only binary or only source rpm, replace -ba with -bb or -bs correspondingly. From other useful rpmbuild parameters one can mention -clean (remove all temporary files after the packages are made), --rmsource (remove sources from SOURCE) after build and -target=architecture (build package for given architecture).

You can also launch only particular section. We won't describe such parameters here, see man rpmbuild for more details.

Rebuilding RPM package from the installed one

It sometimes happens that a package is already installed in your system but you can't find rpm package itself anywhere, or you may want to rebuild some installed package with different configs.

This problem can be solved by means of rpmrebuild tool. This is actually a Bash written and it is available in the ROSA contrib repository.

The tool is very easy to use. Just type:

rpmrebuild name_of_installed_package

If some file has beed modified since the installation, you will be informed about this, but this won't be treated as error.

Rpmrebuild has a lot of options - for example, you can change package release, changelog, scripts, Requires sections, description and a lot of other characteristics. You can even reuse a spec file which will be generated by the script. Though it will look a little ugly, but it's better than nothing.

You can get the whole list of parameters using

rpmrebuild --help

and

rpmrebuild --help-plugins


See Also

Packaging_HowTo

ROSA Packaging Guidelines


Idea.png
Note

This page is based on several posts from the "Notes about Linux" blog: