<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mardy (Posts about QBS)</title><link>http://mardy.it/</link><description></description><atom:link href="http://mardy.it/categories/qbs.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:info@mardy.it"&gt;Alberto Mardegan&lt;/a&gt; </copyright><lastBuildDate>Sat, 11 Apr 2026 13:53:51 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>QHtmlParser: writing an HTML parser with your brain switched off</title><link>http://mardy.it/blog/2021/10/qhtmlparser-writing-an-html-parser-with-your-brain-switched-off.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;While developing &lt;a href="https://gitlab.com/mardy/mitubo"&gt;MiTubo&lt;/a&gt; I've recently felt
the need of parsing HTML pages: the first problem I wanted to solve was
implementing proper RSS feed detection when the user entered a website URL into
MiTubo's search box, so that MiTubo would parse the site's HTML, look for
&lt;code&gt;&amp;lt;link rel="alternate"...&amp;gt;&lt;/code&gt; URLs in the &lt;code&gt;HEAD&lt;/code&gt; section, and let the user
subscribe to any video feeds found there.&lt;/p&gt;
&lt;p&gt;A quick search in the internet did not provide a clear answer: I found &lt;a href="https://github.com/cutelyst/html-qt"&gt;a Qt
HTML parser in (stalled) development&lt;/a&gt;, and
a few other C++ or C parsers (among the latters,
&lt;a href="https://github.com/lexbor/lexbor/tree/master/source/lexbor/html"&gt;lexbor&lt;/a&gt;
is the most inspiring), but all of them seem to take the approach of parsing
the HTML file into a DOM tree, while I was hoping to find a lightweight
SAX-like parser. Pretty much like Python's
&lt;a href="https://docs.python.org/3/library/html.parser.html"&gt;html.parser&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, I don't remember how it happened, but at a certain point I found myself
looking at &lt;code&gt;html.parser&lt;/code&gt; source code, and I was surprised to see how compact it
was (apart, of course, for the long list of character references for the HTML
entities!). Upon a closer look, it also appeared that the code was not making
much use of Python's dynamic typing, so, I thought, maybe I could give it a try
to rewrite that into a Qt class. And a few hours later
&lt;a href="https://gitlab.com/mardy/qhtmlparser"&gt;QHtmlParser&lt;/a&gt; was born.&lt;/p&gt;
&lt;p&gt;As this post's title suggests, the process of rewriting &lt;code&gt;html.parser&lt;/code&gt; with Qt
was quite straightforward, and the nice thing about it is that I didn't have to
spend any time reading the HTML standard or trying to figure out how to
implement the parser: I just had to translate Python code into C++ code, and
thanks to the nice API of QString (which in many ways resembles Python's — or
vice versa) this was not too hard. I even left most of the original code
comments untouched, and reused quite a few tests from the test suite.&lt;/p&gt;
&lt;p&gt;It was time well spent. :-)&lt;/p&gt;
&lt;p&gt;If you think you might need an HTML parser for your Qt application, you are
welcome to give it a try. It's not a library, just a set of files that you can
import into your project; for the time being I only have a build file for
&lt;a href="https://doc.qt.io/qbs/overview.html"&gt;QBS&lt;/a&gt;, but I'll happily accept
contributions to make it easier to use QHtmlParser with projects built using
other build systems. You can see
&lt;a href="https://gitlab.com/mardy/mitubo/-/commit/531bd4e8b0d354aad5bb3e749073ddf16f6fe625"&gt;here&lt;/a&gt;
the changes I made in MiTubo to start using it and detect RSS feed in a
webpage's HEAD.&lt;/p&gt;
&lt;p&gt;That's all for now. And in case you missed the link before, you can find
QHtmlParser &lt;a href="https://gitlab.com/mardy/qhtmlparser"&gt;here&lt;/a&gt;.&lt;/p&gt;</description><category>english</category><category>informatica</category><category>kdeplanet</category><category>Linux</category><category>MiTubo</category><category>planetmaemo</category><category>programmation</category><category>QBS</category><category>Qt</category><category>Ubuntu</category><guid>http://mardy.it/blog/2021/10/qhtmlparser-writing-an-html-parser-with-your-brain-switched-off.html</guid><pubDate>Sun, 10 Oct 2021 19:57:28 GMT</pubDate></item><item><title>Announcing CuteVNC</title><link>http://mardy.it/blog/2020/12/announcing-cutevnc.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;Having a single screen connected to my PC, I was wondering if I could use my
nice &lt;a href="https://en.wikipedia.org/wiki/BQ_Aquaris_M10"&gt;BQ M10 tablet&lt;/a&gt; running
UBports as an additional screen. The idea was that if I could convince the X
server to create a new virtual display, and then run the x11vnc server on it, I
could then connect the tablet to it and enjoy my desktop on two screens. Yes,
the M10 has not such a big display, but it couls still be useful to host a
window with a mail or a chat client, so that I would not need to switch between
applications just to check if new emails or chat messages have arrived (and I
hate instant notifications, so I tend to disable them in every program that
allows me to).&lt;/p&gt;
&lt;p&gt;Anyway, I digress. I found some articles, and specifically &lt;a href="https://unix.stackexchange.com/questions/156412/vnc-server-as-a-virtual-x11-monitor-to-expand-screen"&gt;this
question&lt;/a&gt;,
that show how one can add a new virtual screen and connect to it via VNC. I
tried it and it kind of worked, but there were some visual artifacts that
annoyed me (most likely due to the AMDGPU drivers), so I'll defer the creation
of a demo video till when I'll have figured out a better setup. But the main
point is that the idea, in principle, can work.&lt;/p&gt;
&lt;h2&gt;CuteVNC&lt;/h2&gt;
&lt;p&gt;So I sat down and started writing a VNC client for UBports, since it appears
that there wasn't one yet in the store. I use the past tense, because after a
week or so of work, &lt;a href="https://open-store.io/app/it.mardy.lomiri-vnc"&gt;CuteVNC is
there&lt;/a&gt;. It's still a very alpha
version, and does seem to get confused if the VNC server is using caching, but
overall it's working. Its impressive feature list includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can connect to a VNC server, and show the remote display&lt;/li&gt;
&lt;li&gt;Can send mouse events&lt;/li&gt;
&lt;li&gt;Windowed and fullscreen mode&lt;/li&gt;
&lt;li&gt;Pinch to zoom&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There's a lot more that could be done, but for a first release this can be OK.&lt;/p&gt;
&lt;h2&gt;Development of a UBports Qt/QML app with QBS&lt;/h2&gt;
&lt;p&gt;If, like me, you are a fan of QBS, you might want to have a look at the &lt;a href="https://gitlab.com/mardy/lomiri-vnc"&gt;source
code of CuteVNC&lt;/a&gt; (yes, the project was
born as "Lomiri VNC", but since it's a generic QtQuick.Controls 2 application,
there was no need to tie it to the Lomiri environment); there you can find a
&lt;a href="https://gitlab.com/mardy/lomiri-vnc/-/tree/master/qbs/modules/ubuntutouch"&gt;QBS module for UBports
applications&lt;/a&gt;,
which can help in filling in the manifest file and deploying other Ubuntu Touch
specific files into their proper install location.&lt;/p&gt;
&lt;p&gt;You can also see the &lt;a href="https://gitlab.com/mardy/lomiri-vnc/-/blob/master/clickable.json"&gt;configuration
file&lt;/a&gt; to make
&lt;a href="https://clickable-ut.dev/en/stable/"&gt;clickable&lt;/a&gt; build a QBS-based project. In
my mental task backlog I still have the idea of making clickable support QBS
out of the box, but the integration of the two technologies is so easy even
now, that I gave this task a quite low priority.&lt;/p&gt;
&lt;h2&gt;A class for computing viewport transformations&lt;/h2&gt;
&lt;p&gt;Last but not least, a developer might find useful the &lt;a href="https://gitlab.com/mardy/lomiri-vnc/-/blob/master/src/scaler.h"&gt;generic Scaler
class&lt;/a&gt; I wrote
to compute the viewport transformations: it's a simple, QtGui-only C++ class
which takes an input structure with the viewport information, and returns a
similar structure containing a &lt;a href="https://doc.qt.io/qt-5/qtransform.html"&gt;QTransform
matrix&lt;/a&gt; to map item coordinates to
coordinates in the source object coordinates (in my case, the source object is
the remote screen served by VNC) and some other useful parameters, such as the
scale, center offset, and the painted area rectangle.&lt;/p&gt;
&lt;p&gt;The class has a 100% line and branch coverage in the &lt;a href="https://gitlab.com/mardy/lomiri-vnc/-/blob/master/tests/tst_scaler.cpp"&gt;unit
tests&lt;/a&gt;,
so I hope I can rely on it.&lt;/p&gt;</description><category>english</category><category>informatica</category><category>kdeplanet</category><category>programmation</category><category>QBS</category><category>QML</category><category>Qt</category><category>Ubports</category><category>Ubuntu</category><guid>http://mardy.it/blog/2020/12/announcing-cutevnc.html</guid><pubDate>Sun, 13 Dec 2020 13:38:48 GMT</pubDate></item><item><title>New website for Mappero Geotagger, and cross-compiling stuff</title><link>http://mardy.it/blog/2020/04/new-website-for-mappero-geotagger.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;Mappero Geotagger has now moved from &lt;a href="http://www.mardy.it/mappero-geotagger/"&gt;its previous page from this
site&lt;/a&gt; to a &lt;a href="http://mappero.mardy.it"&gt;new, separate
website&lt;/a&gt; built with the awesome &lt;a href="http://getnikola.com"&gt;Nikola static website
generator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The main reason for this change is that I didn't have an online space where to
host the application binaries, and I wanted to experiment with a different
selling method. Now, downloads are (poorly) hidden behind a payment page,
whereas in multiple places of the website I also mention that I can provide
the application for free to whomever asks for it. While it might seem weird at
first, I do honestly believe that this will not stop people from buying it:
first of all, many people just think it's fair to pay for a software
applications, and secondly, for some people writing an e-mail and establishing
a personal contact with a stranger is actually harder than paying a small
amount of money. And in all sincerity, the majority of the income I've had so
far for Mappero Geotagger came from donations, rather than purchases; so, not
much to lose here.&lt;/p&gt;
&lt;h3&gt;QBS and MXE&lt;/h3&gt;
&lt;p&gt;Anyway, since this is primarily a technical blog, I want to share my
experiences with cross-building from Linux to Windows. As you might remember,
&lt;a href="http://mardy.it/blog/2019/07/qbs-and-code-coverage-reports.html"&gt;some time ago I switched the build system of Mappero from qmake to
QBS&lt;/a&gt;, and I haven't regretted it at
all. I've managed to build the application in Linux (of course), macOS, as a
Debian package on the &lt;a href="https://launchpad.net/~mardy/+archive/ubuntu/mappero"&gt;Ubuntu PPA
builders&lt;/a&gt;, on &lt;a href="https://ci.appveyor.com/project/mardy/mappero"&gt;Windows
with AppVeyor&lt;/a&gt; and, last but not
least, on Linux for Windows using the mingw setup provided by the &lt;a href="http://mxe.cc"&gt;MXE
project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;QBS worked surprisingly well also in this case, though I had to fight with a
small bug on the toolchain detection, which is hopefully going to be &lt;a href="https://codereview.qt-project.org/c/qbs/qbs/+/296870"&gt;fixed
soon&lt;/a&gt;. For the few of you
who are interested in achieving something similar, here's the steps I ran to
configure QBS for mingw:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;MXE_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;path-to-mxe&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;MXE_TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x86_64-w64-mingw32.shared&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 32 bit or static targets are also available&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;MXE_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mxe"&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;QT_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MXE_PROFILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-qt"&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;qbs&lt;span class="w"&gt; &lt;/span&gt;setup-toolchains&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MXE_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/usr/bin/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MXE_TARGET&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-g++"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$MXE_PROFILE&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;qbs&lt;span class="w"&gt; &lt;/span&gt;config&lt;span class="w"&gt; &lt;/span&gt;profiles.&lt;span class="nv"&gt;$MXE_PROFILE&lt;/span&gt;.cpp.toolchainPrefix&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MXE_TARGET&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# temporary workaround&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;qbs&lt;span class="w"&gt; &lt;/span&gt;setup-qt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MXE_BASE&lt;/span&gt;&lt;span class="s2"&gt;/usr/&lt;/span&gt;&lt;span class="nv"&gt;$MXE_TARGET&lt;/span&gt;&lt;span class="s2"&gt;/qt5/bin/qmake"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;QT_PROFILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;qbs&lt;span class="w"&gt; &lt;/span&gt;config&lt;span class="w"&gt; &lt;/span&gt;profiles.&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;QT_PROFILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;.baseProfile&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$MXE_PROFILE&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sorry for using that many environment variables ☺. After qbs is configured,
it's just a matter of running &lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;qbs&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="nv"&gt;$QT_PROFILE&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;to build the application. You will get a nice window binary and, once you
collect all the needed library dependencies, you'll be able to run it on
Windows. Or WINE ☺.&lt;/p&gt;
&lt;p&gt;As part of this effort, I also had to build &lt;a href="http://libraw.org"&gt;libraw&lt;/a&gt;, so I
didn't miss the occasion to &lt;a href="https://github.com/mxe/mxe/pull/2481"&gt;contribute its recipe to
MXE&lt;/a&gt;. I'm also trying to get a change
accepted, that would make MXE &lt;a href="https://github.com/mxe/mxe/pull/2480"&gt;support the dynamic OpenGL
selection&lt;/a&gt; available since Qt 5.4.&lt;/p&gt;</description><category>english</category><category>gps</category><category>informatica</category><category>kdeplanet</category><category>mappero-geotagger</category><category>photographia</category><category>planetmaemo</category><category>programmation</category><category>QBS</category><category>Qt</category><category>Ubuntu</category><guid>http://mardy.it/blog/2020/04/new-website-for-mappero-geotagger.html</guid><pubDate>Sun, 12 Apr 2020 09:20:55 GMT</pubDate></item><item><title>Qbs and code coverage reports</title><link>http://mardy.it/blog/2019/07/qbs-and-code-coverage-reports.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;You know that I'm not an &lt;em&gt;early adopter&lt;/em&gt;. That's why it was only a couple of
weeks ago when I decided to give &lt;a href="https://doc.qt.io/qbs/"&gt;Qbs&lt;/a&gt; a try, by using
the good old &lt;a href="https://www.mardy.it/mappero/"&gt;Mappero&lt;/a&gt; (and its spin-off,
&lt;a href="https://www.mardy.it/mappero-geotagger/"&gt;Mappero Geotagger&lt;/a&gt;) as a test bench.
Yes, I know that the Qt company is not going to maintain Qbs anymore in the
future, but the little I knew about Qbs was enough to convince me that it's a
project worth supporting. So, better late than never -- and hopefully the
community (me included) will do a good job in keeping Qbs thriving.&lt;/p&gt;
&lt;p&gt;Having Mappero build with Qbs was the simplest thing ever. The only issue I met
was in building the unit tests, because I'm used to set the &lt;code&gt;rpath&lt;/code&gt; on test
executables in order to make it easy to run them uninstalled, and with &lt;code&gt;qmake&lt;/code&gt;
I achieved that with this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;QMAKE_RPATHDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;QMAKE_LIBDIR&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In turns out that with Qbs you can do it in almost the same way, but for some
reason I couldn't figure it out and I even &lt;a href="https://bugreports.qt.io/browse/QBS-1455"&gt;reported a
bug&lt;/a&gt; to which I got some nice
suggestions, before eventually settling on this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;qbs&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;

&lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"path-test"&lt;/span&gt;

    &lt;span class="k"&gt;files:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"path-test.cpp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"path-test.h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"paths.qrc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;Depends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Mappero"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;cpp.rpaths:&lt;/span&gt; &lt;span class="nx"&gt;cpp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;libraryPaths&lt;/span&gt;    &lt;span class="c1"&gt;// &amp;lt;-- this does the trick!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It's surprisingly similar to how it's done in qmake, so it's not clear even to
me why I didn't guess that immediately. Anyway, that was literally my only
problem, and you can see the whole set of Qbs files I wrote by having a look at
&lt;a href="https://gitlab.com/mardy/mappero/commit/2a19b59f018cd0517d37eadd24d1aa1780140e4b"&gt;this
commit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Given how easy the migration was, I thought I should also try to add a code
coverage report; that's not something I had in my qmake build either, but it's
something I really want to have in all my newer projects.&lt;/p&gt;
&lt;h3&gt;Teaching Qbs to make a code coverage report&lt;/h3&gt;
&lt;p&gt;Unfortunately, my search for examples on how to have Qbs prepare a coverage
report was mostly insuccessful, but thanks to some amazing help from Christian
in the #qbs IRC channel, this was not hard to achieve. So, I hope to be of some
help myself too, by sharing how this works.&lt;/p&gt;
&lt;p&gt;First of all, it must be said that Qbs doesn't know anything about code
coverage, at all. However, it's possible (and often easy) to extend Qbs by
adding your own &lt;code&gt;Product&lt;/code&gt; with its own set of build rules, so here's the
&lt;code&gt;CoverageReport&lt;/code&gt; item for Mappero (though, it should be general enough to be
reusable in your own project):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;qbs&lt;/span&gt;

&lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"coverage"&lt;/span&gt;

    &lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="k"&gt;outputDirectory:&lt;/span&gt; &lt;span class="s2"&gt;"coverage-html"&lt;/span&gt;
    &lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="nx"&gt;stringList&lt;/span&gt; &lt;span class="k"&gt;extractPatterns:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;builtByDefault:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="k"&gt;files:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"**"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;type:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"coverage.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;Depends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;productTypes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"autotest-result"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;Rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;multiplex:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="k"&gt;explicitlyDependsOnFromDependencies:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"autotest-result"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;outputFileTags:&lt;/span&gt; &lt;span class="s2"&gt;"coverage.html"&lt;/span&gt;
        &lt;span class="k"&gt;requiresInputs:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="k"&gt;prepare:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;captureCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lcov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"--directory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--capture"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--output-file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--no-checksum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--compat-libtool"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="nx"&gt;captureCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Collecting coverage data"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;captureCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;captureCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;captureCmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;extractArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extractPatterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;extractArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"--extract"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;extractArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;extractArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extractPatterns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extractPatterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;extractArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"-o"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;extractArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;extractCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lcov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;extractArgs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;extractCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Extracting coverage data"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;extractCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;extractCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;extractCmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;filterCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lcov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"--remove"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'moc_*.cpp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--remove"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'qrc_*.cpp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--remove"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*/tests/*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"-o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="nx"&gt;filterCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Filtering coverage data"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;filterCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;filterCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterCmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;genhtmlCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"genhtml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"--prefix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--output-directory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Code coverage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--legend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"--show-details"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"coverage.info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="nx"&gt;genhtmlCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Generate HTML coverage report"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;genhtmlCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;genhtmlCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;genhtmlCmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The most important thing here are the references to the &lt;code&gt;autotest-result&lt;/code&gt; tag:
this is the tag used by the &lt;code&gt;AutotestRunner&lt;/code&gt; Qbs item, which is responsible for
running the unit tests. Referencing its product's tag in the &lt;code&gt;Depends&lt;/code&gt; item and
in the &lt;code&gt;explicitlyDependsOnFromDependencies&lt;/code&gt; properties ensures that "building"
our product will cause the unit tests to run. Other needed bits are the
&lt;code&gt;requiresInputs: false&lt;/code&gt; property, which means that our rule doesn't have any
required inputs, and the &lt;code&gt;builtByDefault: false&lt;/code&gt; property, which says that our
coverage report should not be generated when just typing &lt;code&gt;qbs&lt;/code&gt;. Instead, to run
the tests and get the code coverage report one will have to request it
explicitly, by typing&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;qbs -p coverage
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;prepare&lt;/code&gt; property of the &lt;code&gt;Rule&lt;/code&gt; is where the commands to generate the code
coverage report are defined. Here we can use the &lt;code&gt;Command&lt;/code&gt; item to invoke
external programs, and we return a list of such items, so that the commands
will be executed in sequence. Note that here I'm using &lt;code&gt;lcov&lt;/code&gt; and expecting to
find the coverage data produced by &lt;code&gt;gcov&lt;/code&gt;, so this is probably not portable
outside of Linux/gcc.&lt;/p&gt;
&lt;p&gt;Using the &lt;code&gt;CoverageReport&lt;/code&gt; item is quite easy: you just need to declare it, and
specify which paths contain the coverage data that you are interested in
(otherwise, lcov will collect data from all object files that it find under the
build directory, which might not be what you desire):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    &lt;span class="nx"&gt;CoverageReport&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;condition:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableCoverage&lt;/span&gt;
        &lt;span class="k"&gt;extractPatterns:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'*/src/*.cpp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*/lib/*.cpp'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There's little more than that to be done. Of course, you need to find a way to
