The Nokia Qt SDK

…was just launched as a public beta. It seems this SDK was in the works for quite some time, because there are promotional videos from Nokia with testimonials from early adopters.

The SDK is a one-stop install for all the tools that you need to develop for Symbian (and Maemo). It’s basically a replacement for all the .exes and .zips and .sises that you had to download while following Allesandro’s “Setting up a Symbian development environment” videos. This is obviously a good thing (but I still didn’t dare to install it on a drive other than C).

The contents of the SDK are as follows (I’ll skip the Maemo stuff – I don’t have a device):

  • The Qt Symbian SDK. This looks like a generic SDK which you can use both on touch and non-touch devices. Alessandro mentioned that it doesn’t matter if you download the SDK for Symbian 3rd or 5th because Qt treats it all the same, so I assume that this generic SDK is just a convenience.
  • MinGW + Symbian toolchain. The usual.
  • QtCreator. A snapshot built on the 23rd of April.
  • The Qt sources. 4.6.2 + 4.7.0
  • The Qt simulator. A new program that is supposed to help you get an idea about how your app looks on various devices – both non-touch and touch skins are available. You can simulate all sorts of situations such as incoming messages, having a low battery, sensor input (ambient light, etc), location changes. Very cool and very useful. Looking at the install kit, it seems to just build your app for MinGW or MSVC, my guess is that apps running under the simulator are actually running on your development OS. The simulator is fast, unlike the emulator.
  • .sis setup files for Qt, the TRK and other dependencies.

What was previously the difficult task of getting a Symbian development environment up and running has now become simple. All the developers from the testimonial videos seemed thrilled with the SDK.

Interesting factoid: the testimonial videos indicate that some Qt apps might already be available in the Ovi store. The WIKITUDE app is a suspect at a size of 8.66 MB. What’s even more impressive than the size is that very few people are complaining about it! Most of the reviews are positive, and the negative ones complain that they couldn’t start the app.

More Qt on S60: building an app

I’ve been working on a Qt Symbian S60 app to familiarize myself with Symbian development. After struggling with the build system for about an hour, a passage from Dr. Kenneth Kamler‘s book – Surviving the extremes – popped into my mind:

While crossing an aluminium ladder placed horizontally to bridge a crevasse in the ice, Passang had slipped and fallen 80 feet, wedging himself headfirst between the narrowing walls of ice at the bottom.

Working quickly, a combined team of Spanish and Nepalese climbers managed to get a rope around his waist and hoist him back up to the surface. But by then he had been refrigerated upside down for nearly half an hour.

Fascinating book, I cannot recommend it highly enough. To prevent anyone else from slipping on a makefile and wedging themselves between a library and a .sisx file, I’m going to make the following recommendation about building Qt apps for Symbian: drop all your sources into one folder, build, deploy and run. At this point it seems to be very difficult to build and deploy a SUBDIRS project:

  • The biggest problem is actually an older issue with multi-library projects in Qt: PRE_TARGETDEPS. LIBS works fine, but you can’t change the destination diractories for the target files nor the lib search paths. This means that your PRE_TARGETDEPS should point into the SDK’s build directory -> compiler directory -> build configuration. There are too many path combinations!
  • Even if you somehow managed to make library dependencies work, you can’t create a sis package for SUBDIRS projects.

Not being able to organize source code into libraries will not be such a big hindrance for Symbian-only programs, but it does make it more difficult to manage a cross-platform solution, which is what I was after.

Qt on S60: baby steps

After following Allesandro’s videos I managed to install the Qt SDK and write a small test app for my S60 3.2 phone.

A word of advice: don’t try to be too clever with the install, use paths without spaces and install on drive C. There’s ample opportunity for improvement when it comes to getting a Symbian development environment up and running. Most of the headaches come from the Symbian tools, but the Symbian tools are needed by Qt.

Qt on S60

I proceeded to install Qt on my phone. Qt needs OpenC and the C++ standard libraries to run, so I used the qt_demos.sis installer which handles all the dependencies. The Qt install package is ~4MB in size. The Qt + dependencies package is ~11MB. It’s very big for a mobile phone, but the Smart installer should trim it down. Having the option of selecting which modules to install would be very helpful!

I expect the size to be  a problem for over-the-air installs, including Ovi store. I’ve noticed that Ovi customers are sensitive to the download sizes and most of the Ovi installs kits that I’ve seen were in the <500KB area. The biggest I’ve downloaded was Skype (4MB) and I used wireless for that one.

The install process went alright and I started some of the demos. According to Nokia, the E72 is a Tier 1 device. All the demos that I’ve tried worked, but it’s obvious that most of them were designed for touch-screen devices; the touch version of Symbian seems to get more attention, all the Qt demos I’ve seen were done on a 5800 or maybe N97. A few apps had the window overflow from the screen (a known problem – seems to happen even with layouts) while others simulated a mouse cursor which was difficult to operate with a D-pad.

