Monday, 16 December 2013

Cross-Compiling QT5 Windows Applications on Ubuntu 13.10


I've built a QT application which runs on both Linux and Windows using QT4.8, but found that the accessibility features on QT4.8 are lacking on Windows (for example, a simple text-entry dialogue box will read the contents, but not show them up on a braille display, using Jaws 14).
I opted to make the move to QT5, and I wanted to ensure that:
  • the accessibility features were enabled
  • the windows applications could be statically linked as far as possible
  • the qt-creator application would enable me to produce both Linux and Windows versions of my program

Setting up the Environment


MINGW32 and Ubuntu Tools

In order to be able to build QT5 and applications, and a Windows release of QT5 and the cross-compilation applications, a number of Ubuntu packages are required.  These can be installed with the apt-get command:

sudo apt-get install autoconf automake bash bison bzip2 cmake flex gettext git g++ intltool libffi-dev libtool libltdl-dev libssl-dev libxml-parser-perl make openssl patch perl pkg-config scons sed unzip wget xz-utils

QT5 for Linux (Dynamic Linking)

I've downloaded QT5 from the git repository, and built in a separate directory as advised, but have had significant trouble, so I've ended up untarring multiple instances of the source, and building in-situ.

See at the end of this blog entry the sorts of problems I had, which were resolved by downloading a tarball, and building in-situ.

Download tarball

cd /opt/src 



tar xf qt-everywhere-opensource-src-5.2.0-beta1.tar.gz

mv qt-everywhere-opensoure-src-5.2.0-beta1 qt5.2.0-beta1-linux


Specific to the beta release5.2.0-beta1 that I chose:


There is a problem with localtime_r, so some alternative code needs to be included. The bugfix adds additional code for cross-compiling with mingw32, which is what we are doing.  It requires the variable Q_CC_MINGW to be defined.

cd /opt/src/qt5.2.0-beta1-win32/qtdeclarative/src/qml/jsruntime


Build in situ

cd /opt/src/qt5.2.0-beta1-linux
./configure --prefix=/opt -opensource -confirm-license \
  -shared -developer-build -debug \
  -nomake examples -no-compile-examples \
  -accessibility | tee config.log 2>&1

make -j 4 | tee compile.log 2>&1

make install | tee install.log 2>&1

QT Creator 3 for Linux

Download tarball



Build in situ

cd qt-creator-3.0.0

make install into /opt

make install INSTALL_ROOT=/opt | tee install.log 2>&1

QT5 for Windows (Static Linking)

Use same tarball as QT5 for Linux

Build in situ
Defining Q_CC_MINGW

./configure -static -release -opensource -confirm-license \
      -make libs -nomake tests -nomake examples \
      -no-compile-examples \
      -accessibility \
      -no-sse -no-sse2 -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2 \
      -no-avx -no-avx2 -no-neon -no-mips_dsp -no-mips_dspr2 \
      -no-gif \
      -optimized-qmake -reduce-relocations -no-pch \
      --xplatform=win32-g++ \
      -device-option CROSS_COMPILE=/usr/bin/i686-w64-mingw32- \
      --prefix=/opt/i686-w64-mingw32 > qtconfig.log 

make install into /opt/i686-w64-mingw32

Cross Compiling 101 

In order to cross-compile in general, all you need to do is set an environment variable: ${CROSS_COMPILE} to i686-pc-mingw32- and any time you need to call a compiler (e.g. gcc), use ${CROSS_COMPILE}gcc - this way, if the environment variable is set, the cross-compiler is used, and if it is not set, the native compiler is used.

A note about qmake

Qmake is a builder of makefiles (which in turn are used to build your qt application). Qmake takes an argument, which tells it what the target application is (e.g. a windows 32 program).. Qmake also converts the GUIs you've drawn into cpp source code for compilation.

There are some paths / libraries / definitions hard-coded into qmake, so if you use the default system-installed qmake, which is usually installed in /usr/bin, the files it creates will not build windows applications, even if you point it at the correct configuration file, as they will try to link your windows object files with linux libraries.

This is why we make a short-cut in /opt/bin called i686-pc-mingw32-qmake. So you can use ${CROSS_COMPILE}qmake in your scripts / programs.

