openSUSE:Build Service cross distribution howto
tagline: From openSUSE
- Build Service cross distribution howto
- Build Service Tips and Tricks
- Build Service Tutorial
- Creating a changes file (RPM)
- Java jpackage-utils
- Java RPM Macros
- Package group guidelines
- Package naming guidelines
- Package security guidelines
- Packaging checks
- Packaging Conventions RPM Macros
- Packaging desktop menu categories
- Packaging Fonts
- Packaging Games
- Packaging Go
- Packaging guidelines change process
- Packaging Haskell
- Packaging init scripts
- Packaging Java
- Packaging Lua
- Packaging Multiple Version guidelines
- Packaging Patches guidelines
- Packaging Perl
- Packaging PHP
- Packaging Python
- Packaging Ruby
- Packaging scriptlet snippets
- Packaging wxWidgets
- Ruby Gem Strategies
- Shared library packaging policy
- Specfile guidelines
- Systemd packaging guidelines
- Packaging guidelines
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 Build Service 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 openSUSE, but also recent SLES, CentOS, Fedora, Red Hat Enterprise Linux, Ubuntu, Debian 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 ?
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 there is no '%elseif' to chain multiple tests at the same level. Note that Fedora uses "%{fedora}" without "_version". You can also check for which SUSE distribution by using
%if 0%{?suse_version} > 1130
for instance to execute something for everything after SUSE Linux 11.3. Similar checks for other distributions exist as well.
%if %{defined fedora}
%if %{defined mdkversion}
%if 0%{?fedora} < 5
%if 0%{?mdkversion} > 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} || 0%{?rhel_version} || 0%{?centos_version}
<yourstuff>
%endif
To group conditionals, split the conditional to several lines, like this:
# mono: only on suse, sle only from sle10
%if 0%{?suse_version}
%if 0%{?sles_version} == 0 || 0%{?sles_version} >= 1000
BuildRequires: mono-core
%endif
%endif
Grouping with parentheses will fail on fedora/rhel/centos:
# mono: only on suse, sle only from sle10
# FAIL on fedora RHEL centos:
%if 0%{?suse_version} && ( 0%{?sles_version} == 0 || 0%{?sles_version} >= 1000 )
BuildRequires: mono-core
%endif
You can also select a special architecture using e.g.:
%if 0%{?suse_version} == 1030
%ifarch x86_64
<yourstuff>
%endif
%endif
Warning: The following version can change ! to check for the latest version go to the project page, and check the configuration file. For example with RedHat 5 go to: https://build.opensuse.org/project/prjconf?project=RedHat%3ARHEL-5 and look for the content "%rhel_version 505" to get the latest version. Please update this page if versions doesn't match.
The following overview helps to choose correct settings:
| Distribution | Variable | Comment |
|---|---|---|
| openSUSE Factory | %if 0%{?suse_version} > 1230 | current upcoming release (changing) |
| openSUSE 12.3 | %if 0%{?suse_version} == 1230 | |
| openSUSE 12.2 | %if 0%{?suse_version} == 1220 | |
| openSUSE 12.1 | %if 0%{?suse_version} == 1210 | |
| openSUSE 11.4 | %if 0%{?suse_version} == 1140 | |
| openSUSE 11.3 | %if 0%{?suse_version} == 1130 | |
| openSUSE 11.2 | %if 0%{?suse_version} == 1120 | |
| openSUSE 11.1 | %if 0%{?suse_version} == 1110 | could also be SLE11 |
| 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 | could also be SLE10 |
| 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} == 505 | |
| CentOS 6 | %if 0%{?centos_version} == 600 | |
| RHEL 4 | %if 0%{?rhel_version} == 406 | |
| RHEL 5 | %if 0%{?rhel_version} == 505 | |
| RHEL 6 | %if 0%{?rhel_version} == 600 | |
| Fedora 6 with Extras | %if 0%{?fedora} == 6 | |
| Fedora 7 with Extras | %if 0%{?fedora} == 7 | |
| Fedora 8 with Extras | %if 0%{?fedora} == 8 | |
| Fedora 9 with Extras | %if 0%{?fedora} == 9 | |
| Fedora 10 with Extras | %if 0%{?fedora} == 10 | |
| Fedora 11 with Extras | %if 0%{?fedora} == 11 | |
| Fedora 15 | %if 0%{?fedora} == 15 | |
| Fedora 16 | %if 0%{?fedora} == 16 | |
| Fedora 17 | %if 0%{?fedora} == 17 | |
| Mandriva 2006 | %if 0%{?mdkversion} == 2006 | |
| Mandriva 2007 | %if 0%{?mdkversion} == 2007 | |
| Mandriva 2008 | %if 0%{?mdkversion} == 2008 | |
| Mandriva 2009.0 | %if 0%{?mdkversion} == 2009 | |
| Mandriva 2009.1 | %if 0%{?mdkversion} == 200910 | |
| Mandriva 2010.0 | %if 0%{?mdkversion} == 201000 |
ServicePacks cannot be distinguished. SLES11 SP1 sets exactly the same variables as SLES11.
Install info files
Info files should get installed by using the %info_add and %info_del macros. For example
%post
%info_add %{name}.info
%preun
%info_del %{name}.info
Please note that the info files get compressed on some distros as .gz and as .bz2 or even .lzma (recent Mandriva) on 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, use osc meta prjconf <project-name> -e, which starts $EDITOR. In the web client this is hidden in the Advanced section of the central project menu.
In case you are doing this on build.opensuse.org and you think your substitution is of interest to others as well (and might be added to the central configuration) drop a message on opensuse-buildservice@opensuse.org.
If you want to have a look which Substitutes for a special distro already exist, have a look at the project configuration of that distro, e.g. https://build.opensuse.org/project/prjconf?project=CentOS%3ACentOS-6
Suggests: is only on SUSE and only from 10.0
# 'Suggests:' is a SUSE feature. Don't make it "Requires:", though,
# the package does not need vi or graphviz to run.
%if 0%{?suse_version} > 1000
# possibly 920 or 930 is ok to. sle9 910 sure is not.
Suggests: vim graphviz
%endif
Finding Qt 3.x on Fedora/RHEL
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} >= 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} >= 5
source "%{_sysconfdir}/profile.d/qt.sh"
%endif
%configure \
%if 0%{?fedora} >= 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, you may still 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 kind of packages, please read the debian builds page.
