This section describes how GTK+ and GNOME packages are done on SUSE Linux. After the first part including basic information, there are some subsections describing more complicated or less common features, namely: Gconf, the GStreamer registry, and the shared MIME database.
The following basic rules are defined:
GTK+ version 1.x is deprecated. Packages using GTK+ version 2.x are preferred and should be used whenever possible.
GTK+ and GNOME–based libraries (optionally also applications) should use the same prefix as GTK+/GNOME itself. This helps to prevent prefix clashes. The prefix is currently /opt/gnome, but it will change to /usr in the future. There are few exceptions where files must be explicitly moved to /usr. See Section 10.1.3, “Shared MIME Info”.
According to FHS, configuration files must be located below /etc/opt/gnome and variable data below /var/opt/gnome if the the prefix is /opt/gnome.
GTK+-related -devel packages should be in the RPM group Development/Libraries/X11. GNOME related -devel subpackages packages should be in the group Development/Libraries/GNOME. Both GTK+ and GNOME–related packages providing the parts of libraries needed at runtime should be in the group System/Libraries. The GNOME desktop packages should be in the group System/GUI/GNOME. Finally, the GTK+ and GNOME–related applications should be in a respective subgroup of Productivity.
The packages needed for build must be mentioned in the neededforbuild line and in the BuildRequires tag. Two meta packages are defined: gtk2-devel-packages and gnome2-devel-packages, which can be used in the neededforbuild line. They substitute for packages needed for compilation of packages based on GTK+ 2.x and GNOME 2.x. The meta package gnome2-devel-packages includes only core libraries, including libgnomeprint, but not less common libraries, like gnome-panel, vte, and gail. Some other packages that are required at runtime but not for building are also not included, for example, some gdk-pixbuf loaders, fonts, and font database configuration.
Most GTK+ and GNOME packages use the standard configure, make, and make install technique. It is usually enough to set the right paths with configure options but no other special actions are necessary to locate GTK+ and GNOME. In this way, it is similar to other packages.
The related part of the spec file typically looks like:
%build
%suse_update_config -f
CFLAGS="$RPM_OPT_FLAGS” \
./configure --prefix=/opt/gnome \
--libdir=/opt/gnome/%_lib \
--sysconfdir=/etc/opt/gnome \
--localstatedir=/var/opt/gnome
make
%install
make DESTDIR=$RPM_BUILD_ROOT installIn the example above, see how the $RPM_OPT_FLAGS are usually passed to configure. Also see that the macro %suse_update_config is usually called to update some auto-stuff related files.
Many GNOME packages use helper scripts or binaries installed in the libexec directory. They must call --libexecdir=/opt/gnome/lib/{name} where {name} usually is the package name. lib is used instead of %lib. See Section 4.1, “Biarch Systems” for more details. The configure options usually look like:
./configure --libdir=/opt/gnome/%_lib \
--libexecdir=/opt/gnome/lib/%{name} \
[...]Packages providing GNOME applets can use --libexecdir=/opt/gnome/lib/gnome-applet. The directory is reserved for these applets.
All applications should install a .desktop file to define a menu entry. They must call the macro %suse_update_desktop_file for all installed menu entries in the %install section. This typical example is taken from the package planner:
%install [...] %suse_update_desktop_file %name Office ProjectManagement
Language-specific files (localizations of menu entries, messages, help content, etc.) should be marked with the respective %lang tag in the file list. There is the macro %find_lang for this purpose. It is typically used the following way:
%install
[...]
%find_lang %name
%files -f %{name}.lang
[...]GNOME packages often use the GConf configuration database. It is made from front-end files and back-end files. Only front-end files are included in the file list. Back-end files are generated during installation. This feature is used when a package installs any file to $sysconfdir/gconf.
To use this, the maintainer should first check whether the application installs all schemas files used to $sysconfdir/gconf/schemas. Most packages do it, but there are some buggy packages.
Next, the package must be configured not to create the back-end files within the %install phase. It can be done:
By adding --disable-schemas-install option to configure:
./configure --disable-schemas-install ...
By using of GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL variable:
export GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL=1 make install DESTDIR=$RPM_BUILD_ROOT unset GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL
If both fail, the package needs to be fixed manually.
Finally, the back-end files must be generated in the %post script. do not forget to mention the packages used in the PreReq tag.
This example is taken from the package epiphany. There are two files, epiphany.schemas and epiphany-lockdown.schemas, installed in /etc/opt/gnome/gconf/schemas. The corresponding %post script looks like:
PreReq: gconf2 gnome-filesystem
%post
export GCONF_CONFIG_SOURCE=`opt/gnome/bin/gconftool-2 \
–get-default-source`
opt/gnome/bin/gconftool-2 –makefile-install-rule \
etc/opt/gnome/gconf/schemas/epiphany.schemas >/dev/null
opt/gnome/bin/gconftool-2 –makefile-install-rule \
etc/opt/gnome/gconf/schemas/epiphany-lockdown.schemas \
>/dev/nullThe back-end files are not removed in the %postun script. This is a design problem of GConf. Since SL 9.2, the script gconftool-rebuild, which can be used to rebuild GConf database from scratch, is available.
It is a good practice to avoid globbing in the file list and explicitly list the .schemas files there. This helps to prevent problems after an update. Both the file list and the %post script must be updated if a new .schemas file appears and rpm warns if all installed files are not mentioned in the file list. The file list from the example above should look like:
%files [...] /etc/opt/gnome/gconf/schemas/epiphany.schemas /etc/opt/gnome/gconf/schemas/epiphany-lockdown.schemas
instead of:
/etc/opt/gnome/gconf/schemas/*.schemas
A multimedia package can define its own multimedia plug-in for Gstreamer. This feature is used when the package installs any file to /opt/gnome/%_lib/gstreamer-{version}.
The GStreamer registry must be updated to make the plug-in visible. It should be done in both the %post and the %postun script. Do not forget to mention the utilities used in the PreReq tag. The related code then looks like:
PreReq: /opt/gnome/bin/gst-register [...] %post opt/gnome/bin/gst-register >/dev/null %postun opt/gnome/bin/gst-register >/dev/null
Paths can change in future versions of SuSE Linux.
Packages, except the package gstreamer, must not include the file /var/opt/gnome/cache/gstreamer-{version}/registry.xml. If it is created by make install in $RPM_BUILD_ROOT, it is a bug and the file must be removed.
The shared MIME info is a new standard defined by freedesktop.org. See http://www.freedesktop.org/Standards/shared-mime-info-spec. It is used by new versions of GNOME.
This feature is used when the package installs any file to $datadir/mime and the distribution contains the shared-mime-info package. This package has been part of SUSE Linux since SL 9.2.
The shared MIME database is located in /usr/share/mime and not all applications respect multiple prefix paths. That is why GNOME packages must move the related files from /opt/gnome/share/mime to /usr/share/mime. This can be done with the following code at the end of the %install section:
%install [...] mkdir -p $RPM_BUILD_ROOT/usr/share mv $RPM_BUILD_ROOT/opt/gnome/share/mime $RPM_BUILD_ROOT/usr/share
Some packages call update-mime-database during build. It is a bug that can cause packaging of the actual MIME database instead of its component even if DESTDIR is set. The simplest work-around is to remove the generated files at the end of the %install section. Generally, everything except packages/*.xml are generated files and need to be removed. This example is taken from the package planner:
%install [...] cd $RPM_BUILD_ROOT/usr/share/mime rm XMLnamespaces globs magic application/x-planner.xml
The file /usr/share/mime/packages/planner.xml is left there to be included in the package.
Finally, the shared MIME database must be updated in the %post and %postun scripts. Do not forget to mention the needed packages in the PreReq tag. The related code then looks like:
PreReq: shared-mime-info [...] %post usr/bin/update-mime-database /usr/share/mime >/dev/null %postun usr/bin/update-mime-database /usr/share/mime >/dev/null
MIME types can be tested by the package nautilus. It is enough to install the tested package, start or restart Nautilus, and look at properties of a corresponding file. The installed MIME type should be defined properly there.
Older GNOME packages use mime-info for MIME type definitions. Such MIME types are not recognized by new version of GNOME. The package needs shared-mime-info, too. This feature is used when the package installs files in /opt/gnome/share/mime-info. If there are no files in /usr/share/mime (possibly moved from /opt/gnome/share/mime, see Section 10.1.3, “Shared MIME Info”), the shared-mime-info must be generated from mime-info.
The conversion can be done either by the script mime-info-to-mime provided by the package shared-mime-info, it can be called the following way in the %install section:
%install [...] DESTDIR=$RPM_BUILD_ROOT mime-info-to-mime
Or if the command fails, the generated files $RPM_BUILD_ROOT/usr/share/mime/packages/*.xml need to be manually edited. The fixed files are usually added to the package as an extra source and installed in the %install section. This example is taken from the package file-roller:
Source1: file-roller.xml
[...]
%install
[...]
mkdir -p $RPM_BUILD_ROOT/usr/share/mime/packages
cp %{S:1} $RPM_BUILD_ROOT/usr/share/mime/packagesFinally, the new files must be listed in the %files section and the Shared MIME database must be updated in the %post and %postun scripts. See Section 10.1.3, “Shared MIME Info”.
This section describes how the kernel modules are packaged on SUSE Linux. More detailed information about the kernel can be found at http://www.suse.de/~agruen/kernel-doc/.
On SUSE Linux, packages providing kernel modules do not build them themselves. They create a subpackage with the kernel module sources (a binary RPM package with sources). Such packages are then installed when the kernel is built and the kernel modules are built together with the kernel binaries. Then the modules distributed under GPL are even packaged together with the kernel binaries. The others are put into a separate package with a name suffixed by -nongpl.
This approach has some advantages:
Kernel modules can be simply updated together with kernel. It helps to keep the system consistent for example after an security update.
Packages providing kernel modules need not build the modules for all available kernels. It simplifies the maintenance because the packages need not be touched because of a new specific kernel.
The following rules are defined for subpackages with kernel module sources:
The package name is kernel-XXX where XXX is something close to the module name. See also Section 1.6, “Name Tag”.
The sources necessary to build the module are installed into /usr/src/kernel-modules/module_name.
/usr/src/kernel-modules/module_name/Makefile must also be included and provide targets: modules, install and clean. See below for more details.
The following example is taken from the package drbd, which provides a kernel module of the same name. Here are the related parts from drbd.spec:
Source1: Makefile.module
[...]
%package -n km_drbd
Summary: Sources for the drbd Kernel Module
Group: Development/Sources
%description -n km_drbd
Sources for the drbd kernel module used to build SUSE kernels.
Authors:
--------
Philipp Reisner <philipp.reisner@linbit.com>
Lars Ellenberg <lars.ellenberg@linbit.com>
[...]
%install
[...]
mkdir -p $RPM_BUILD_ROOT/usr/src/kernel-modules/
cp -a drbd/. $RPM_BUILD_ROOT/usr/src/kernel-modules/drbd/
cp -a %{SOURCE1} \
$RPM_BUILD_ROOT/usr/src/kernel-modules/drbd/Makefile
# Clean up, if anything was around by accident...
find $RPM_BUILD_ROOT/usr/src/kernel-modules \( -name '*.orig' \
-o -name '*~' -o -name '.svn' \) \
-print0 | xargs -0 rm -rf
[...]
%files -n km_drbd
%defattr(-,root,root)
%dir /usr/src/kernel-modules
/usr/src/kernel-modules/drbdThe required Makefile can already be a part of the original sources or it must be added to the package as an extra source. The example above shows the second variant.
The Makefile must provide the following targets:
modules — build the modules
install — install the modules
clean — clean up the source tree
The Makefile must use the following variables instead of exact paths. The variables are set correctly when the Makefile is called within the kernel and its modules are being built:
KERNEL_SOURCE — defines the path to kernel sources
INSTALL_MOD_PATH — defines the directory in which to install the modules
The target modules must be built with the following command to keep compatibility with regular kernel Makefiles:
$(MAKE) -C $(KERNEL_SOURCE) modules SUBDIRS=$(CURDIR)
The targets install and clean are added to improve convenience and consistency. This requires changes to the kernel build system that are done currently only in the SUSE kernel.
This is a template that can be used to create the required Makefile in km_* packages:
# Add the kernel makefile definitions first... # Set the place where to install the module(s) # below lib/modules/`uname -r`, it defaults to "extra". MOD_DIR := some/where .PHONY: modules install clean modules_add install : modules_add modules modules_add clean: $(MAKE) -C $(KERNEL_SOURCE) $@ SUBDIRS=$(CURDIR)
This real example is taken from the package drbd. The file is installed as /usr/src/kernel-modules/drbd/Makefile:
#
# SUSE specific makefile for the km_drbd
#
EXTRA_CFLAGS += -I$(src)
obj-m := drbd.o
drbd-objs := drbd_buildtag.o drbd_bitmap.o drbd_fs.o \
drbd_proc.o drbd_worker.o drbd_receiver.o \
drbd_req.o drbd_actlog.o lru_cache.o drbd_main.o
# Set to something different to install somewhere else:
# MOD_DIR := extra
.PHONY: modules install clean modules_add
install : modules_add
modules modules_add clean:
$(MAKE) -C $(KERNEL_SOURCE) $@ SUBDIRS=$(CURDIR)This section describes how Perl modules are packaged on SUSE Linux. The following rules are defined:
Each Perl module should be in a separate package.
The package name should be perl-XXX, where XXX is the original name of the source tarball. See also Section 1.6, “Name Tag”.
The RPM group should be Development/Libraries/Perl.
The package should require Perl of the same version as was used for build. The macro %perl_version serves this purpose.
A dependency on Perl modules is not detected automatically. This means the packages must mention the necessary Perl modules in the Requires tag. This applies to the dependency between Perl modules as well.
The package perl need not be mentioned in the neededforbuild line because it is in the default set. However, it should be mentioned in the BuildRequires tag. This does not apply to the Perl modules. They must be mentioned in both places.
This example of a typical spec file preamble comes from the package perl-Inline-CPR:
# norootforbuild
# neededforbuild perl-Inline perl-Parse-RecDescent
# usedforbuild ... perl perl-Inline perl-Parse-RecDescent ...
Name: perl-Inline-CPR
License: Artistic License
Group: Development/Libraries/Perl
Version: 0.12
Release: 151
Autoreqprov: on
Requires: perl = %{perl_version}
Requires: perl-Inline
Summary: Write Perl subroutines in C
URL: http://cpan.org/modules/by-module/Inline
Source: Inline-CPR-%{version}.tar.bz2
Patch: Inline-CPR-%{version}.diff
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
This module allows you to program C in perl. See also perl-Inline.
Authors:
--------
Brian Ingerson <INGY@cpan.org>In the example above, see that two other Perl modules are needed for build and at run-time. They are mentioned by the neededforbuild line, BuildRequires tag, and the package perl-Inline is mentioned by the Requires tag. The second package perl-Parse-RecDescent need not be mentioned by the Requires tag because it is required already by perl-Inline.
Most Perl modules are built and installed a standard way. In addition, the macros %perl_make_install, %perl_process_packlist, %perl_vendorarch, and %perl_vendorlib are available. This makes it extremely easy to create a package. This approach is also used in the package perl-Inline-CPR from the example above. Here is the rest of its spec file:
%prep
%setup -n Inline-CPR-%{version}
%patch
%build
perl Makefile.PL
make
make test
%install
%perl_make_install
%perl_process_packlist
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-, root, root)
%doc Changes README MANIFEST
%{perl_vendorlib}/Inline/CPR*
%{perl_vendorarch}/auto/Inline/CPR
/var/adm/perl-modules/%{name}In the example above, see how the macro %perl_process_packlist is used. It removes $RPM_BUILD_ROOT from some files and allows packing the file %perl_archlib/perllocal.pod as /var/adm/perl-modules/%{name}. See Section 3.15, “%perl_process_packlist” for more details.
SuSEconfig --module perl should be called after installing the package. It updates the %perl_archlib/perllocal.pod from the information saved in /var/adm/perl-modules. It is not called from the %post script because it would take ages if several packages are installed at once and each of them called this script independently.
If a module includes a part written in C, the $RPM_OPT_FLAGS can usually be passed the following way. The example is taken from the package perl-Bit-Vector:
%build perl Makefile.PL OPTIMIZE="$RPM_OPT_FLAGS -Wall" make make test
This section describes how Python modules are packaged on SUSE Linux. The following rules are defined:
Each Python module should be in a separate package.
The package name should be python-XXX. See also Section 1.6, “Name Tag”.
The RPM group should be Development/Libraries/Python.
The package should require Python of the same major version as was used for build. This avoids problems when upgrading Python. The macro %py_requires exists for this purpose. See how it is used in the example below.
The packages python and python-devel are usually needed to build. They need to be mentioned in the line neededforbuild and defined in the tag BuildRequires.
This example of a typical spec file preamble comes from the package python-numeric:
# norootforbuild
# neededforbuild python python-devel
BuildRequires: aaa_base ... python python-devel ...
Name: python-numeric
License: BSD, Python
Group: Development/Libraries/Python
Version: 23.3
Release: 1
Autoreqprov: on
%py_requires
Summary: A Numerical Extension to Python
URL: http://sourceforge.net/projects/numpy
Source: Numeric-%{version}.tar.bz2
Patch: Numeric-%{version}-noatlas.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
Numerical Python adds a fast and compact multi-dimensional array
language facility to Python.
Authors:
--------
numpy-developers@lists.sourceforge.netMost Python modules use distutils now, so it is extremely easy to package them. This feature is documented at http://www.python.org/sigs/distutils-sig/. It is also used in the package python-numeric from the example above. Here is the rest of its spec file:
%prep
%setup -n Numeric-%{version}
%patch
%build
export CFLAGS="$RPM_OPT_FLAGS"
python setup.py build
%install
python setup.py install --root=$RPM_BUILD_ROOT \
--record-rpm=INSTALLED_FILES
%clean
rm -rf $RPM_BUILD_ROOT
%files -f INSTALLED_FILES
%defattr(-,root,root)
%doc README changes.txt DemoIn the example above, see how the variable $RPM_OPT_FLAGS is usually used to build binaries. Also see in the install command that the option --record-rpm can be used to create a file list that is then used in the %files section. This feature currently exists only in SUSE Python packages. A patch for upstream is waiting for review.
If a package uses a nonstandard build method, the special RPM macros %py_ver, %py_incdir, %py_libdir and %py_sitedir can be used to get the location of Python directories.
This example is taken from the package python-fcgi:
Source0: http://alldunn.com/python/fcgi.py
[...]
%prep
%build
%install
install -m755 -d $RPM_BUILD_ROOT/%{py_sitedir}
install -m644 %{S:0} $RPM_BUILD_ROOT/%{py_sitedir}
python%{py_ver} %{py_libdir}/compileall.py -d %{py_site}/ \
$RPM_BUILD_ROOT/%{py_sitedir}
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%{py_sitedir}/fcgi.py*