It’s worth noting that the apps worked and that the issues were mostly UI related. I don’t think that programs can be ported to non-touch phones without a complete UI redesign. Take the FTP app for instance: works perfectly but it is cumbersome to use because the server lineedit, the cdup and download buttons take half of the screen leaving too little space for the tree widget.

As far as I can tell the trick to having a usable S60 3.2 UI is using lists, tabs, soft keys + menus and shortcut keys. From the OS main menu to the music player and clock almost everything is a list. The file manager displays the file system in lists. QuickOffice’s main screen is a list. It’s lists all the way down…

Maybe UIs are hard to get right in non-touch Symbian. I’ve seen few programs with a nice UI and I’ve been using Symbian on and off since Nokia 7650. I’ve bought an acclaimed Finance tracking app written in Flash from the Ovi store recently and it displays itself in portrait mode on my landscape screen making it completely unusable.

Anyway, back to Qt: I have used Qt Creator 1.3.1 for deploying to the device and debugging. The AppTRK will try to listen for debugger connections on port 1 while QtC will try to connect on something like port 17. It’s a known issue and I solved this by using the device manager to make the E72 connect on port 1.

The debugger jumped to assembly directly when encountering a breakpoint. I also tried a recent snapshot but it didn’t stop at the breakpoint at all. This is also a known issue which will hopefully be fixed in 2.0.

These two issues aside, the whole process was straightforward, not unlike developing a regular Qt program. All in all, I think that when Qt Mobility, the Smart installer and QtC 2.0 come out, Qt development will be more attractive on Symbian.

The Nokia e72

It’s nice, but not great. I had a Symbian UIQ phone before this one and while I can see that the E72 is better overall, there are little annoyances that prevent me from being completely happy with it.

I’m also not sure where this phone stands in relation to Qt. Qt development was one of the reasons that I bought it for, seeing that it’s tier 1, and the top of the line in the E series, but it doesn’t seem to be getting too much Qt-tention.

The Ovi store

I watched a presentation about getting your Qt apps on the Ovi store and the costs were 200$ for the publisher id, 10$ for signing the app and 10$ for signing the smart installer. Since the smart installer is in beta, it’s not allowed on the store yet, which means that users are looking at a few megabytes of downloads. I’m not even sure that you can publish a Qt app to the store yet, because technically it’s two downloads right now: one for Qt and one for the actual app.

One thing’s for sure: getting software from Ovi is much more convenient than the old days when you had to use various aggregator sites or buy straight from the publisher. A good Qt-Ovi integration should be a priority for Nokia.

Logging in Qt land

Sooner or later you’ll want to add logging to your Qt program. What are your options? After looking around the web a few years ago, I was disappointed to find out that there was no official Qt logging library. There is some support in Qt for logging, but you won’t get a logger component and it’s not immediately obvious how to log into a file.

The third party support that I had found wasn’t particularly encouraging:

  • There was a Log4Qt based on Log4j that was at version 0.1 back then. It has since reached version 0.3 at  the beginning of 2009, but there are no check-ins for the last 12 months.
  • Then there was the QxtLogger class, part of the qxt library. This one looked much more promising, but the API is a bit cumbersome (you have to pass the things that you want to log as QVariants  or as a QVariantList) and it was LGPL, which meant an extra dynamic library dependency.
  • A multitude of non-Qt C++ loggers, heavyweights like log4cxx or Pantheios.

What I really wanted was a simple logging library that knew about Qt types that I could just drop into my project in a few cpp files and then forget about it. After reading the Qt docs, I wrote a proof of concept logger with multiple destinations and logging levels. It would use qInstallMsgHandler to set up a static function that would build a message based on the text received from qDebug(), the current date and time,  the log level and send it to a list of destinations.

That was the same implementation that I cleaned up and decided to publish yesterday, only to find out in the mean time that using qInstallMsgHandler is not a good idea at all…

The simple solution that fails

The Qt docs mention that one could install a custom message handler that is called by the qDebug function family when doing the output. Basically, when you write qWarning() << “Parameter out of range:” << 1.0 << << “-” << 2.0, the custom message handler will see an array of char “Parameter out of range: 1.0 – 2.0″ and the message type, which is one of debug, warning, critical and fatal.

There are two issues with this approach:

  • the custom message handler must be a free function
  • there are too few logging levels!

My original implementation easily solved the first problem by using a singleton logger class. The custom handler just called Logger::instance() and was itself a static member of Logger, which meant that it had access to all its member variables.

The second problem was more tricky, but I managed to get around it by writing a special character at the beginning of the log message depending on the log level. If I wanted to log an info message, I would write QLOG_INFO() << “message”, which was translated into qDebug() << QsLogging::detail::infoMessage << “message”. The custom handler would then remove the QsLogging::detail::infoMessage from the message and pass it on to each destination.

