I have been developing cross-platforms C++ applications for some years now. In this post I would like to share my experience on several aspects of C++ cross-platform development, mainly focusing on Windows and Linux and using Qt.
Keeping your build project files (makefiles on unix, Visual Studio project files) in sync manually is a hassle and error prone task. To help with that I have tried several alternatives: cmake, qmake and bjam. I found that the easiest to use by far is qmake, part of the Qt toolkit.
qmake is my first choice when it comes to cross-platform development. It is not as powerful as cmake but its language is much simpler and concise. Imagine we would like to compile the helloworld program of my previous post. This qmake helloworld.pro file will suffice as build script:
The template app tells qmake we would like to build an application. By default, in Windows this means to creating an .exe file that runs on a console.
If we would like to use an IDE to build the project, we can just open the .pro file with QtCreator, or we are using Visual Studio we can actually generate the solution files from the command line.
Because Visual Studio has the concept of “solution”, a root file that points to different projects, we need to create an equivalent to the .sln file, in this case, a .pro file that point to the other .pro files. In our case, I created a helloworld_global.pro file:
TEMPLATE = subdirs
helloworld.subdir = helloworld
helloworld.target = helloworld
SUBDIRS += helloworld
which looks for a .pro file called helloworld in the helloworld folder. Then I was able to generate the VS project files with:
%QTDIR%\bin\qmake -r -spec win32-msvc2013 -tp vc Q
The spec specifies the pair platform/compiler version to use. In my case because the spec was win32-msvc2013 and I was using a x64 native tools command prompt this generated 64-bit Visual Studio 2013 solution, that could be opened with the file helloworld_global.sln.
Many of the features of qmake are very straightforward, including adding precompiled headers portably.
I do not recommend using the Visual Studio Qt wizards to manage the VS project files. I feel much more practical to use the .pro file as a single point of truth and then use the command line to generate the VS project files.
cmake is probably the most popular and powerful toolkit for building cross-platform C++ code.
Its syntax is a bit cumbersome (for instance because it does not have compound statements, so sometimes you have to explicitly mark which statement is being ended, i.e. if you have nested ifs you may need to specify which if you are actually closing of all the ifs that were opened).
cmake has a GUI which is very handy for inspecting and change the value of the cmake variables in a CMake build directory.
bjam is a nifty tool. It is a good idea to use it if you are generating Boost Python, as it will take care that all the compiler options that are needed to interface C++ with Python are actually used. Unfortunately, it is not well-documented (when I used it, I had to look in the boost code which options where available).
Processes and threads
C++11 introduced added language support to multithreading to C++. If you are using a pre-C++11 compiler and still want portable threading you can use boost (which primitives are very similar to C++11) or Qt.
Unfortunately there is still not a way in the C++ language to create processes, as process handling is very different between systems. Nevertheless Qt includes QProcess which allows you to manage processes in a portable way.
I developed a GUI for C++ using GTK around 10 years ago. I used glade to generate the code, and I really liked it at the time. The callback code needed the use of a lot of macros used emulate a type hierarchy (GTK is C based), but I thought it was mainly clean and neat anyway.
Unfortunately, as of 2016, it seems that GTK does not seem to be so well supported outside of Linux, specially if compared with Qt. Many projects that used GTK have moved to Qt.
Qt is C++ based and has many features that are interesting for GUI development. For instance, it has internalization support; its widgets take into account that some languages are written right to left, some have several accents, some have ligatures… It also allows you create a XML repository of translations that you can query at runtime depending on the locales. E.g. this element in qt_es.ts (included in Qt itself):
Will instruct Qt to translate “File” to “Fichero”, when the Spanish/Spain locale is being used. E.g. the code:
QMenu *menu = new QMenu(menuBar);
will create a menu with the name “Fichero”. The macro tr() should be used for any string literal that could be displayed to the user, so the literal will be translated before displaying it.
Qt has also Android, iphone and Windows Phone support. For mobile development, Qt provides QML, a mark-up language which provides a good way to specify small user interfaces using a declarative language.
Compilers implemented the C++11 standard at different speeds, and for some time this made the newest features in the standard not very portable. Fortunately, as of 2016, all the major compilers support C++11 almost in full.
There are still differences, though, the Visual Studio preprocessor is not standard compliant and fails when passing variadic data as a whole directly into a non-variadic macro.
Nevertheless Microsoft has promised to integrate the clang front-end in Windows as well, so in the future developing cross-platform C++ applications using Visual Studio should be completely hassle-free.
Subversion and end-of-line
Subversion is still probably the most popular centralized version control system. One problem it has when used in cross-platform development is that, by default, it does not pay attention to end of line markers. This means that, for example, if we commit a file on Linux and then check it out on a Windows machine, the editor may display the whole file in a single line, as it will not have carriage returns which the Windows programs expect.
The best solution to the problem is to use eol-style=native, that can be specified in subversion´s config file:
enable-auto-props = yes
*.cpp = svn:eol-style=native
This instructs svn to check out *.cpp files differently according to the platform. LF on UNIX and CRLF on Windows, the native end of line character on each one. We would need to do the same for every file extension that could cause problems.