QT Cross-Compiling 101

OK, so lets assume that you've been writing a QT application for Linux using QtCreator, and you've got all of your source code files, and your project file.

All you need to do is invoke the correct qmake, tell it what your source is, and what your target is, and sit back!

cd output-build-directory
${CROSS_COMPILE}qmake -spec win32-g++ path-to-project/

Qmake Gotchas

  • Make sure you use the correct qmake program.
  • The Mingw32 windows libraries are built as static, but as long as you use the correct qmake, this should be transparent to you.

Bugs / Problems / Gotchas


  1. The configure script needs a double hyphen for the prefix and xplatform options, not a single hyphen as indicated in all of the documentation. 

Cross-Compiling qtactiveqt/src/tools/idc

When cross-compiling the IDC on the Linux platform for the Win32 target, the Makefile is built to call up the Linux g++ compiler, and then asked to build a file which includes the windows.h header, which is clearly wrong.

My workaround was to replace the idc Makefile with a file containing the lines:



Downloading from git: 

My first attempt at building was from the git repository, but I changed to using the tarball because I was hampered by a number of errors.
  1. Git stable releases.  I found that the -developer-build option did not copy the private headers across on installation, and I could not get the QT_PRIVATE_HEADERS parameter for qmake to work, so when I tried to build qt-creator, it always failed.
  2. The private headers seems to be going through a change at the moment, and qt-creator expects them to be in a module called XXXX, but that module does not exist in the QT5 file set.

Saturday, 23 November 2013

Settin up CSIPSimple and Voiptalk on Android

To set up CSIPSimple for Voiptalk, all you need to do is create an account with the following settings in Expert Mode!

Make sure that you replace the bits in bold with details from your account.

And watch for the colon in the Registration URI, it's definitely not a dot!

If you don't de-select the Allow Contact Rewrite, the application double-registers with VoipTalk, and confuses the system, particularly when you check online to see if you have connected or not.

Account Name: Descriptive Account Name
Account ID: Your Name <>
Registration URI:
Realm: *
Username: 00000000
Data (password): ********
Proxy URI:
Allow Contact Rewrite: Unticked

Wednesday, 6 November 2013

Gure Sekretua

Just set up a new website: Gure Sekretua.  The site shows our apartment in France, which is available for holiday rentals.  It is in the Basque spa town of Cambo-Les-Bains in the south west of France.

Gure Sekretua is basque for "our secret".  What we didn't realise when we bought the property was that it used to be owned by chocolate makers, and rumour has it that our living room used to be used to make the chocolate, an the "slab" is now underneath our patio!!!

Tuesday, 29 October 2013

A Good Place for a Massage

An excellent place for a head massage, or reflexology session is Head Over Heels, in St. Neots, Cambridgeshire.

A relaxing hour in a comfortable environment, with soothing music (if you want!).

All of the details are online here.

TomTom 1005 and Linux

Got a new TomTom, and was expecting the same non-linux-friendly support from TomTom Home, and I wasn't disappointed!

Well, however, a few things are different, since my old TomTom Go Live 530, but not much has changed.

TomTom Home has been replaced with "My Drive", which is a web browser plugin, using Adobe Flash.  Flash communicates with the TomTom via TCP/IP through a windows taskbar application to the device (which is plugged in via USB).

For map updates, you have to use the My Drive program, but what about other features ...

TomTom have removed the feature whereby the GPS looks like a disk drive, so it looked at first like it would not be possible to update / manage favourites / points of interest on a Linux box.

Well, as the device now communicates via TCP/IP, it is possible to access it via a web browser to manage certain aspects, without the need to install any software.

I plugged the TomTom into the USB port, and then connected to:

And voila, an admin screen where I could upload / download my favourites, points of interest, voices, images, car symbols etc.

Under the Bonnet

# lsusb

Bus 001 Device 057: ID 1390:5454 TOMTOM B.V.

# lsmod | grep usb

usbnet       25170  1 cdc_ether
usblp        17752  0
usbhid       41734  0
hid          82179  2 hid_generic,usbhid
usb_storage  39346  0

