(deb -> rpm conversion tutorial/example, contribution on behalf of Nokia. feel free to improve, discuss or contact about it.) |
(How to build RPMs using Python Distutils) |
||
| Line 232: | Line 232: | ||
After build, rpmlint will give a couple of warnings, but no errors. The warnings currently relate to localizations for languages not yet supported in MeeGo, and two duplicate png image files that could be fixed by symlinking. | After build, rpmlint will give a couple of warnings, but no errors. The warnings currently relate to localizations for languages not yet supported in MeeGo, and two duplicate png image files that could be fixed by symlinking. | ||
| + | |||
| + | = .deb to .rpm Conversion Example (Python Distutils) = | ||
| + | |||
| + | If you already have a Python package that makes use of Distutils then producing RPM based packages is reasonably simple. Once you know how. Some of this information was taken from http://darkness.codefu.org/wordpress/2006/03/17/230. | ||
| + | |||
| + | Creating a RPM can be a simple as issuing the following command: | ||
| + | |||
| + | <pre> | ||
| + | python setup.py bdist_rpm | ||
| + | </pre> | ||
| + | |||
| + | Distutils will automatically create a .spec file and in turn generate a RPM with little or no extra work. There are a variety of parameters you can pass setup.py and these are described in detail here: http://docs.python.org/distutils/builtdist.html. | ||
| + | |||
| + | |||
| + | == Handling files with spaces in their name == | ||
| + | |||
| + | |||
| + | One thing you may notice is that if any of the files in the package have a space in the name generating an RPM will fail. This is because the list of installable files generated by Distutils aren't quoted. The RPM build program assumes these are two seperate files, and fails. | ||
| + | |||
| + | In order to fix this one needs to correct the INSTALLED_FILES file generated by Distutils, and to do this a script needs to be written. | ||
| + | |||
| + | First add the following to setup.cfg, it instructs Distutils to run bdist_rpm_install for the %install part of the .spec file: | ||
| + | |||
| + | <pre> | ||
| + | vi ./setup.cfg | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | [bdist_rpm] | ||
| + | install_script = bdist_rpm_install | ||
| + | </pre> | ||
| + | |||
| + | Next we need to create the bdist_rpm_install script and add the following to it: | ||
| + | |||
| + | <pre> | ||
| + | vi ./bdist_rpm_install | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | python2.5 setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES | ||
| + | sed -i -e '/ /s/\(.*\)/"\1"/' INSTALLED_FILES | ||
| + | </pre> | ||
| + | |||
| + | Notice that the Python version is explicitly set in the script, this appears to be necessary if you want to use a non-default version of Python. | ||
| + | |||
| + | If you now try and build the RPM, but produce the .spec file only, you'll see the following in the %install section: | ||
| + | |||
| + | <pre> | ||
| + | python setup.py bdist_rpm --spec-only | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | cat dist/[packagename].spec | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | <snip> | ||
| + | %install | ||
| + | python2.5 setup.py install --single-version-externally-managed --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES | ||
| + | sed -i -e '/ /s/\(.*\)/"\1"/' INSTALLED_FILES | ||
| + | </snip> | ||
| + | </pre> | ||
| + | |||
| + | Now, should you have any spaces in your filenames, the RPM build won't fail. | ||
| + | |||
| + | <pre> | ||
| + | python setup.py bdist_rpm | ||
| + | </pre> | ||
Contents |
This page aims to act as a helpful source for people having .deb packages and wishing to offer them as .rpm packages instead in MeeGo. It will mean manual work for every package, but this page should help in getting a first working draft done quicker.
In a DEB package, most of the package meta information is located under the directory debian, mainly in files control and rules but also a few others. Meanwhile, the .spec file of an RPM contains all the RPM meta data in a single file. Notation of these files is completely different, similarities exist in separation of build phases into logical sections and vivid use of conditional variables. Source RPM (.srpm) package has the upstream .tar.gz together with patches while "source DEB" (a bundle which is fetched by the dget tool by pointing the tool to a .dsc file) is three files: .dsc, orig.tar.gz and .debian.tar.gz. The DEB files unpacked with dpkg-source -x, or during fetching with dget -x, becomes the combination where packaging is under debian/ and possible patches usually under debian/patches.
A table below describes the highest level differences:
| Data | deb source format | rpm source format |
|---|---|---|
| upstream source | as is | as is |
| full packaged source | 3 files, of which the .dsc file is a pointer that can be used to fetch and unpack 1) original source and 2) debian packaging and patches in .debian.tar.gz | .srpm that includes 1) original source, 2) spec file and optionally 3) patches |
| packaging metadata | after unpacking the debian/ directory as a whole | after unpacking the .spec file and patches separately |
In this example we select a random package to convert from deb format to rpm format. The lucky winner was Transmission BitTorrent Client. Note that it is already packaged for various other rpm distributions, so it's just for the sake of an example and in practice it would be probably beneficial to glance at existing .spec files. We are taking the debian/ directory and the upstream Transmission source to look at from Debian project by looking at and running (on our Debian/Ubuntu machine):
# Download only dget -d http://ftp.debian.org/debian/pool/main/t/transmission/transmission_1.92-1.dsc # Unpack upstream source tar jxvf transmission_1.92.orig.tar.bz2 # Unpack debian/ directory separately tar zxvf transmission_1.92-1.debian.tar.gz
Start editing transmission.spec by copy-pasting the following template into your favorite text editor:
Name:
Version:
Release:1%{?dist}
Summary:
Group:
License:
URL:
Source0:
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires:
Requires:
%description
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}
%clean
rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
%doc
%changelog
It is more common than not in the rpm world to provide single binary package instead of multiple binary packages. Even so, it is possible to create multiple binaries from one source package even with rpm:s. For the sake of this example, we will do only one binary package similar to Transmission packaging in Fedora, even though Debian has multiple binaries generated.
In another window, go to the unpackaged debian/ directory and first take a look at the control file.
| debian/control file entry | .spec file entry | notes |
|---|---|---|
| Source | Name | |
| 1st line of Description of the main binary package | Summary | Should begin always with capital letter in the RPM world as per rpmlint policies |
| Description | %description | |
| Section | Group | See less /usr/share/doc/rpm*/GROUPS and find a match |
| Homepage | URL | |
| Build-Depends | BuildRequires | This needs manual thinking and tinkering and will often require a bit of trial and error. Try to match the Debian packages to http://repo.meego.com/MeeGo/test/trunk-test/repo/ia32/os/i586/ package names. |
| Depends | Requires | Only if some specifics not covered by the non-devel version of BuildRequires package. In this example, the only non-macro dependency in control file's Depends: fields is lsb-base (>= 3.0), which corresponds to meego-lsb in MeeGo. |
More precisely the mapping of build depends from debian/control to .spec file goes like this:
| Debian dependency | MeeGo dependency | Notes |
|---|---|---|
| debhelper | not needed | deb packaging related |
| autotools-dev | not needed | contains only config.sub and config.guess system-wide files |
| libgtk2.0-dev | gtk2-devel | |
| libevent-dev (>= 1.4) | libevent-devel >= 1.4 | |
| libglib2.0-dev | glib2-devel | |
| libnotify-dev | libnotify-devel | |
| libssl-dev | openssl-devel | |
| libcurl4-dev / libcurl-dev | libcurl-devel | |
| chrpath | chrpath | |
| intltool (>= 0.40) | intltool >= 0.40 | |
| qt4-qmake | qt-devel | qt-devel includes both dev files and qmake |
| libqt4-dev | qt-devel | qt-devel includes both dev files and qmake |
| libcanberra-gtk-dev | libcanberra-devel | Note: commented out in control, but we can use them in our package |
| libgconf2-dev | GConf-dbus-devel | Note: commented out in control, but we can use them in our package |
Other stuff to fill in the .spec file from debian/ files:
| .spec file entry | Where to find |
|---|---|
| License | debian/copyright |
| Source0 | upstream or debian/copyright |
| Version | obvious, or debian/changelog |
Now we have all the basics covered. Let's see what's remaining and potentially needing importing in some form or another:
| debian/ file | What to do |
|---|---|
| *.install, *.dirs, *.links | Consider to be listed in .spec file's %files section |
| *.postinst | %post section |
| *.postrm | %postun section |
| changelog | %changelog, but should be new for the .rpm package |
In the case of post-installation scripts of Transmission, they deal with setting the permissions of the transmission-daemon binary so that it will be run as a special user. We can mimick that behavior in the %post section (and %postun section) of the spec file. A rough take on it is included in the example final spec file, but take into account that there may be or maybe will be policies defining a better way of doing eg. permission handling.
This section is used to include all the wanted files to the resulting rpm binary package. When filling in the %files section of the .spec file, it is rather easy to miss files that are installed during the building. One tip is to check the build log for "error: Installed (but unpackaged) file(s) found" or "RPM build errors: Installed (but unpackaged) file(s) found" and utilize that information to select more files to the package.
%{_bindir}, %{_datadir}, %{_mandir} etc. variables should be used in the section to use standard directory names.
Localization files are handled specially. An rpm macro called %find_lang will find all the locale files that belong to the package, and put the list in a file, usually %{name}.lang. That file can be then used to include all of the locales. The "name" parameter given to %find_lang equals to package name, but if the translation domain differs from the package name, it should be specified instead. The generated list can be used with the -f parameter to %files when starting the %files section.
This is the result of following the example through.
Name: transmission
Version: 1.92
Release: 1%{?dist}
Summary: Lightweight BitTorrent client
Group: Applications/Internet
License: MIT
URL: http://www.transmissionbt.com/
Source0: http://download.m0k.org/transmission/files/transmission-1.92.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: gtk2-devel,libevent-devel >= 1.4,glib2-devel,libnotify-devel,openssl-devel,libcurl-devel,chrpath,intltool >= 0.40,qt-devel,libcanberra-devel,GConf-dbus-devel
Requires: meego-lsb >= 3.0
%description
Transmission is a simple BitTorrent client. It features a very simple,
intuitive interface (gui and command-line) on top on an efficient,
cross-platform back-end.
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}
%find_lang %{name}
%post
addgroup --system --quiet meego-transmission
adduser --system --group --no-create-home --quiet meego-transmission
chown meego-transmission:meego-transmission /var/lib/transmission-daemon/info
chown meego-transmission:meego-transmission /var/lib/transmission-daemon/downloads
chown meego-transmission:meego-transmission /etc/transmission-daemon/settings.json
%postun
if [ -d /var/lib/transmission-daemon/info ]; then
rm -rf /var/lib/transmission-daemon/info/*
fi
%clean
rm -rf %{buildroot}
%files -f %{name}.lang
%defattr(-,root,root,-)
%doc AUTHORS COPYING NEWS README
%{_bindir}/transmission*
%{_datadir}/applications/transmission.desktop
%{_datadir}/icons/hicolor/*/apps/transmission.png
%{_datadir}/icons/hicolor/scalable/apps/transmission.svg
%{_datadir}/pixmaps/*
%{_datadir}/transmission
%doc %{_mandir}/man1/transmission*
%changelog
* Mon Apr 26 2010 Timo Jyrinki <timo.jyrinki@nomovok.com> - 1.92
- http://trac.transmissionbt.com/wiki/Changes#version-1.92
After build, rpmlint will give a couple of warnings, but no errors. The warnings currently relate to localizations for languages not yet supported in MeeGo, and two duplicate png image files that could be fixed by symlinking.
If you already have a Python package that makes use of Distutils then producing RPM based packages is reasonably simple. Once you know how. Some of this information was taken from http://darkness.codefu.org/wordpress/2006/03/17/230.
Creating a RPM can be a simple as issuing the following command:
python setup.py bdist_rpm
Distutils will automatically create a .spec file and in turn generate a RPM with little or no extra work. There are a variety of parameters you can pass setup.py and these are described in detail here: http://docs.python.org/distutils/builtdist.html.
One thing you may notice is that if any of the files in the package have a space in the name generating an RPM will fail. This is because the list of installable files generated by Distutils aren't quoted. The RPM build program assumes these are two seperate files, and fails.
In order to fix this one needs to correct the INSTALLED_FILES file generated by Distutils, and to do this a script needs to be written.
First add the following to setup.cfg, it instructs Distutils to run bdist_rpm_install for the %install part of the .spec file:
vi ./setup.cfg
[bdist_rpm] install_script = bdist_rpm_install
Next we need to create the bdist_rpm_install script and add the following to it:
vi ./bdist_rpm_install
python2.5 setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES sed -i -e '/ /s/\(.*\)/"\1"/' INSTALLED_FILES
Notice that the Python version is explicitly set in the script, this appears to be necessary if you want to use a non-default version of Python.
If you now try and build the RPM, but produce the .spec file only, you'll see the following in the %install section:
python setup.py bdist_rpm --spec-only
cat dist/[packagename].spec
<snip> %install python2.5 setup.py install --single-version-externally-managed --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES sed -i -e '/ /s/\(.*\)/"\1"/' INSTALLED_FILES </snip>
Now, should you have any spaces in your filenames, the RPM build won't fail.
python setup.py bdist_rpm