Building PyQt5 for Python2.7 on a clean Ubuntu 13.10 build machine

This tells how to build PyQt5 for Python 2.7 on a newly installed Ubuntu 13.10.  The problem is that Ubuntu 13.10 defaults the command ‘python’ to version 2.7.5, and Ubuntu repositories don’t provide a compatible PyQt5 package.  (The package ‘python3-pyqt5’ installs with Python 3 packages, and won’t be found if you run ‘python’ instead of ‘python3’.)

The audience is developers who for any reason want to stick with Python 2.7.  Many will just use ‘python3’ and the packages provided by Ubuntu.

  • One reason you might want Python2.7 is that you are using PyQt because it is cross-platform, and you are waiting until Python 3 is blessed on all your platforms.
    /usr/local/include/python2.7
  • Another reason is you are using pyinstaller, which doesn’t support Python3 yet

This is tedious, and you wait about an hour.

In my opinion, it illustrates needless complexity surrounding:

  • the transition to Python 3
  • different Linux distribution’s ‘standard’ file hierarchy
  • the overly flexible Linux packaging philosophy: ‘don’t distribute everything, and track dependencies.’

Finally, you might need this recipe on Ubuntu 14.04 also.

The reason for a build machine

A build machine has a well-documented configuration.  On a ‘development’ machine (hacked  by a programmer),  you might not be absolutely sure what versions of libraries are used.  So this tutorial starts on a machine on which you just installed default Ubuntu 13.10.

I am using Pyinstaller as the next step.  You would think that a Pyinstaller binary would be more or less independent of libraries, since the binary packages almost all needed libraries.  Thus you would not need a clean build machine; a binary from the dev machine should work, and a little sanity testing on other platforms would show that.  However, such sanity testing shows that Pyinstaller binary from 13.04 does NOT work on 13.10, some of the system libraries in the package crash!

But in apparent contradiction, Pyinstaller recommends that you build on the oldest version of the operating system that you have ‘laying around.’  Thus Pyinstaller is not a magic bullet.

 Overview

Steps:

  • get the packages needed for compiling Python bindings to Qt
  • get missing Qt libraries
  • fix a problem with PyQt’s makefile
  • build PyQt and SIP from the origin vendor.

Get the packages needed for compiling PyQt Python bindings to Qt

  • using Ubuntu Software Center (USC), install package ‘qt5-default’.  This package set Qt5 to be the default when running Qt dev tools, instead of Qt4. This is an omnibus package, including many other packages. PyQt needs the header files to compile, and uses the qmake tool to determine which version of Qt you are using.
  • using USC, install package ‘python-dev’.  These are include header files for Python.

 

Get optional Qt libraries

My app uses QtSvg, an optional library of Qt.  For some reason, Ubuntu13.10 doesn’t include it.

Using USC, install package ‘libqt5svg5’ and ‘libqt5svg5-dev’.

If you fail to do this first, PyQt5 will successfully build, but not build bindings to QtSvg.  Then later, your app will fail to import PyQt5.QtSvg, and you will need to rebuild PyQt5.  Apparently PyQt5 builds bindings to optional Qt libraries based on whether their header files are present (not whether the libraries are present.)  Thus you need the -dev package.

There are many other optional Qt libraries.  Qt5 has moved towards having more optional libraries.

Fix a problem with PyQt’s makefile

PyQt’s makefile assumes python headers are in /usr/local/include/python27.  This is a typical problem among Linux distributions: some install certain things to /usr/local, some install to /usr.  Ubuntu does the latter, while PyQt makefile assumes the former.

Here we create a soft link:

ln -s  /usr/include/python2.7  /usr/local/include/python2.7

Note that the second path is the link that is created, to the target given by the first path.

Build PyQt and SIP from the origin vendor.

PyQt depends on SIP.

Build SIP

  • Download SIP from the vendor.
  • Extract
  • cd to that directory

Follow the vendor’s instructions, the default:

python configure.py
make
sudo make install

Build PyQt

  • Download PyQt5 from the vendor.
  • Extract
  • cd to that directory

Follow the vendor’s instructions, slightly augmented:

python configure.py --sip-incdir ../sip*/siplib
make - j 2
sudo make install

This assumes you built SIP in a parallel directory to PyQt.  I don’t know why installing SIP did not put its sip.h header where PyQt could find it.  Possibly it was installed to /usr/local/include.

The make takes many minutes.

Note the makefile prints an error message about ‘strip’, at the end of its processing.  The vendor advises to ignore it.

Testing

python
>>>import PyQt5.QtSvg

 

 

Advertisements

5 thoughts on “Building PyQt5 for Python2.7 on a clean Ubuntu 13.10 build machine

  1. Thanks for your tutorial. I’ve just installed PyQt5 on Ubuntu 14.10.
    But I got this error when execute your last line:

    >>> import PyQT5.QtSvg
    Traceback (most recent call last):
    File “”, line 1, in
    ImportError: No module named PyQT5.QtSvg

    But when I “import PyQT5”, no error shown up.
    Is that normal?

    • First, I think it is case sensitive: try PyQt5 with lower case t.

      Then, you can check whether the PyQt bindings to the QtSvg module were built by using a file browser to /usr/lib/python3.4/site-packages/Qt5. In that directory you should find QtSvg.o and libQtSvg.a.

      By default, I think it builds bindings for all Qt modules that are installed in Qt. So if you installed QtSvg (it is not always installed with Ubuntu’s Qt, but you might have also installed a newer Qt) then building PyQt should make the bindings to it.

      Also, if you used a newer Python to configure PyQt ( >python3 configure.py instead of >python configure.py), that’s where it installs, and you must use the same python when you test it.

      These are just ideas off the top of my head, without knowing the specifics for what you might have done differently from the tutorial (and without my rereading the tutorial for exactly what I did at that time. I think I am still on Ubuntu 14.04 but with a newer Qt and newer python.)

  2. I got the error:

    /home/guillermo/Downloads/PyQt5_gpl-5.9/QtCore/sipQtCoreQUrl.cpp: In function ‘PyObject* meth_QUrl_fromUserInput(PyObject*, PyObject*, PyObject*)’:
    /home/guillermo/Downloads/PyQt5_gpl-5.9/QtCore/sipQtCoreQUrl.cpp:1403:59: error: ‘QUrl::UserInputResolutionOption’ is not a class or namespace
    ::QUrl::UserInputResolutionOptions a2def = QUrl::UserInputResolutionOp
    ^
    Makefile:1887: recipe for target ‘sipQtCoreQUrl.o’ failed
    make[1]: *** [sipQtCoreQUrl.o] Error 1
    make[1]: Leaving directory ‘/home/guillermo/Downloads/PyQt5_gpl-5.9/QtCore’
    Makefile:57: recipe for target ‘sub-QtCore-make_first-ordered’ failed
    make: *** [sub-QtCore-make_first-ordered] Error 2

    when executing “make – j 2” while building PyQt

    • Its been a long time since I did this. I suggest using later versions of everything.

      PyQt has an email group that is helpful, but I don’t subscribe any longer.

      Finally, it is hard to read your listing, but is there a typo misspelling? One place it is …tionOption (without an s) and another place it is …tionOptions (with an s). I know you didn’t type it in, but it is strange and maybe it was fixed in a later version.

  3. Grey, I got over the error when I replaced line 1403 of QtCore/sipQtCoreQUrl.cpp with ->
    ::QUrl::UserInputResolutionOptions a2def = QUrl::DefaultResolution;

    I’m not sure if this will create run-time errors, but the compilation went through.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s