# ifconfig
usb0  Link encap:Ethernet HWaddr 02:04:06:08:09:0a:0c
inet addr:  Bcast:  Mask:
inet6 addr: fe80::4:6ff:fe08:a0c/64 Scope:Link
RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:115 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:684 (684.0 B)  TX bytes:18836 (18.8 KB)

Monday, 24 June 2013

Vigor 2710 Caller ID PSTN and Relays

I am trying to understand how the relay within the Vigor 2710 ADSL Modem works.

I've got a Skype Freetalk adaptor, which works fine, however, when I plug it into the Vigor 2710 as shown in the picture below, I get the following:
  • PSTN calls don't ring on Phone 1 or Phone 2
  • Skype calls do ring on Phone 2
  • The Caller ID on inbound Skype calls shows up on Phone 2, but the call is not logged in the modem

The Relay is used to switch voice calls to/from the PSTN or the Voip feature within the heart of the modem.

Call Logging (or not)

The modem has some features associated with a relay, but it is not clear how the relay is connected / how it is controlled.  There is a command line option in the modem:
> voip dsp relaydbounce off
> voip dsp relaydbounce   
% voip dsp relaydbounce [on|off]
% on : Enable relay filter noise but it maybe ignore the caller-id!!!
% off: Disable relay filter noise. But the noise will cause the relay to switch to PSTN!!!
I've tried both options for the command, and neither allow the incoming numbers to be logged.

Phone Not Ringing

This one is also strange:
  • If I plug the phone handset directly into the Freetalk box, it rings for incoming.
  • If I plug the PSTN line directly into the 2710 modem, the phones connected to it ring for incoming.
So it suggests that the problem is a combination of the Freetalk box and the modem, but I understand not!


I suspect that an understanding of how the relay is configured in the 2710 modem will help the overall understanding - any help would be greatly appreciated.

OpenBSD and Incorrect UserMod -G

The usermod program is used to manage a user entry in the password and group data files on a unix system.
The OpenBSD version of usermod claims that the -G switch will set the secondary groups (i.e. those in the /etc/group file) for a given user. In actual fact, it appends the user to groups to which he does not belong, and does not remove him from any groups, so it is more of an append, rather than a set.
The source code can be downloaded as follows:

cvs -qd get -P user

And the user.c file needs modifying to:
  • change the append_group function to be modify_group
  • Not to delete the group for any groups to which the user already belongs
  • Remove the \n newline
  • Remove the user from each line when he is found in a group entry
  • Add the user to the end of a line for a requested group
  • Append the \n newline
The diff is run as follows:

cvs diff -u

And the output is here:
Index: user.c
RCS file: /cvs/src/usr.sbin/user/user.c,v
retrieving revision 1.81
diff -u -r1.81 user.c
--- user.c 16 Apr 2011 07:41:08 -0000 1.81
+++ user.c 17 Apr 2011 18:35:26 -0000
@@ -485,9 +485,9 @@
return 1;

-/* modify the group entries for all `groups', by adding `user' */
+/* modify the group entries for all `groups', by adding or removing `user' */
static int
-append_group(char *user, int ngroups, const char **groups)
+modify_group(char *user, int ngroups, const char **groups)
struct group *grp;
struct stat st;
@@ -500,20 +500,19 @@
int cc;
int i;
int j;
+ int c ;
+ int d ;
+ int l ;

