Build Service/cross distribution package how to
From openSUSE
Contents |
Overview
This howto lists special hints to work with one spec file for different distributions. It is not a beginners guide for packagers, please visit the SUSE Build Tutorial for this instead. Also, this document does not cover distributions that use Debian packages.
The Build Service can reliably package rpms for not only Suse, but also recent CentOS, Fedora, Red Hat Enterprise Linux and Mandriva distributions.
What are the limitations ? The only practical limit is not having certain dependencies satisfied for Fedora or Mandriva, where they can be easily satisfied for Suse distributions by linking or aggregating to another Build Service project. An example: It is easy to build packages for Suse which require the latest versions of Qt4 or GTK2, as these dependencies can be satisfied by other repos on the Build Service which provide backports of newer Qt4 packages for older Suse versions, as well as SLES. This can only be overcome by also packaging the needed dependencies within your own project. Even then, this is only an issue if you wish to support as many distributions as possible.
Some 'gotcha' differences between distributions which you need to pay attention to:
- Installing desktop files. Each of the five distros use somewhat different mechanisms for installing desktop files and then creating the menu entries. Mandriva even has a special rpm macro %update_menus to accomplish this, which uses a Debian-like setup, different from Suse or Fedora. Example:
%post %update_menus %postun %clean_menus
- Package naming for dependencies. See below for more specific hints and tricks to make this work in your spec file.
- Subtle differences in rpm macros. Link with a table showing the variations below.
Can you point me to good example of a cross-platform package ?
Amilcar's KDevelop Package Build Server Login required.
Detect a distribution flavor for special code
You can add
%if %{defined suse_version}
%if %{undefined suse_version}
or more portable:
%if 0%{?suse_version}
<suse stuff here>
%else
<other distros>
%endif
to check if the current build is for a suse distribution or not. Note that Fedora uses "%{fedora}" without "_version". You can also check for which SUSE distribution by using
%if 0%{?suse_version} > 930
for instance to execute something for everything after SUSE Linux 9.3. Similar checks for other distributions exist as well.
%if %{defined fedora_version}
%if %{defined mandriva_version}
%if 0%{?fedora_version} < 5
%if 0%{?mandriva_version} > 2006
Note that rpm prefers:
>=
vs.
=>
You can also exclude one particular version:
%if 0%{?rhel_version} != 406
You can combine multiple distributions in a single if block like this:
%if 0%{?fedora_version} || 0%{?rhel_version} || 0%{?centos_version}
<yourstuff>
%endif
You can also select a special architecture using e.g.:
%if 0%{?suse_version} == 1030
%ifarch x86_64
<yourstuff>
%endif
%endif
The following overview helps to choose correct settings:
| Distribution | Variable | Comment |
|---|---|---|
| openSUSE Factory | %if 0%{?suse_version} > 1110 | current upcoming release (changing) |
| openSUSE 11.1 | %if 0%{?suse_version} == 1110 | |
| openSUSE 11.0 | %if 0%{?suse_version} == 1100 | |
| openSUSE 10.3 | %if 0%{?suse_version} == 1030 | |
| openSUSE 10.2 | %if 0%{?suse_version} == 1020 | |
| SUSE Linux 10.1 | %if 0%{?suse_version} == 1010 | |
| SUSE Linux 10.0 | %if 0%{?suse_version} == 1000 | |
| SUSE Linux 9.3 | %if 0%{?suse_version} == 930 | |
| SLES 9 | %if 0%{?sles_version} == 9 | also set: %if 0%{?suse_version} == 910 |
| SLE 10 | %if 0%{?sles_version} == 10 | also set: %if 0%{?suse_version} == 1010 |
| SLE 11 | %if 0%{?sles_version} == 11 | also set: %if 0%{?suse_version} == 1110 |
| CentOS 5 | %if 0%{?centos_version} == 501 | |
| RHEL 4 | %if 0%{?rhel_version} == 406 | |
| RHEL 5 | %if 0%{?rhel_version} == 501 | |
| Fedora 6 with Extras | %if 0%{?fedora_version} == 6 | |
| Fedora 7 with Extras | %if 0%{?fedora_version} == 7 | |
| Fedora 8 with Extras | %if 0%{?fedora_version} == 8 | |
| Fedora 9 with Extras | %if 0%{?fedora_version} == 9 | |
| Fedora 10 with Extras | %if 0%{?fedora_version} == 10 | |
| Fedora 11 with Extras | %if 0%{?fedora_version} == 11 | |
| Mandriva 2006 | %if 0%{?mandriva_version} == 2006 | |
| Mandriva 2007 | %if 0%{?mandriva_version} == 2007 | |
| Mandriva 2008 | %if 0%{?mandriva_version} == 2008 | |
| Mandriva 2009 | %if 0%{?mandriva_version} == 2009 | |
| Mandriva 2009.1 | %if 0%{?mandriva_version} == 200910 | |
| Mandriva 2010 | %if 0%{?mandriva_version} == 201000 |
Install info files
Info files should get installed by using the %info_add and %info_del macros. For example
%post
%info_add %{name}.info
%pre
%info_del %{name}.info
Please note that the info files get compressed on some distros as .gz and as .bz2 at some others. You can use %ext_info for the file suffix in the file list.
Handling dependencies
Different distributions often use different names for packages, so the Requires: and BuildRequires: tags may need to vary from repository to repository. It is possible to specify package name substitutions in the configuration of a project e.g.
%if 0%{?fedora_version}
Substitute: libnetcdf-devel netcdf
%endif
In order to change your project configuration write text similar to the above in file (called "config" in my example) and upload it using curl
curl -u user:pass -X PUT -T config 'https://api.opensuse.org/source/home:user/_config'
This can probably achieved via the command line client as well (but not with the web client).
Finding Qt 3.x on Fedora
Redhat/Fedora uses a different naming scheme and build setup to use Qt to build other apps. Here is an example from a spec file to build Qt based apps on both Suse and Fedora in one spec file:
BuildRequires: cups cups-devel python-devel shared-mime-info libart_lgpl-devel libtiff-devel libxml2-devel
BuildRequires: fontconfig-devel openssl-devel pkgconfig desktop-file-utils qt-devel
%if 0%{?fedora_version} >= 5
BuildRequires: libstdc++-devel gcc-c++ lcms-devel >= 1.12 qt
%endif
%if 0%{?suse_version} > 910
BuildRequires: update-desktop-files
%endif
Then:
%if 0%{?fedora_version} >= 5
source "%{_sysconfdir}/profile.d/qt.sh"
%endif
%configure \
%if 0%{?fedora_version} >= 5
--with-xinerama \
--with-extra-libs=%{_libdir} \
%endif
%if 0%{?suse_version} > 910
--with-qt-libraries=/usr/%_lib/qt3/%_lib \
--with-docdir=%{prefix}/share/doc/packages/scribus \
%ifarch x86_64 ppc64 s390x
--enable-libsuffix=64 \
%endif
%endif
<programoptions>
Finding Qt4 on Mandriva
By default, Qt3 will be found before Qt4, so simply add this to the %build section of your spec file:
%build
%if 0%{?mandriva_version} > 2006
export PATH=/usr/lib/qt4/bin:$PATH
export QTDIR=%{_prefix}/lib/qt4/
%endif
- This may have changed on Mdv 2008
Handling Mandriva Provides/Obsoletes
Special care is needed when handling Mandriva, as unlike CentOS, RHEL, Fedora or Suse, they often create separate library rpms for many apps which use these libraries privately. Application foo may also have a dependency on libfoo or libfoo-0. Thus, you need to check Mandriva original spec files if they have explicit Provides and Obsoletes to prevent conflicts on install. Even though RPM handles dependencies automatically if you add Autoreqprov: on in the spec file ( good idea anyways) you still may need to explicitly added these like below:
%if 0%{?mandriva_version}
Provides: foo libfoo-0
Obsoletes: foo libfoo-0
%endif
Building on Older Distros
While sources in a package can build on older distros, the way packages are built sometimes evolve in an incompatible way.
For example, when calling autoreconf -fi (as is commonly done in spec files), it happens (due to the -i for install) that the tarball's versions of config.sub, config.guess and ltmain.sh are replaced with the versions from the autoconf package of the target build platform. This can mean that files from the year 2007 are replaced with the 2005 versions when building for SLE10, for instance, which may not work properly. This can have negative effects, and even lead to a miscompile, for example when building libapr1 on SLE10.
Thus, it might be better, or even required, that you call autoheader, autoconf or whatever is needed by hand instead of autoreconf on targets older than Factory. An example would be:
%if 0%{?suse_version} > 1010
autoreconf -fi
%else
autoheader
autoconf
%endif
Debian and xUbuntu packages
For these packages, read the Build_Service/Deb_builds page.