Simple and it worked: I could use more logging levels and log to multiple destinations with a convenient syntax. Unfortunately, this custom handler had some subtle bugs.

For starters, when you install a custom message handler, all messages from qDebug/qWarning/etc will be sent to your handler. This means that Qt’s warnings or asserts would also end up in the handler and that the logger itself could trigger another log call. This could result either in a deadlock or an endless loop.

I had two choices: not use any Qt types in the custom handler and the log class or detect Qt’s messages and send them to the default handler. I chose the second, only to find out that there is no default handler, or at least not always.

qInstallMsgHandler can return NULL as the old handler. The function that calls the custom message handler is named qt_message_output and lives in qdebug.h. The docs mention that

The default message handler prints the message to the standard output under X11 or to the debugger under Windows. If it is a fatal message, the application aborts immediately.

The defaults are coded directly in qt_message_output, which checks to see if there’s any handler installed. My old handler was zero so I couldn’t forward Qt’s messages to it and I couldn’t forward them to my log. Even if I could somehow access the default handler, it was not thread safe, which meant that I would have to use platform specific synchronization (QMutex would not be available).

Custom message handlers were starting to be more trouble than they were worth, so I started looking at the qDebug implementation.  qDebug just returns an instance of the QDebug object, which does all the message formatting and sends the final message to qt_message_output when it’s destroyed.

The even simpler solution

Maybe I could use QDebug to get all the formatting for free? The QDebug constructor can take a QtMsgType debug level, a QIODevice or a QString.  Only when a QtMsgType is used will the QDebug destructor call qt_message_output.

As an example you could easily write a class MyFileLog which keeps  a QFile and gives you access to a QDebug(MyFileLog::theFile) for logging. In my case, I used the QString constructor and a wrapper to make QDebug give me the formatted log message and notify the logger that it should send the message to the destinations.

The final implementation is available at my bitbucket repository under a BSD license. It features a file and debugger destination, 6 logging levels, level filtering and can be added directly into a project. Since it’s based on QDebug, you can log most Qt types such as QVector or QHash directly or extend it for other types.

My conclusion is that you can use qInstallMsgHandler to control Qt’s messages, but you should use something more flexible for logging. Give QsLog a try and let me know what you think. Bugs & suggestions can be submitted directly at the repository.

ScopeGuard for signals: first try

While working with state machines in Qt I have encountered the typical situation where a state can be exited through a “fail” transition or a “success” transition. In my case, both transitions were triggered by signals and the signals were emitted from a checker function.

The success transition was easy since there’s usually only one way to do things right, but the failure transition could be triggered from multiple places inside the checker function. Every few lines I would check for some condition, do a few things, emit failed(), and return. Every few other lines I would forget to emit failed() and get some interesting bugs. Fun as that was, I got tired of it pretty fast… hence SignalGuard!

SignalGuard is a ScopeGuard that works with the moc and signals instead of template tricks and arbitrary functions. It automatically emits a signal when the SignalGuard object is destroyed, simplifying emits when dealing with multiple exit points.

Here’s a quick example:

SignalGuard cancelGuard(this, SIGNAL(requestCanceled()));
// do check one, if failed show a message, return
// do check two, if failed show a message, return
// do check three, if failed show a message, return
cancelGuard.dismiss(); // phew, we've made it

The signal guard will automatically emit requestCanceled when it is destroyed unless we dismiss() it. A maintenance programmer that will add other checks won’t introduce a subtle bug by forgetting to emit the canceled signal and the code is cleaner too!

Here’s another example:

emit uiWait(); // show a busy cursor
foo();
bar();
emit uiFinishWait(); // show a regular cursor

Without SignalGuard, we’d probably have to rewrite the above code or risk being stuck with an hourglass cursor:

emit uiWait();
try
{
  foo();
  bar(); // what if this throws?
}
catch( std::exception& )
{
  emit uiFinishWait();
  throw;
}
emit uiFinishWait();

But why complicate the control flow when you could write this instead:

SignalGuard g(this, SIGNAL(uiFinishWait()));
emit uiWait();
foo();
bar();

That’s about all that SignalGuard does right now. You can download the sources from my brand new bitbucket repository. The code is really simple – that’s why this is labeled first try – but I’d like to extend it to allow specifying the connection type (easy) and signals/slots with parameters (tricky, I need the parameter types).

QTL or STL?

First, a little history: when I started working with Qt I was coming from a STL/Boost background and was accustomed to using the STL containers and strings. On the first Qt project that I’ve worked on, a Linux port for a large-scale C++ system, the team’s approach was to use Qt strictly for the UI and the STL, Boost and other libraries for everything else.

