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

 

 

GUI interactions: system alert beep() missing on Linux platform Qt

Most platforms (OS’s) have some aural (audible) way of telling the user that their action is a dud (will not have any effect).  Typically, the dud action is a keystroke, when no window has keyboard focus.  This GUI interaction is typically called the ‘system alert.’  Not to be confused with alert dialogs, and other alerts that appear for example in the upper right of the screen, for example when new email messages arrive.

The Qt framework has a QApplication.beep()  that is supposed to do this interaction, on all platforms.  Unfortunately, it doesn’t work on Linux.

As I sit writing this, if I click on the Ubuntu menu bar and start pressing the ‘a’ key, I don’t hear anything.   I think that the sound settings are properly set to ‘play the alert sound.’  (I don’t think this even goes through Qt.)

The root cause doesn’t seem to be that Qt is deficient.  It seems to be that Linux is deficient.  There are many bug reports about this is at least for Ubuntu distributions.  The bug reports are so many, long, and intricate that it is hard for me to be sure where the fault lies.  But it certainly seems like great minds have looked at it and that it is a complicated issue that no average coder can step forward and fix.  To me, the root cause is that someone made a decision that the Ubuntu platform should not have an alert that the user cannot mute or control the volume on (squelch.)  So the hardware that all PC’s have (a small speaker on the motherboard) is made not directly available through the operating system, but only indirectly available through the OS’s sound subsystem.  And that sound subsystem is complicated and fragile, if not broke.  You might say that the root root cause is that Linux supports so many variations of hardware and software that the complexity is too great to be easily maintained.

Suppose you have written an app using Qt and want to use ‘system alerts.’ One workaround is for the Linux platform only, display a dialog with a “don’t show again” checkbox.  Then at least the user will be able to learn what dud actions exist in your app.  Then they can squelch the dialog.

Adventures in translating an app to Chinese

This is a how-to.  A log of steps to take.  I am not an expert.  This is rudimentary, but better than nothing.  The results of this amateur translation might not be the best.   But the results are probably no worse then translations coming in the other direction.

Preparing your development computer

Your development computer must be capable of displaying the glyphs of the language into which you will be translating.  You usually must install more packages.

For Ubuntu, see Pinyin Joe.  Pinyin is a standard way of writing Chinese, across many dialects of Chinese.

If you don’t have the necessary software, the symptom is that when you paste Chinese characters onto your computer, they appear as boxes.

For translation, you don’t need ‘input methods.’  You will only be copy and pasting Chinese characters, not inputting them.  You don’t need a special keyboard.

General comments about the ease of translating apps

For an app, much that needs translation are simple words or phrases, and  have special computer meanings.  Such special computer meanings often appear as separate definitions at translating web sites.

Alternatively, you can find another app that is translated, and copy the translations from it.

Error messages, which are often complete sentences and questions, are more difficult to translate well.

Translating simple words and phrases

The best web site for translating is wordreference.com

The steps are:

  • enter an English word or phrase and choose the ‘Search’ button.  You will see a list of translations.
  • pick a translation with the appropriate meaning and part of speech
  • click on the translated string to see a list of reverse translations to English.  That helps you know whether the forward translation is correct, or gives you ideas for a better forward translation
  • copy and paste the translation (Chinese characters) into your translating program (such as Qt Linguist.)

Translating sentences

To translate sentences, you need at least a rudimentary knowledge of the grammar.   See Wiki.

The steps are:

  • translate words and put them in what you think is an appropriate order
  • copy the translated sentence into Google translate and translate it.  Check that the English meaning is not too strange.

The difference between a word translator and Google translate

I think that a site such as wordreference starts with translated words  (it also may have translations for idiomatic phrases.)  It is your responsibility to understand grammar and parts of speech.  The data there is much about parts of speech, tense, gender and so forth.  In other words, the data there is provided by humans, asserting attributes of words (but usually just words, not always phrases or sentences).

Whereas Google simply has a codex of translated text.  It finds the best match for your source text in that codex.  It has little understanding of grammar, parts of speech, etc.  It’s success depends on whether it has indexed documents in the ‘computer application’ arena.  For example, if it has indexed the user’s manuals for many applications, it might find a good translation for phrases in your app.