This tutorial was Powered by Rackspace Cloud Hosting
The following resources were needed for this tutorial. That said you may need to make additional pre-configurations to your system in order to follow along. Any recent RPM based Linux distro should be suitable.
Operating System
Required/Recommended Packages
Experience Level
This article assumes that you are atleast familiar with both Python, and RPM Packaging. If not, perhaps you might need to take a few steps back and add a bit of reading material to your stack:
RPMs for Python applications have to take into account where the 'Python Site Library' is which is where python libraries need to be installed to. Installing here ensures that libraries will be accessible when you try to import them. We will call this the 'python_sitedir'.
Other than a few Python-isms in the RPM spec file, everything else is more or less kosher.
For this example we are going to use CherryPy as our Python application, and look at the python-cherrypy RPM from Fedora EPEL 5:
[root@slice03 ~]# yum install rpm-build python-devel python-setuptools [root@slice03 ~]# rpm --import http://mirrors.kernel.org/fedora-epel/RPM-GPG-KEY-EPEL [root@slice03 ~]# wget http://mirrors.kernel.org/fedora-epel/5Server/SRPMS/python-cherrypy-2.2.1-10.el5.src.rpm [root@slice03 ~]# rpm -Uvh python-cherrypy-2.2.1-10.el5.src.rpm 1:python-cherrypy ########################################### [100%]
Our Source RPM will be available in the default location of /usr/src/redhat, lets work with that.
[root@slice03 ~]# cd /usr/src/redhat [root@slice03 redhat]# vi SPECS/python-cherrypy.spec
We can see the first line looks like so:
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
#You will see this exact [or similar] line in all Python rpms from Fedora/CentOS/Redhat/Etc. In laymen's terms, what this line says is: "If the RPM macro 'python_sitelib' is not already set, then define the macro python_sitelib as the output of the shell command %(...)". If we want to see what that output is on a system, we can run that command (manually substituting the RPM macro for python):
[root@slice03 redhat]# python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" /usr/lib/python2.4/site-packages
This macro definition is important because it sets python_sitelib appropriately for the system we are building on and building for. The 'sitelib' will be different based on the OS and python version... and this trick allows us to dynamically know where our files are going to install to.
Skipping down a bit further, lets check out the %build section and %install sections (which are pretty straight forward):
%build
%{__python} -c 'import setuptools; execfile("setup.py")' build
%install
rm -rf $RPM_BUILD_ROOT
%{__python} -c 'import setuptools; execfile("setup.py")' install -O1 --skip-build --root %{buildroot}This might look like some fancy magic, and to tell you the truth I'm not really sure why the Fedora EPEL people are doing it this way, however we could just as easily write this as:
%build
%{__python} setup.py build
%install
rm -rf $RPM_BUILD_ROOT
%{__python} setup.py install -O1 --skip-build --root %{buildroot}
Either way will work, however the key note to point out here is how we are telling setup.py where to install the files to. By passing the '--root' flag we tell setuptools to install the files to an alternate root (rather than slash '/' root) allowing us to package the files into an RPM via the RPM_BUILD_ROOT directory structure (aka %{buildroot}).
Skip once again down to our %files section and we will see how we are packaging up the files we just installed:
%files
%defattr(-,root,root,-)
%doc CHANGELOG.txt CHERRYPYTEAM.txt README.txt
%doc cherrypy/tutorial
%{python_sitelib}/cherrypy
Once again, all pretty straight forward RPM spec stuff except you will notice that we are using our pre-defined '%{python_sitelib}' to know where our files installed to. Without that macro, we would need to hard code the '/usr/lib/python2.4/site-packages' directory based on the OS and Python version for every system we wanted to build this package on.
The following is just a simple template you can use if you need a starting point. Simply search and replace anywhere you see a 'REPLACE', make any modifications you need to solidify your package, and build:
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
#
Name: REPLACE
Version: [?]
Release: 1%{?dist}
Summary: REPLACE
Group: Development/Libraries
License: REPLACE
URL: http://REPLACE
Source0: http://REPLACE/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildArch: noarch
BuildRequires: python-devel
%if 0%{?fedora} >= 8
BuildRequires: python-setuptools-devel
%else
BuildRequires: python-setuptools
%endif
%description
REPLACE
%prep
%setup -q -n %{name}-%{version}
%build
%{__python} -c 'import setuptools; execfile("setup.py")' build
%install
[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
%{__python} -c 'import setuptools; execfile("setup.py")' install -O1 --skip-build --root %{buildroot}
%clean
[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
%doc REPLACE
%{python_sitelib}/%{name}
%changelog
* Fri Jul 03 2009 BJ Dierkes <wdierkes@5dollarwhitebox.org>
- Example Python RPM Spec FileAs we've seen by looking at this example, there really is only a little bit of magic going on inside the RPM spec to properly build packages for Python applications. I hope this helps any new comers along and clarifies Python-isms required for building RPMs.