pass the &lt;code&gt;--coverage&lt;/code&gt; option to gcc when building your products, and for this I
created a small &lt;code&gt;buildconfig&lt;/code&gt; module in
&lt;code&gt;qbs/modules/buildconfig/BuildConfig.qbs&lt;/code&gt; which I depend on in all products
which I wish to build with coverage enabled:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;qbs&lt;/span&gt;

&lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;cpp.cxxFlags:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableCoverage&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"--coverage"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
    &lt;span class="k"&gt;cpp.dynamicLibraries:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableCoverage&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"gcov"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;

    &lt;span class="nx"&gt;Depends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"cpp"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If all this looks scary, you should probably have a look at the diff which
shows &lt;a href="https://gitlab.com/mardy/mappero/commit/ee04f6a453a935db653095c45bfe57af6a0ce508"&gt;how I added code coverage reporting to
qbs&lt;/a&gt;:
hopefully you'll find that it's not that complex, after all.&lt;/p&gt;
&lt;p&gt;I hope that Qbs users will find this interesting, and possibly improving my
setup. Ideally we should try to get something like this part of Qbs itself, but
portability outside of Linux / gcc is going to be an issue.&lt;/p&gt;</description><category>english</category><category>informatica</category><category>kdeplanet</category><category>Linux</category><category>maemo</category><category>mappero</category><category>mappero-geotagger</category><category>meego</category><category>planetmaemo</category><category>programmation</category><category>QBS</category><category>Qt</category><guid>http://mardy.it/blog/2019/07/qbs-and-code-coverage-reports.html</guid><pubDate>Mon, 01 Jul 2019 13:42:20 GMT</pubDate></item></channel></rss>