+ /* Check groups are valid */
for (i = 0 ; i < ngroups ; i++) {
if ((grp = getgrnam(groups[i])) == NULL) {
warnx("can't append group `%s' for user `%s'",
groups[i], user);
- } else {
- for (j = 0 ; grp->gr_mem[j] ; j++) {
- if (strcmp(user, grp->gr_mem[j]) == 0) {
- /* already in it */
- groups[i] = "";
- }
- }
+ /* Open and lock files */
if ((from = fopen(_PATH_GROUP, "r")) == NULL) {
warn("can't append group for `%s': can't open `%s'", user,
@@ -536,7 +535,10 @@
warn("can't append group: fdopen `%s' failed", f);
return 0;
while (fgets(buf, sizeof(buf), from) != NULL) {
+ /* Load entry from file */
cc = strlen(buf);
if (cc > 0 && buf[cc - 1] != '\n' && !feof(from)) {
while (fgetc(from) != '\n' && !feof(from))
@@ -545,30 +547,53 @@
_PATH_GROUP, buf, cc);
- if ((colon = strchr(buf, ':')) == NULL) {
+ while (isspace(buf[cc-1])) cc-- ;
+ buf[cc]='\0' ;
+ /* Remove username from list */
+ for (c=0,d=0; buf[c]!=':' && buf[c]!='\0'; c++,d++) ;
+ if (buf[d]==':') d++ ;
+ for (; buf[d]!=':' && buf[d]!='\0'; d++) ;
+ if (buf[d]==':') d++ ;
+ for (; buf[d]!=':' && buf[d]!='\0'; d++) ;
+ if (buf[d]!=':') {
warnx("badly formed entry `%s'", buf);
+ l=strlen(user) ;
+ for (i=d; buf[i]!='\0' &&
+ !(strncmp(user, &buf[i], l)==0 &&
+ !isalnum(buf[i+l])); i++) ;
+ if (buf[i]!='\0') {
+ if (buf[i-1]==',') { i-- ; l++ ; }
+ else if (buf[i-1]==':') { l++ ; }
+ for (i+=l; buf[i]!='\0'; i++)
+ buf[i-l]=buf[i] ;
+ buf[i-l]='\0' ;
+ cc=strlen(buf) ;
+ }
+ /* Append username to list if in group */
for (i = 0 ; i < ngroups ; i++) {
- j = (int)(colon - buf);
+ j = (int)c ;
if (strncmp(groups[i], buf, j) == 0 &&
groups[i][j] == '\0') {
- while (isspace(buf[cc - 1]))
- cc--;
- buf[(j = cc)] = '\0';
- if (buf[strlen(buf) - 1] != ':')
+ j=cc ;
+ if (buf[strlen(buf)] != ':')
strlcat(buf, ",", sizeof(buf));
- cc = strlcat(buf, user, sizeof(buf)) + 1;
- if (cc >= sizeof(buf)) {
+ cc = strlcat(buf, user, sizeof(buf)) ;
+ if (cc >= sizeof(buf)-1) {
warnx("Warning: group `%s' would "
"become too long, not modifying",
cc = j + 1;
- buf[cc - 1] = '\n';
buf[cc] = '\0';
+ buf[cc++]='\n' ;
+ buf[cc]='\0' ;
if (fwrite(buf, cc, 1, to) != 1) {
(void) fclose(from);
(void) fclose(to);
@@ -1195,7 +1220,7 @@
errx(EXIT_FAILURE, "can't create gid %d for login name %s",
gid, login_name);
- if (up->u_groupc > 0 && !append_group(login_name, up->u_groupc, up->u_groupv)) {
+ if (up->u_groupc > 0 && !modify_group(login_name, up->u_groupc, up->u_groupv)) {
(void) close(ptmpfd);
errx(EXIT_FAILURE, "can't append `%s' to new groups", login_name);
@@ -1538,7 +1563,7 @@
homedir, pwp->pw_dir);
if (up->u_groupc > 0 &&
- !append_group(newlogin, up->u_groupc, up->u_groupv)) {
+ !modify_group(newlogin, up->u_groupc, up->u_groupv)) {
(void) close(ptmpfd);
errx(EXIT_FAILURE, "can't append `%s' to new groups",
Index: usermod.8
RCS file: /cvs/src/usr.sbin/user/usermod.8,v
retrieving revision 1.25
diff -u -r1.25 usermod.8
--- usermod.8 8 Apr 2011 18:13:54 -0000 1.25
+++ usermod.8 17 Apr 2011 18:35:26 -0000
@@ -103,7 +103,12 @@
.It Fl G Ar secondary-group[,group,...]
Sets the secondary groups the user will be a member of in the
.Pa /etc/group
+file. If the user is not in a group that is listed, the user
+will be added to the
+.Pa /etc/group
+file. If the user is a member of the group in the
+.Pa /etc/group
+file, but is not listed, he will be removed from that group.
.It Xo
.Fl g Ar gid | name | Li =uid
@@ -236,6 +241,9 @@
utility first appeared in
.Ox 2.7 .
+was modified in April 2011 to make the -G switch set secondary groups for user,
+rather than append user to listed groups.