At that time, I didn’t even know there was a QTL and I was using std::(w)string pretty much everywhere. After working on more Qt projects, I now use the QTL everywhere and have extensive experience with both libraries. My conclusion is that there is no clear winner in this comparison, that the choice can be quite complicated depending on the project type, and switching from one library to the other poses some subtle difficulties.

Containers

The STL and Qt have a different philosophy when it comes to containers:

STL

  • The containers are very parameterizable and built for maximum speed.
  • Has performance guarantees for each container.
  • Each implementation can use copy-on-write as it sees fit.
  • Free, generic functions are prefered to member functions.
  • There are multiple container implementations, just as there are multiple standard library implementations.
  • … and those implementations are not binary compatible, but they must obey the C++ standard. This includes the interfaces and performance guarantees.
  • Each implementation is free to do whatever optimizations that it pleases as long as it respects the standard.
  • Provides regular iterators.
  • Only includes a hash in TR1.
  • Only includes a variable length array in TR1.
  • Have a header-only implementation and the compiler has access to all the source code.
  • Has the <algorithm> header.

QTL

  • Containers are not parameterizable. Don’t like the default memory allocator? Well, that’s too bad…
  • Provides a list of performance guarantees in the docs.
  • Use copy-on-write to avoid needless expensive copies.
  • Lots of member functions provided for convenience. e.g: contains, indexOf, removeAt, takeAt, uniqueKeys, startsWith, etc
  • One implementation that is binary compatible between major releases but not major versions. i.e: Qt 4.5 is compatible up to Qt 4.9, but Qt 3.2.2 is not compatible with Qt 4.0
  • Qt containers do optimizations which are available on all operating systems.
  • Can use STL-style iterators or Java-style iterators.
  • Includes a hash and multihash implementation.
  • Includes QVarLengthArray.
  • Are not header only. Some functions are not available when building your program and they can’t be used for global optimizations.
  • Has the <QtAlgorithm> header.

If you will use the Qt containers together with the Qt framework, you will get a few other advantages:

  • Qt containers are streamable by default with QDataStream. This means that you only have to write a streaming operator for your user defined contained type.
  • They are used extensively in Qt’s API. If you use STL containers you will almost certainly have to make conversions.
  • Some signal slots connections copy their parameters. Since the Qt containers use COW, copying them is less costly.
  • You can use Q_FOREACH with Qt containers. Since Q_FOREACH does a copy of the target container, it would be too expensive to use with the STL.

My opinion is that the biggest advantage of the QTL is that it has the same implementation (including binary compatibility) on all OSes supported by Qt.  Some STL implementations might be below par when it comes to performance or they might be missing functionality. Some platforms don’t even have an STL! On the other hand, the STL is more customizable and is available in its entirety in header files… Like I said, there is no clear winner.

Strings

When deciding about using QString instead of std::(w)string, there are few points to consider:

  • QString scores a lot higher than std::basic_string when it comes to usability.
  • It offers Unicode support.
  • It lives in a dll/so, which means that whole program optimizations won’t be available. This can be worked around by linking with Qt statically, but the static vs dynamic debate is quite complicated and a decision has wider reaching effects.
  • Doesn’t allow customization through character traits or custom allocators. In fact, QString is a regular class, not a template and it can easily be forward declared.

Personally, I almost always use QString if I’m using Qt. I originally used conversion helpers to avoid a deep Qt dependency, but unless most of your program is Qt-free, it’s not worth it to use both QString and std::string.

Not a drop in replacement

Qt containers are STL-compatibile in the way that they provide iterators that match the STL algorithm library and the container interfaces mimic the STL ones. In addition to this, there’s an STL compatibility mode that allows you to directly convert to and from a STL container when you’re working with its Qt counterpart. e.g: QVector::toStdVector

Even so, you can’t swap between Qt and STL containers as easily as replacing a type definition:

  • QVector::at doesn’t do range checking besides an assert.
  • QList provides index-based access and is more similar to a std::deque. QLinkedList is probably the closes thing to std::list.
  • There are no constBegin, constEnd, constFind, etc functions in the STL. You might not easily be able to take advantage of Qt’s COW implementation.
  • The QMap and QMultiMap interfaces differ from the std::map and std::multimap ones. In particular, there’s no equal_range function.
  • Qt containers can’t be parametrized with an allocator.

Smart pointers

Thiago Maceira from Nokia/ex-Trolltech has done an excellent summary of the Qt smart pointers. If you read this summary, you’ll know 99% of what’s to know about Qt’s smart pointers.

I have added only a few observations from experience:

  • Unfortunately TR1 is not as wide spread as I would like at this point and I find it much easier to use the Qt shared pointer instead of introducing a large Boost dependency in a project.
  • QScopedPointer supports d-pointers and custom deleters. AFAIK, neither scoped_ptr nor auto_ptr do.