Friday, October 19, 2007

Compiling mod_python on RHEL 64 bit

I just went through the fairly painful exercise of compiling mod_python 3.3.1 on a 64-bit RHEL 5 server. RHEL 5 ships with Python 2.4.3 and mod_python 3.2.8. I needed mod_python to be compiled against Python 2.5.1. I had already compiled and installed Python 2.5.1 from source into /usr/local/bin/python2.5. The version of Apache on that server is 2.2.3.

I first tried this:

# tar xvfz mod_python-3.3.1.tar.gz
# cd mod_python-3.3.1
# ./configure --with-apxs==/usr/sbin/apxs --with-python=/usr/local/bin/python2.5
# make

...at which point I got this ugly error:

/usr/lib64/apr-1/build/libtool --silent --mode=link gcc -o mod_python.la \
-rpath /usr/lib64/httpd/modules -module -avoid-version finfoobject.lo \
hlistobject.lo hlist.lo filterobject.lo connobject.lo serverobject.lo util.lo \
tableobject.lo requestobject.lo _apachemodule.lo mod_python.lo\
-L/usr/local/lib/python2.5/config -Xlinker -export-dynamic -lm\
-lpython2.5 -lpthread -ldl -lutil -lm

/usr/bin/ld: /usr/local/lib/python2.5/config/libpython2.5.a(abstract.o):
relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object;
recompile with -fPIC

/usr/local/lib/python2.5/config/libpython2.5.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
apxs:Error: Command failed with rc=65536

I googled around for a bit, and I found this answer courtesy of Martin von Loewis. To quote:

It complains that some object file of Python wasn't compiled
with -fPIC (position-independent code). This is a problem only if
a) you are linking a static library into a shared one (mod_python, in this case), and
b) the object files in the static library weren't compiled with -fPIC, and
c) the system doesn't support position-dependent code in a shared library

As you may have guessed by now, it is really c) which I
blame. On all other modern systems, linking non-PIC objects
into a shared library is supported (albeit sometimes with a
performance loss on startup).

So your options are
a) don't build a static libpython, instead, build Python
with --enable-shared. This will give you libpython24.so
which can then be linked "into" mod_python
b) manually add -fPIC to the list of compiler options when
building Python, by editing the Makefile after configure has run
c) find a way to overcome the platform limitation. E.g. on
Solaris, the linker supports an impure-text option which
instructs it to accept relocations in a shared library.

You might wish that the Python build process supported
option b), i.e. automatically adds -fPIC on Linux/AMD64.
IMO, this would be a bad choice, since -fPIC itself usually
causes a performance loss, and isn't needed when we link
libpython24.a into the interpreter (which is an executable,
not a shared library).

Therefore, I'll close this as "won't fix", and recommend to
go with solution a).

So I proceeded to reconfigure Python 2.5 via './configure --enable-shared', then the usual 'make; make install'. However, I hit another snag right away when trying to run the new python2.5 binary:

# /usr/local/bin/python
python: error while loading shared libraries: libpython2.5.so.1.0: cannot open shared object file: No such file or directory


I remembered from other issues I had similar to this that I have to include the path to libpython2.5.so.1.0 (which is /usr/local/lib) in a ldconfig configuration file.

I created /etc/ld.so.conf.d/python2.5.conf with the contents '/usr/local/lib' and I ran

# ldconfig

At this point, I was able to run the python2.5 binary successfully.

I then re-configured and compiled mod_python with

# ./configure --with-apxs=/usr/sbin/apxs --with-python=/usr/local/bin/python2.5
# make

Finally, I copied mod_python.so from mod_python-3.3.1/src/.libs to /etc/httpd/modules and restarted Apache.

Not a lot of fun, that's all I can say.

Update 10/23/07

To actually use mod_python, I had to also copy the directory mod_python-3.3.1/lib/python/mod_python to /usr/local/lib/python2.5/site-packages. Otherwise I would get lines like these in the apache error_log when trying to hit a mod_python-enabled location:

[Mon Oct 22 19:41:20 2007] [error] make_obcallback: \
could not import mod_python.apache.\n \
ImportError: No module named mod_python.apache
[Mon Oct 22 19:41:20 2007] [error] make_obcallback:
Python path being used \
"['/usr/local/lib/python2.5/site-packages/setuptools-0.6c6-py2.5.egg', \
'/usr/local/lib/python25.zip', '/usr/local/lib/python2.5', \
'/usr/local/lib/python2.5/plat-linux2', \
'/usr/local/lib/python2.5/lib-tk', \
'/usr/local/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages']".
[Mon Oct 22 19:41:20 2007] [error] get_interpreter: no interpreter callback found.

Update 01/29/08

I owe Graham Dumpleton (the creator of mod_python and mod_wsgi) an update to this post. As he added in the comments, instead of manually copying directories around, I could have simply said:

make install

and the installation would have properly updated the site-packages directory under the correct version of python (2.5 in my case) -- this is because I specified that version in the --with-python option of ./configure.

Another option for the installation, if you want to avoid copying the mod_python.so file in the Apache modules directory, and only want to copy the Python files in the site-packages directory, is:

make install_py_lib

Update 06/18/10

From Will Kessler:

"You might also want to add a little note though. The error message may actually be telling you that Python itself was not built with --enable-shared. To get mod_python-3.3.1 working you need to build Python with -fPIC (use enable-shared) as well."

22 comments:

Noah Gift said...

Grig,

I really like parts of Red Hat, because it is a very stable distribution, but I really do not like compiling on Red Hat. I would rather carve a chunk of flesh out of my arm then re-compile any integrated rpm.

I had an episode a few months ago where I stayed up for 19 straight hours trying to get trac to work with Python 2.5 on CentOS 4.4. It was an angry, frustrating experience, that ended with me slapping myself for being so stupid :)

Grig Gheorghiu said...

Hi, Noah

I sympathize with your frustration obviously. Sometimes do you gotta do what you gotta do....and no, I'm not thinking about carving flesh chunks out of our arms :-)

Grig

Unknown said...

You know, if you actually make use of the wisdom that is embedded in the RPMs, instead of struggling against them, your life won't be so painful. It also becomes something that you can easily deploy on other servers, and share with other people.

Instead of pulling down a pristine Python and mod_python tar file, try using newer versions of the source RPMs, for example the ones in Red Hat development (rawhide) or F7...

The benefit here is that you get all the wisdom of the previous packagers and how they built them. Including compile-time options, etc...

In the past, I had need for mod_python 3.3.1 on Cent OS 4.5, but with Python 2.4 not 2.5... Using the RPMs to build new packages has huge benefits.

In general, I think that either you should develop for the Python which is on your chosen deployment platform (older Python and mod_python). Or you should deploy a platform that matches your development requirements (like a Fedora 7, and plan to re-deploy production every roughly 18 months to keep up with security updates). Or, you need to commit to rolling your own distro, taking RHEL and "back-porting" and maintaining the newer packages on the older distro.

The last option should not be jumped into lightly. However, many people do, and then complain. However, rebuilding RPMs on Red Hat platforms is not actually "hard". It's easier to do using SRPMs than it is to do from tar source, because the tar source doesn't incorporate build flags and other things necessary to turn the source into an installed set of software.

Sean

Graham Dumpleton said...

If you had followed the mod_python installation instructions and run 'make install', you would not have needed to copy the mod_python Python code components into your site-packages directory by hand as it would have been done for you.

Grig Gheorghiu said...

Graham -- you're right. I did not want to run 'make install' though, because I didn't want mod_python to touch areas of the system that would conflict with the packages shipped with RHEL 5. I could have probably run it with no problems.

Grig

Graham Dumpleton said...

Because you used --with-python, it would have used that version to install the Python module components and so they would have end up under /usr/local/... and not in system area.

If you wanted to avoid having it also try and install the Apache mod_python.so file, then you can use just 'make install_py_lib'.

Grig Gheorghiu said...

Thanks for the clarification, Graham. I'll update my post soon with your explanations.

Grig

Anonymous said...

Great post, it was a great help! I found a minor typo tho, in your configure command for mod_python you have "--with-apxs==/usr/sbin/apxs" when it should be "--with-apxs=/usr/sbin/apxs".

Grig Gheorghiu said...

Thanks, Sean, I updated the post and got rid of the extra '='.

Grig

Unknown said...

Hey Grig, thank you very much for sharing your experience with us. It helped me very much. Now it's working. ;)

Thijs Triemstra said...

Thanks so much, looked hours for this solution!

Anonymous said...

Thank you for this post. It saved me a lot of time and headache :)

Unknown said...

Very useful info. Thanks

Unknown said...

Please Be aware with this solution. That if you use any .egg modules that you have to create /var/www/.python-eggs
with ownership of apache

mkdir /var/www/.python-eggs
chown apache:apache /var/www/.python-eggs

Unknown said...

Everything on this was perfect. Except one thing. In order to you python egg modules you have to make a folder for apache to decpmpress them
mkdir /var/www/.python-eggs
chown apache:apache /var/www/.python-eggs

will do the trick

Anonymous said...

Hi Grig, I had this exact problem. Thanks for sharing your solution - I was banging my head against this one for a couple of painful hours...

Karl

Anonymous said...

[mod_python] Compiling mod_python on 64bit RHEL 4: I have Apache 1.3.31 and Python 2.3.4 and I'm trying to compile
mod_python 2.7.10 on 64bit RHEL 4 but after running configure
-with-apxs=/ots/apache_1.3.31/bin/apxs the make dso fails with the
following error.



/usr/bin/ld: mod_python.o: relocation R_X86_64_32 against `a local
symbol' can not be used when making a shared object; recompile with
-fPIC

mod_python.o: could not read symbols: Bad value

collect2: ld returned 1 exit status

apxs:Break: Command failed with rc=1

make[1]: *** [mod_python.so] Error 1

make[1]: Leaving directory `/tmp/mod_python-2.7.10/src'

make: *** [do_dso] Error 2



I've tried several version of apache, python, and mod_python and I get
the same error.

Anonymous said...

Hi Grig,
Can show me how u install the python2.5? i am struggle with this now... thanks

Regards,
Kelvin

cocobende said...

Thank you for that precise and very helpful documentation. This saved my day.

Unknown said...

Fantastic! Exactly what I was looking for. Reproduced on 64 bit Centos 4, where I needed Python 2.4 and mod_python 3.3.1, but wanted to keep the originals intact. Thanks!

ToM Krickl said...

Hey!

Thanks for your post. Helped me a lot.

Thanks again
ToM

Serge_HID said...

thanks a lot, was very helpful

Modifying EC2 security groups via AWS Lambda functions

One task that comes up again and again is adding, removing or updating source CIDR blocks in various security groups in an EC2 infrastructur...