Mardy (Articoli su mappero)http://mardy.it/it/categories/mappero.atom2024-02-02T20:11:08ZAlberto MardeganNikolaQbs and code coverage reportshttp://mardy.it/it/blog/2019/07/qbs-and-code-coverage-reports.html2019-07-01T16:42:20+03:002019-07-01T16:42:20+03:00Alberto Mardegan<p>You know that I'm not an <em>early adopter</em>. That's why it was only a couple of
weeks ago when I decided to give <a href="https://doc.qt.io/qbs/">Qbs</a> a try, by using
the good old <a href="https://www.mardy.it/mappero/">Mappero</a> (and its spin-off,
<a href="https://www.mardy.it/mappero-geotagger/">Mappero Geotagger</a>) 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.</p>
<p>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 <code>rpath</code> on test
executables in order to make it easy to run them uninstalled, and with <code>qmake</code>
I achieved that with this:</p>
<div class="code"><pre class="code literal-block"><span class="nv">QMAKE_RPATHDIR</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$$</span><span class="o">{</span>QMAKE_LIBDIR<span class="o">}</span>
</pre></div>
<p>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 <a href="https://bugreports.qt.io/browse/QBS-1455">reported a
bug</a> to which I got some nice
suggestions, before eventually settling on this:</p>
<div class="code"><pre class="code literal-block"><span class="kr">import</span> <span class="nx">qbs</span> <span class="mf">1.0</span>
<span class="nx">Test</span> <span class="p">{</span>
<span class="k">name:</span> <span class="s2">"path-test"</span>
<span class="k">files:</span> <span class="p">[</span>
<span class="s2">"path-test.cpp"</span><span class="p">,</span>
<span class="s2">"path-test.h"</span><span class="p">,</span>
<span class="s2">"paths.qrc"</span><span class="p">,</span>
<span class="p">]</span>
<span class="nx">Depends</span> <span class="p">{</span> <span class="k">name:</span> <span class="s2">"Mappero"</span> <span class="p">}</span>
<span class="k">cpp.rpaths:</span> <span class="nx">cpp</span><span class="p">.</span><span class="nx">libraryPaths</span> <span class="c1">// <-- this does the trick!</span>
<span class="p">}</span>
</pre></div>
<p>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
<a href="https://gitlab.com/mardy/mappero/commit/2a19b59f018cd0517d37eadd24d1aa1780140e4b">this
commit</a>.</p>
<p>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.</p>
<h3>Teaching Qbs to make a code coverage report</h3>
<p>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.</p>
<p>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 <code>Product</code> with its own set of build rules, so here's the
<code>CoverageReport</code> item for Mappero (though, it should be general enough to be
reusable in your own project):</p>
<div class="code"><pre class="code literal-block"><span class="kr">import</span> <span class="nx">qbs</span>
<span class="nx">Product</span> <span class="p">{</span>
<span class="k">name:</span> <span class="s2">"coverage"</span>
<span class="nx">property</span> <span class="nx">string</span> <span class="k">outputDirectory:</span> <span class="s2">"coverage-html"</span>
<span class="nx">property</span> <span class="nx">stringList</span> <span class="k">extractPatterns:</span> <span class="p">[]</span>
<span class="k">builtByDefault:</span> <span class="kc">false</span>
<span class="k">files:</span> <span class="p">[</span><span class="s2">"**"</span><span class="p">]</span>
<span class="k">type:</span> <span class="p">[</span><span class="s2">"coverage.html"</span><span class="p">]</span>
<span class="nx">Depends</span> <span class="p">{</span> <span class="k">productTypes:</span> <span class="p">[</span><span class="s2">"autotest-result"</span><span class="p">]</span> <span class="p">}</span>
<span class="nx">Rule</span> <span class="p">{</span>
<span class="k">multiplex:</span> <span class="kc">true</span>
<span class="k">explicitlyDependsOnFromDependencies:</span> <span class="p">[</span><span class="s2">"autotest-result"</span><span class="p">]</span>
<span class="k">outputFileTags:</span> <span class="s2">"coverage.html"</span>
<span class="k">requiresInputs:</span> <span class="kc">false</span>
<span class="k">prepare:</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">commands</span> <span class="o">=</span> <span class="p">[]</span>
<span class="kd">var</span> <span class="nx">captureCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="p">[</span>
<span class="s2">"--directory"</span><span class="p">,</span> <span class="nx">project</span><span class="p">.</span><span class="nx">sourceDirectory</span><span class="p">,</span>
<span class="s2">"--capture"</span><span class="p">,</span>
<span class="s2">"--output-file"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span>
<span class="s2">"--no-checksum"</span><span class="p">,</span>
<span class="s2">"--compat-libtool"</span><span class="p">,</span>
<span class="p">]);</span>
<span class="nx">captureCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Collecting coverage data"</span><span class="p">;</span>
<span class="nx">captureCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">captureCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">captureCmd</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">extractArgs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"--extract"</span><span class="p">);</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"coverage.info"</span><span class="p">);</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"-o"</span><span class="p">);</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"coverage.info"</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">extractCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="nx">extractArgs</span><span class="p">);</span>
<span class="nx">extractCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Extracting coverage data"</span><span class="p">;</span>
<span class="nx">extractCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">extractCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">extractCmd</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">filterCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="p">[</span>
<span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'moc_*.cpp'</span><span class="p">,</span>
<span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'qrc_*.cpp'</span><span class="p">,</span>
<span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'*/tests/*'</span><span class="p">,</span>
<span class="s2">"-o"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span>
<span class="p">]);</span>
<span class="nx">filterCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Filtering coverage data"</span><span class="p">;</span>
<span class="nx">filterCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">filterCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">filterCmd</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">genhtmlCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"genhtml"</span><span class="p">,</span> <span class="p">[</span>
<span class="s2">"--prefix"</span><span class="p">,</span> <span class="nx">project</span><span class="p">.</span><span class="nx">sourceDirectory</span><span class="p">,</span>
<span class="s2">"--output-directory"</span><span class="p">,</span> <span class="nx">product</span><span class="p">.</span><span class="nx">outputDirectory</span><span class="p">,</span>
<span class="s2">"--title"</span><span class="p">,</span> <span class="s2">"Code coverage"</span><span class="p">,</span>
<span class="s2">"--legend"</span><span class="p">,</span>
<span class="s2">"--show-details"</span><span class="p">,</span>
<span class="s2">"coverage.info"</span><span class="p">,</span>
<span class="p">]);</span>
<span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Generate HTML coverage report"</span><span class="p">;</span>
<span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">genhtmlCmd</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">commands</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>The most important thing here are the references to the <code>autotest-result</code> tag:
this is the tag used by the <code>AutotestRunner</code> Qbs item, which is responsible for
running the unit tests. Referencing its product's tag in the <code>Depends</code> item and
in the <code>explicitlyDependsOnFromDependencies</code> properties ensures that "building"
our product will cause the unit tests to run. Other needed bits are the
<code>requiresInputs: false</code> property, which means that our rule doesn't have any
required inputs, and the <code>builtByDefault: false</code> property, which says that our
coverage report should not be generated when just typing <code>qbs</code>. Instead, to run
the tests and get the code coverage report one will have to request it
explicitly, by typing</p>
<div class="code"><pre class="code literal-block">qbs -p coverage
</pre></div>
<p>The <code>prepare</code> property of the <code>Rule</code> is where the commands to generate the code
coverage report are defined. Here we can use the <code>Command</code> 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 <code>lcov</code> and expecting to
find the coverage data produced by <code>gcov</code>, so this is probably not portable
outside of Linux/gcc.</p>
<p>Using the <code>CoverageReport</code> 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):</p>
<div class="code"><pre class="code literal-block"> <span class="nx">CoverageReport</span> <span class="p">{</span>
<span class="k">condition:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span>
<span class="k">extractPatterns:</span> <span class="p">[</span> <span class="s1">'*/src/*.cpp'</span><span class="p">,</span> <span class="s1">'*/lib/*.cpp'</span> <span class="p">]</span>
<span class="p">}</span>
</pre></div>
<p>There's little more than that to be done. Of course, you need to find a way to
pass the <code>--coverage</code> option to gcc when building your products, and for this I
created a small <code>buildconfig</code> module in
<code>qbs/modules/buildconfig/BuildConfig.qbs</code> which I depend on in all products
which I wish to build with coverage enabled:</p>
<div class="code"><pre class="code literal-block"><span class="kr">import</span> <span class="nx">qbs</span>
<span class="nx">Module</span> <span class="p">{</span>
<span class="k">cpp.cxxFlags:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span> <span class="o">?</span> <span class="p">[</span><span class="s2">"--coverage"</span><span class="p">]</span> <span class="o">:</span> <span class="kc">undefined</span>
<span class="k">cpp.dynamicLibraries:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span> <span class="o">?</span> <span class="p">[</span><span class="s2">"gcov"</span><span class="p">]</span> <span class="o">:</span> <span class="kc">undefined</span>
<span class="nx">Depends</span> <span class="p">{</span> <span class="k">name:</span> <span class="s2">"cpp"</span> <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>If all this looks scary, you should probably have a look at the diff which
shows <a href="https://gitlab.com/mardy/mappero/commit/ee04f6a453a935db653095c45bfe57af6a0ce508">how I added code coverage reporting to
qbs</a>:
hopefully you'll find that it's not that complex, after all.</p>
<p>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.</p><p>You know that I'm not an <em>early adopter</em>. That's why it was only a couple of
weeks ago when I decided to give <a href="https://doc.qt.io/qbs/">Qbs</a> a try, by using
the good old <a href="https://www.mardy.it/mappero/">Mappero</a> (and its spin-off,
<a href="https://www.mardy.it/mappero-geotagger/">Mappero Geotagger</a>) 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.</p>
<p>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 <code>rpath</code> on test
executables in order to make it easy to run them uninstalled, and with <code>qmake</code>
I achieved that with this:</p>
<div class="code"><pre class="code literal-block"><span class="nv">QMAKE_RPATHDIR</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$$</span><span class="o">{</span>QMAKE_LIBDIR<span class="o">}</span>
</pre></div>
<p>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 <a href="https://bugreports.qt.io/browse/QBS-1455">reported a
bug</a> to which I got some nice
suggestions, before eventually settling on this:</p>
<div class="code"><pre class="code literal-block"><span class="kr">import</span> <span class="nx">qbs</span> <span class="mf">1.0</span>
<span class="nx">Test</span> <span class="p">{</span>
<span class="k">name:</span> <span class="s2">"path-test"</span>
<span class="k">files:</span> <span class="p">[</span>
<span class="s2">"path-test.cpp"</span><span class="p">,</span>
<span class="s2">"path-test.h"</span><span class="p">,</span>
<span class="s2">"paths.qrc"</span><span class="p">,</span>
<span class="p">]</span>
<span class="nx">Depends</span> <span class="p">{</span> <span class="k">name:</span> <span class="s2">"Mappero"</span> <span class="p">}</span>
<span class="k">cpp.rpaths:</span> <span class="nx">cpp</span><span class="p">.</span><span class="nx">libraryPaths</span> <span class="c1">// <-- this does the trick!</span>
<span class="p">}</span>
</pre></div>
<p>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
<a href="https://gitlab.com/mardy/mappero/commit/2a19b59f018cd0517d37eadd24d1aa1780140e4b">this
commit</a>.</p>
<p>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.</p>
<h3>Teaching Qbs to make a code coverage report</h3>
<p>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.</p>
<p>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 <code>Product</code> with its own set of build rules, so here's the
<code>CoverageReport</code> item for Mappero (though, it should be general enough to be
reusable in your own project):</p>
<div class="code"><pre class="code literal-block"><span class="kr">import</span> <span class="nx">qbs</span>
<span class="nx">Product</span> <span class="p">{</span>
<span class="k">name:</span> <span class="s2">"coverage"</span>
<span class="nx">property</span> <span class="nx">string</span> <span class="k">outputDirectory:</span> <span class="s2">"coverage-html"</span>
<span class="nx">property</span> <span class="nx">stringList</span> <span class="k">extractPatterns:</span> <span class="p">[]</span>
<span class="k">builtByDefault:</span> <span class="kc">false</span>
<span class="k">files:</span> <span class="p">[</span><span class="s2">"**"</span><span class="p">]</span>
<span class="k">type:</span> <span class="p">[</span><span class="s2">"coverage.html"</span><span class="p">]</span>
<span class="nx">Depends</span> <span class="p">{</span> <span class="k">productTypes:</span> <span class="p">[</span><span class="s2">"autotest-result"</span><span class="p">]</span> <span class="p">}</span>
<span class="nx">Rule</span> <span class="p">{</span>
<span class="k">multiplex:</span> <span class="kc">true</span>
<span class="k">explicitlyDependsOnFromDependencies:</span> <span class="p">[</span><span class="s2">"autotest-result"</span><span class="p">]</span>
<span class="k">outputFileTags:</span> <span class="s2">"coverage.html"</span>
<span class="k">requiresInputs:</span> <span class="kc">false</span>
<span class="k">prepare:</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">commands</span> <span class="o">=</span> <span class="p">[]</span>
<span class="kd">var</span> <span class="nx">captureCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="p">[</span>
<span class="s2">"--directory"</span><span class="p">,</span> <span class="nx">project</span><span class="p">.</span><span class="nx">sourceDirectory</span><span class="p">,</span>
<span class="s2">"--capture"</span><span class="p">,</span>
<span class="s2">"--output-file"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span>
<span class="s2">"--no-checksum"</span><span class="p">,</span>
<span class="s2">"--compat-libtool"</span><span class="p">,</span>
<span class="p">]);</span>
<span class="nx">captureCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Collecting coverage data"</span><span class="p">;</span>
<span class="nx">captureCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">captureCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">captureCmd</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">extractArgs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"--extract"</span><span class="p">);</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"coverage.info"</span><span class="p">);</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">product</span><span class="p">.</span><span class="nx">extractPatterns</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"-o"</span><span class="p">);</span>
<span class="nx">extractArgs</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">"coverage.info"</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">extractCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="nx">extractArgs</span><span class="p">);</span>
<span class="nx">extractCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Extracting coverage data"</span><span class="p">;</span>
<span class="nx">extractCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">extractCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">extractCmd</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">filterCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"lcov"</span><span class="p">,</span> <span class="p">[</span>
<span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'moc_*.cpp'</span><span class="p">,</span>
<span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'qrc_*.cpp'</span><span class="p">,</span>
<span class="s2">"--remove"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span> <span class="s1">'*/tests/*'</span><span class="p">,</span>
<span class="s2">"-o"</span><span class="p">,</span> <span class="s2">"coverage.info"</span><span class="p">,</span>
<span class="p">]);</span>
<span class="nx">filterCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Filtering coverage data"</span><span class="p">;</span>
<span class="nx">filterCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">filterCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">filterCmd</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">genhtmlCmd</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Command</span><span class="p">(</span><span class="s2">"genhtml"</span><span class="p">,</span> <span class="p">[</span>
<span class="s2">"--prefix"</span><span class="p">,</span> <span class="nx">project</span><span class="p">.</span><span class="nx">sourceDirectory</span><span class="p">,</span>
<span class="s2">"--output-directory"</span><span class="p">,</span> <span class="nx">product</span><span class="p">.</span><span class="nx">outputDirectory</span><span class="p">,</span>
<span class="s2">"--title"</span><span class="p">,</span> <span class="s2">"Code coverage"</span><span class="p">,</span>
<span class="s2">"--legend"</span><span class="p">,</span>
<span class="s2">"--show-details"</span><span class="p">,</span>
<span class="s2">"coverage.info"</span><span class="p">,</span>
<span class="p">]);</span>
<span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">description</span> <span class="o">=</span> <span class="s2">"Generate HTML coverage report"</span><span class="p">;</span>
<span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">=</span> <span class="s2">"coverage"</span><span class="p">;</span>
<span class="nx">genhtmlCmd</span><span class="p">.</span><span class="nx">silent</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">commands</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">genhtmlCmd</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">commands</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>The most important thing here are the references to the <code>autotest-result</code> tag:
this is the tag used by the <code>AutotestRunner</code> Qbs item, which is responsible for
running the unit tests. Referencing its product's tag in the <code>Depends</code> item and
in the <code>explicitlyDependsOnFromDependencies</code> properties ensures that "building"
our product will cause the unit tests to run. Other needed bits are the
<code>requiresInputs: false</code> property, which means that our rule doesn't have any
required inputs, and the <code>builtByDefault: false</code> property, which says that our
coverage report should not be generated when just typing <code>qbs</code>. Instead, to run
the tests and get the code coverage report one will have to request it
explicitly, by typing</p>
<div class="code"><pre class="code literal-block">qbs -p coverage
</pre></div>
<p>The <code>prepare</code> property of the <code>Rule</code> is where the commands to generate the code
coverage report are defined. Here we can use the <code>Command</code> 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 <code>lcov</code> and expecting to
find the coverage data produced by <code>gcov</code>, so this is probably not portable
outside of Linux/gcc.</p>
<p>Using the <code>CoverageReport</code> 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):</p>
<div class="code"><pre class="code literal-block"> <span class="nx">CoverageReport</span> <span class="p">{</span>
<span class="k">condition:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span>
<span class="k">extractPatterns:</span> <span class="p">[</span> <span class="s1">'*/src/*.cpp'</span><span class="p">,</span> <span class="s1">'*/lib/*.cpp'</span> <span class="p">]</span>
<span class="p">}</span>
</pre></div>
<p>There's little more than that to be done. Of course, you need to find a way to
pass the <code>--coverage</code> option to gcc when building your products, and for this I
created a small <code>buildconfig</code> module in
<code>qbs/modules/buildconfig/BuildConfig.qbs</code> which I depend on in all products
which I wish to build with coverage enabled:</p>
<div class="code"><pre class="code literal-block"><span class="kr">import</span> <span class="nx">qbs</span>
<span class="nx">Module</span> <span class="p">{</span>
<span class="k">cpp.cxxFlags:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span> <span class="o">?</span> <span class="p">[</span><span class="s2">"--coverage"</span><span class="p">]</span> <span class="o">:</span> <span class="kc">undefined</span>
<span class="k">cpp.dynamicLibraries:</span> <span class="nx">project</span><span class="p">.</span><span class="nx">enableCoverage</span> <span class="o">?</span> <span class="p">[</span><span class="s2">"gcov"</span><span class="p">]</span> <span class="o">:</span> <span class="kc">undefined</span>
<span class="nx">Depends</span> <span class="p">{</span> <span class="k">name:</span> <span class="s2">"cpp"</span> <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>If all this looks scary, you should probably have a look at the diff which
shows <a href="https://gitlab.com/mardy/mappero/commit/ee04f6a453a935db653095c45bfe57af6a0ce508">how I added code coverage reporting to
qbs</a>:
hopefully you'll find that it's not that complex, after all.</p>
<p>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.</p>Mappero: public source code, CLA, Qt5 porthttp://mardy.it/it/blog/2013/11/mappero-public-source-code-cla-qt5-port.html2013-11-03T15:55:00+04:002013-11-03T15:55:00+04:00Alberto Mardegan<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://www.mardy.it/mappero">Mappero</a> has always been distributed under a GPL licence. However, since when I started selling <a href="http://www.mardy.it/mappero-geotagger">Mappero Geotagger</a> (which is built from the same source), I decided not to publish the source code in a public repository, but only to provide it to those who made an explicit request to obtain it.<br>
<br>
I spent some time reconsidering the matter, and I've finally decided to let the source code live in a <a href="https://gitlab.com/mardy/mappero">public repository</a>. I also setup a <a href="http://lists.mardy.it/listinfo.cgi/mappero-mardy.it">mailing list</a> for it. And indeed I welcome code contributions, however there's a small catch: a <a href="http://en.wikipedia.org/wiki/Contributor_License_Agreement">CLA</a>. While Mappero is distributed under the GPLv3 licence, <i>I request that all contributors send me an e-mail in which they give me the right to re-licence their contribution under any licence published by the Free Software Foundation</i>.<br>
<br>
Since I believe that the busiest time for my involvement with <a href="http://blog.mardy.it/2013/11/speculo-or-shared-memory-made-easy.html">speculo</a> has passed, I expect to be able to spend some more time developing Mappero. The qt5 port is more or less working, but most of the cool features are missing, so it's little more than a map viewer at the moment (Mappero Geotagger, however, is fully working under Qt5!).<br>
<center>
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/QeAT6LFrpp4" width="560"></iframe></center>
<br>
Here you can see Mappero running on an Ubuntu Touch powered Nexus 4. Pinch zooming and GPS are not yet working, but I promise they'll be there in less than a week. Also I found a nasty bug which can cause the application to crash when downloading map tiles, and I'll fix it ASAP (I'm mentioning it just so that I won't be flooded with identical bug reports now :-) ).</div><div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://www.mardy.it/mappero">Mappero</a> has always been distributed under a GPL licence. However, since when I started selling <a href="http://www.mardy.it/mappero-geotagger">Mappero Geotagger</a> (which is built from the same source), I decided not to publish the source code in a public repository, but only to provide it to those who made an explicit request to obtain it.<br>
<br>
I spent some time reconsidering the matter, and I've finally decided to let the source code live in a <a href="https://gitlab.com/mardy/mappero">public repository</a>. I also setup a <a href="http://lists.mardy.it/listinfo.cgi/mappero-mardy.it">mailing list</a> for it. And indeed I welcome code contributions, however there's a small catch: a <a href="http://en.wikipedia.org/wiki/Contributor_License_Agreement">CLA</a>. While Mappero is distributed under the GPLv3 licence, <i>I request that all contributors send me an e-mail in which they give me the right to re-licence their contribution under any licence published by the Free Software Foundation</i>.<br>
<br>
Since I believe that the busiest time for my involvement with <a href="http://blog.mardy.it/2013/11/speculo-or-shared-memory-made-easy.html">speculo</a> has passed, I expect to be able to spend some more time developing Mappero. The qt5 port is more or less working, but most of the cool features are missing, so it's little more than a map viewer at the moment (Mappero Geotagger, however, is fully working under Qt5!).<br>
<center>
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/QeAT6LFrpp4" width="560"></iframe></center>
<br>
Here you can see Mappero running on an Ubuntu Touch powered Nexus 4. Pinch zooming and GPS are not yet working, but I promise they'll be there in less than a week. Also I found a nasty bug which can cause the application to crash when downloading map tiles, and I'll fix it ASAP (I'm mentioning it just so that I won't be flooded with identical bug reports now :-) ).</div>Introducing Mappero Geotaggerhttp://mardy.it/it/blog/2012/08/introducing-mappero-geotagger.html2012-08-23T19:05:00+04:002012-08-23T19:05:00+04:00Alberto Mardegan<div style="float: right;"><a href="http://www.mardy.it/archivos/imagines/mappero-geotagger.png"><img src="http://www.mardy.it/archivos/imagines/mappero-geotagger.png" width="400px"></a></div>
<p>A few days ago I published the first version of <a href="http://www.mardy.it/mappero-geotagger">Mappero Geotagger</a>, an open source geotagging application for Linux, Mac OS X and Windows.</p>
<p><em>Geotagging</em> a file means assigning a geographic location to it, and it's an action typically performed on picture files, so that the geotagged photo can be shown on a map at the location where it was taken. Many photo-sharing websites, like for instance <a href="http://flickr.com">flickr</a> and <a href="http://picasa.google.com/">picasa</a>, will show your pictures on a map, as you can see for example <a href="http://www.flickr.com/photos/mardytardi/2915024236/in/set-72157607758948089">in this picture</a> of mine. Some services also allow you to view all photos taken in a certain area; for instance, here are some nice pictures taken in <a href="http://www.flickr.com/map?&fLat=60.3834&fLon=25.6776&zl=13">Porvoo</a>, Finland.</p>
<p>Mappero Geotagger is a simple graphical tool to geotag your photos. You can manually move pictures on the map to set or change their location (removing the geotag is also possible) or, if you happened to record your way with a GPS while you took the pictures, the program can automatically correlate the time of the photos with the time of the GPS signal, and therefore establish with a certain precision where the pictures where taken. Since the time of the GPS receiver and the time of your camera might differ (and usually they do, especially if you travel to a different time-zone and forget to update the time in one of your devices), Mappero Geotagger has some controls to allow you to smoothly adjust the time difference and provides you an immediate feedback as you'll see the images being laid out on the map along the GPS track. The video below should give you a better idea of how this works:</p>
<div style="text-align: center; margin: 0 auto;"><iframe width="560" height="315" src="http://www.youtube.com/embed/b1J84dISuNk?rel=0" frameborder="0" allowfullscreen></iframe><br><small>See Mappero Geotagger in action</small></div>
<p>I'm selling the application <a href="http://www.mardy.it/mappero-geotagger">from my website</a> for 15€, but if you hurry up and either <a href="http://twitter.com">tweet</a> or mention it in <a href="http://plus.google.com">Google+</a> you can have it for 5€ only — and <b>if you blog about it, you'll get it for free</b>. Detailed info on the promotion are <a href="http://www.mardy.it/mappero-geotagger#promotions">here</a></p>
<p>Incidentally, if you own a Nokia N9 or N900, the source code which you will get when purchasing Mappero Geotagger can also be compiled for these phones, into an application (still under heavy development, but already usable) which lets you record a GPX track usable with Mappero Geotagger.</p><div style="float: right;"><a href="http://www.mardy.it/archivos/imagines/mappero-geotagger.png"><img src="http://www.mardy.it/archivos/imagines/mappero-geotagger.png" width="400px"></a></div>
<p>A few days ago I published the first version of <a href="http://www.mardy.it/mappero-geotagger">Mappero Geotagger</a>, an open source geotagging application for Linux, Mac OS X and Windows.</p>
<p><em>Geotagging</em> a file means assigning a geographic location to it, and it's an action typically performed on picture files, so that the geotagged photo can be shown on a map at the location where it was taken. Many photo-sharing websites, like for instance <a href="http://flickr.com">flickr</a> and <a href="http://picasa.google.com/">picasa</a>, will show your pictures on a map, as you can see for example <a href="http://www.flickr.com/photos/mardytardi/2915024236/in/set-72157607758948089">in this picture</a> of mine. Some services also allow you to view all photos taken in a certain area; for instance, here are some nice pictures taken in <a href="http://www.flickr.com/map?&fLat=60.3834&fLon=25.6776&zl=13">Porvoo</a>, Finland.</p>
<p>Mappero Geotagger is a simple graphical tool to geotag your photos. You can manually move pictures on the map to set or change their location (removing the geotag is also possible) or, if you happened to record your way with a GPS while you took the pictures, the program can automatically correlate the time of the photos with the time of the GPS signal, and therefore establish with a certain precision where the pictures where taken. Since the time of the GPS receiver and the time of your camera might differ (and usually they do, especially if you travel to a different time-zone and forget to update the time in one of your devices), Mappero Geotagger has some controls to allow you to smoothly adjust the time difference and provides you an immediate feedback as you'll see the images being laid out on the map along the GPS track. The video below should give you a better idea of how this works:</p>
<div style="text-align: center; margin: 0 auto;"><iframe width="560" height="315" src="http://www.youtube.com/embed/b1J84dISuNk?rel=0" frameborder="0" allowfullscreen></iframe><br><small>See Mappero Geotagger in action</small></div>
<p>I'm selling the application <a href="http://www.mardy.it/mappero-geotagger">from my website</a> for 15€, but if you hurry up and either <a href="http://twitter.com">tweet</a> or mention it in <a href="http://plus.google.com">Google+</a> you can have it for 5€ only — and <b>if you blog about it, you'll get it for free</b>. Detailed info on the promotion are <a href="http://www.mardy.it/mappero-geotagger#promotions">here</a></p>
<p>Incidentally, if you own a Nokia N9 or N900, the source code which you will get when purchasing Mappero Geotagger can also be compiled for these phones, into an application (still under heavy development, but already usable) which lets you record a GPX track usable with Mappero Geotagger.</p>Google Maps routing: the day afterhttp://mardy.it/it/blog/2010/08/google-maps-routing-day-after.html2010-08-01T11:51:00+04:002010-08-01T11:51:00+04:00Alberto Mardegan<p>Just one day after releasing mappero 3.0+beta11, another version is out. Today's hot dish is the Google Maps <i>address disambiguation</i> dialog:</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mardy.it/archivos/imagines/mappero-google-disambiguation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://www.mardy.it/archivos/imagines/mappero-google-disambiguation.png" width="400"></a></div>
<p>It sometimes happens (especially to people living in Italy) that the address you need exists in different cities. “Via Roma”, for instance, is one very common street name in Italy, so if you are searching for it in Google Maps web interface you won't get a route, but instead you'll get a list of possible matches. And so far, in such a situation Mappero would have spit out the infamous “Invalid source or destination.” error message.<br>
In today's release the situation is improved, because when we get a disambiguation request from Google Maps, Mappero shows the screen above and lets you pick your destination. This should hopefully save you some time when typing addresses.</p>
<p>I still have a few unclear points about Google Maps behaviour, because sometimes the reply is different from what we get via web, and it seems that it doesn't always honour our request for local results only. So, if someone is familiar with <a href="http://mapki.com/wiki/Google_Map_Parameters">Google Maps parameters</a> and knows how to get the destination address resolved using a local search, please let me know and as a reward I'll append your name to all street names returned by Mappero. ;-)</p>
<p>By the way, the main reason for releasing this today was that this version also fixes the problem when libmappero doesn't get automatically upgraded along with Mappero. Also, the fact of having received a huge donation stimulated me to do something in return. :-)</p>
<br>
<p>Oh! I hope that now you won't be expecting a new release every day! But in case you do, here is how <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DLKNAWDRW4WVG">you can make it happen</a>.</p><p>Just one day after releasing mappero 3.0+beta11, another version is out. Today's hot dish is the Google Maps <i>address disambiguation</i> dialog:</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mardy.it/archivos/imagines/mappero-google-disambiguation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://www.mardy.it/archivos/imagines/mappero-google-disambiguation.png" width="400"></a></div>
<p>It sometimes happens (especially to people living in Italy) that the address you need exists in different cities. “Via Roma”, for instance, is one very common street name in Italy, so if you are searching for it in Google Maps web interface you won't get a route, but instead you'll get a list of possible matches. And so far, in such a situation Mappero would have spit out the infamous “Invalid source or destination.” error message.<br>
In today's release the situation is improved, because when we get a disambiguation request from Google Maps, Mappero shows the screen above and lets you pick your destination. This should hopefully save you some time when typing addresses.</p>
<p>I still have a few unclear points about Google Maps behaviour, because sometimes the reply is different from what we get via web, and it seems that it doesn't always honour our request for local results only. So, if someone is familiar with <a href="http://mapki.com/wiki/Google_Map_Parameters">Google Maps parameters</a> and knows how to get the destination address resolved using a local search, please let me know and as a reward I'll append your name to all street names returned by Mappero. ;-)</p>
<p>By the way, the main reason for releasing this today was that this version also fixes the problem when libmappero doesn't get automatically upgraded along with Mappero. Also, the fact of having received a huge donation stimulated me to do something in return. :-)</p>
<br>
<p>Oh! I hope that now you won't be expecting a new release every day! But in case you do, here is how <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DLKNAWDRW4WVG">you can make it happen</a>.</p>Your favourite router is up again, faster than everhttp://mardy.it/it/blog/2010/07/your-favourite-router-is-up-again.html2010-07-31T11:10:00+04:002010-07-31T11:10:00+04:00Alberto Mardegan<p>Mappero is back from holidays. Version 3.0+beta11 has just been released and doesn't contain any of the big features I was planning; instead, it's mostly a bugfix release, but a rather important one. Here are the main highlights:</p>
<ul>
<li>Google routing works: direct and faster</li>
<li>A new widget for inputing addresses, with history-based auto-completion</li>
<li>Bugfixes: POI edit/view screen doesn't destroy your data, fix some crashes introduced with 3.0+beta9, fix Yandex router, screen unblanking works again, and some other minor corrections.</li>
</ul>
<p>I was hoping to make a gigantic release with some great improvements I had in mind, but the current situation of <a href="http://gnuite.com/">gnuite.com</a> server (the routing data provider for Mappero and maemo-mapper), which lately is often not responding, forced me to hurry up and make a new release as quickly as possible.
<br>
Routing in this new version works by directly connecting to the Google Maps server (although the indirect way is still available, under the "gnuite" router option) and downloading the route as a KML file. This is much faster than the old way, because we have a few network hops less and we are not waiting for the gnuite server to process the route and rebuild it as a GPX file for us.</p>
<p>The other main feature introduced with this release is the address input dialog:
</p><div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mardy.it/archivos/imagines/mappero-address-picker.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://www.mardy.it/archivos/imagines/mappero-address-picker.png" width="400"></a></div>
This dialog is invoked when clicking on the route icon and then choose the "Set destination..." item. It lists the locations you've been searching before and filters them as you type, in a similar fashion as the browser URL suggestion works.<br>
I plan to improve it by adding suggestions retrieved via the network from Google Maps, but this will require some deeper changes in the code that might take some time.
<p>That's it for now. I hope you'll enjoy this release. :-)</p>
<small>(currently it's in the <a href="http://wiki.maemo.org/Extras-testing">extras-testing</a> repository: to try it right now, download <a href="http://repository.maemo.org/extras-devel/pool/fremantle/free/m/maemo-mapper/libmappero0_3.0+beta11_armel.deb">this</a> and <a href="http://repository.maemo.org/extras-devel/pool/fremantle/free/m/maemo-mapper/maemo-mapper_3.0+beta11_armel.deb">this</a>)</small><p>Mappero is back from holidays. Version 3.0+beta11 has just been released and doesn't contain any of the big features I was planning; instead, it's mostly a bugfix release, but a rather important one. Here are the main highlights:</p>
<ul>
<li>Google routing works: direct and faster</li>
<li>A new widget for inputing addresses, with history-based auto-completion</li>
<li>Bugfixes: POI edit/view screen doesn't destroy your data, fix some crashes introduced with 3.0+beta9, fix Yandex router, screen unblanking works again, and some other minor corrections.</li>
</ul>
<p>I was hoping to make a gigantic release with some great improvements I had in mind, but the current situation of <a href="http://gnuite.com/">gnuite.com</a> server (the routing data provider for Mappero and maemo-mapper), which lately is often not responding, forced me to hurry up and make a new release as quickly as possible.
<br>
Routing in this new version works by directly connecting to the Google Maps server (although the indirect way is still available, under the "gnuite" router option) and downloading the route as a KML file. This is much faster than the old way, because we have a few network hops less and we are not waiting for the gnuite server to process the route and rebuild it as a GPX file for us.</p>
<p>The other main feature introduced with this release is the address input dialog:
</p><div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mardy.it/archivos/imagines/mappero-address-picker.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://www.mardy.it/archivos/imagines/mappero-address-picker.png" width="400"></a></div>
This dialog is invoked when clicking on the route icon and then choose the "Set destination..." item. It lists the locations you've been searching before and filters them as you type, in a similar fashion as the browser URL suggestion works.<br>
I plan to improve it by adding suggestions retrieved via the network from Google Maps, but this will require some deeper changes in the code that might take some time.
<p>That's it for now. I hope you'll enjoy this release. :-)</p>
<small>(currently it's in the <a href="http://wiki.maemo.org/Extras-testing">extras-testing</a> repository: to try it right now, download <a href="http://repository.maemo.org/extras-devel/pool/fremantle/free/m/maemo-mapper/libmappero0_3.0+beta11_armel.deb">this</a> and <a href="http://repository.maemo.org/extras-devel/pool/fremantle/free/m/maemo-mapper/maemo-mapper_3.0+beta11_armel.deb">this</a>)</small>How not to get support from an open source projecthttp://mardy.it/it/blog/2010/06/how-not-to-get-support-from-open-source.html2010-06-25T12:42:00+04:002010-06-25T12:42:00+04:00Alberto Mardegan<div style="float:right"><a href="http://www.flickr.com/photos/mardytardi/4464562686/" title="20100326_016.jpg by mardy78, on Flickr"><img src="http://farm3.static.flickr.com/2705/4464562686_f7e784aee9.jpg" width="281" height="500" alt="20100326_016.jpg"></a></div>
<p>Lately many people have been writing to me by e-mail, IM or to my maemo.org account, mostly asking for help on how to use <a href="http://www.mardy.it/mappero">Mappero</a> or request new features. While I'm glad to see that there's some interest about the project, I feel a need to tell everybody that <b>writing personal messages to the developer is not the best way to get help</b>. I'm sorry to say that I couldn't answer most of these requests: it would have simply killed off my time, which instead was spent working on Mappero (see below in the post for some news on what i did).<br>
On the other hand, I understand that the Maemo community is growing a lot, and many new members might not know how to find their way through all the amount of information in <a href="http://maemo.org/">maemo.org</a> and related projects. Unfortunately I'm not going to deliver any solutions to this, but I can at least write here a few pieces of advice that I think are generally productive.</p>
<h4>Where to file bug reports or feature requests</h4>
<p>This is the case when writing to the developer is the most ineffective solution (at least if the developer is me :-)): even in the best case when he has enough time to dedicate the needed attention to your message, in most case he won't be able to solve the problem right away, and he'll simply forget about it. And please, don't keep reminding him about the issue, it's just going to piss him off. And pretty please, don't think that the issue you are reporting is so simple to fix that he'll be able to fix it right away: there are billions of reason why a change that seems trivial to you might be enormously complex to the developers.<br>
So, just use the tools that are meant for this goal: bug trackers. You can probably find the web address of the bug tracker in the <i>About</i> page of the application, if it has one (tap on the application title to open the main menu; if you are lucky, the <i>About</i> item is there!), or in the <a href="http://maemo.org/downloads/">maemo.org downloads page</a> you can search for the application and, once found, on the page there should be links to the project's web page and bug tracker.<br>
Filing a bug report usually requires you to log in into the bug tracker (and create a free account if you don't have one) and fill in a simple form where you'll have to describe the bug you encountered or the feature you want to request. Once done, you'll be notified by mail when someone replies to your request.</p>
<h4>Where to get help, or just talk about the application</h4>
<p>You need a place for discussion. Sometimes it is because you need help on using the application, sometimes it is because you are not sure whether the application has a problem, and would like to check with other users before going and filing a bug. Well, first of all use google or search the forums at <a href="http://talk.maemo.org/">talk.maemo.org</a>; here you might find that people have already asked your question or are discussing the same issue that you had in mind.<br>
If you need to start a new discussion, it's better to do first check the application website and see what's the recommended place for discussion. In Mappero case, we have <a href="https://garage.maemo.org/forum/?group_id=29">web forums</a> in the <a href="http://garage.maemo.org/">Garage</a> project page.<br>
The other option is of course <a href="http://talk.maemo.org/">talk.maemo.org</a>; but there's always the risk that if the application has its own project page somewhere else, they might not be checking the maemo forums frequently (this is especially the case of applications which were not especially developed for maemo only). Anyway, as far as I am concerned, I'm trying to be as active as possible in the maemo forums as well — but that depends a lot on my free time (usually I've just time to browse out of curiosity, but not to answer).</p>
<h4>When to talk to the developer directly</h4>
<p>Practically never. Well, this is a bit exaggerated now, but in practice if the application has its own user base there should almost be no reasons why you'd want to write the developer directly. Except thanking him, if you feel like doing it: a short message in with you express your gratefulness is always welcome. :-)<br>
Other than that, <b>why would you want to write a message to the developers which other people cannot see</b>? Unless it's something secret, don't. Just think about the opposite question then: is there anyone else who could be interested in the discussion? In most cases, the answer it <em>yes</em>! Then don't be shy (or selfish?), and instead ask the question on a public forum. One of the advantages of doing that is that everybody could answer you, not just the developers (who might be busy, or simply unwilling to answer private messages); you might get the answer earlier, and the answer will stay there in the forum, publicly available to any other users who would otherwise ask the same thing later.</p>
<p>The bigger the user base, the more you are saving developers' time, and let them work on their projects. Speaking of which...</p>
<h4>So what's new about Mappero?</h4>
<p>It has been a rather long development cycle: I've been changing many thing on how Mappero works internally (now it's split into an application, a library and dynamically loadable plugins), which you probably won't notice now but has been quite a big work which hopefully will bring some sweet fruits soon. Other than that:</p>
<ul>
<li>Finnish topographic maps (you don't need to upgrade to get them; just follow <a href="http://wiki.maemo.org/Maemo-mapper_topomaps">these instructions)</a></li>
<li>The localized voice navigation should finally work.</li>
<li>Added voice samples for German (contributed by <a href="http://talk.maemo.org/member.php?u=40748">jav_maemo</a>) and Finnish (by <a href="http://talk.maemo.org/member.php?u=41396">Steffe69</a>)</li>
<li>Reduced memory usage by a few megabytes (about 3-4, according to top)</li>
<li>Add support for KML files, make Mappero handle GPX and KML links directly from your N900 browser</li>
</ul>
All this is in version <tt>3.0+beta9</tt>, which is now available in Extras-devel repository and soon in Extras-testing too. Due to the deep changes in the code, I'm almost sure that some new bug has been introduced, so I'm not pushing you to install this version, unless you want to help with testing.<div style="float:right"><a href="http://www.flickr.com/photos/mardytardi/4464562686/" title="20100326_016.jpg by mardy78, on Flickr"><img src="http://farm3.static.flickr.com/2705/4464562686_f7e784aee9.jpg" width="281" height="500" alt="20100326_016.jpg"></a></div>
<p>Lately many people have been writing to me by e-mail, IM or to my maemo.org account, mostly asking for help on how to use <a href="http://www.mardy.it/mappero">Mappero</a> or request new features. While I'm glad to see that there's some interest about the project, I feel a need to tell everybody that <b>writing personal messages to the developer is not the best way to get help</b>. I'm sorry to say that I couldn't answer most of these requests: it would have simply killed off my time, which instead was spent working on Mappero (see below in the post for some news on what i did).<br>
On the other hand, I understand that the Maemo community is growing a lot, and many new members might not know how to find their way through all the amount of information in <a href="http://maemo.org/">maemo.org</a> and related projects. Unfortunately I'm not going to deliver any solutions to this, but I can at least write here a few pieces of advice that I think are generally productive.</p>
<h4>Where to file bug reports or feature requests</h4>
<p>This is the case when writing to the developer is the most ineffective solution (at least if the developer is me :-)): even in the best case when he has enough time to dedicate the needed attention to your message, in most case he won't be able to solve the problem right away, and he'll simply forget about it. And please, don't keep reminding him about the issue, it's just going to piss him off. And pretty please, don't think that the issue you are reporting is so simple to fix that he'll be able to fix it right away: there are billions of reason why a change that seems trivial to you might be enormously complex to the developers.<br>
So, just use the tools that are meant for this goal: bug trackers. You can probably find the web address of the bug tracker in the <i>About</i> page of the application, if it has one (tap on the application title to open the main menu; if you are lucky, the <i>About</i> item is there!), or in the <a href="http://maemo.org/downloads/">maemo.org downloads page</a> you can search for the application and, once found, on the page there should be links to the project's web page and bug tracker.<br>
Filing a bug report usually requires you to log in into the bug tracker (and create a free account if you don't have one) and fill in a simple form where you'll have to describe the bug you encountered or the feature you want to request. Once done, you'll be notified by mail when someone replies to your request.</p>
<h4>Where to get help, or just talk about the application</h4>
<p>You need a place for discussion. Sometimes it is because you need help on using the application, sometimes it is because you are not sure whether the application has a problem, and would like to check with other users before going and filing a bug. Well, first of all use google or search the forums at <a href="http://talk.maemo.org/">talk.maemo.org</a>; here you might find that people have already asked your question or are discussing the same issue that you had in mind.<br>
If you need to start a new discussion, it's better to do first check the application website and see what's the recommended place for discussion. In Mappero case, we have <a href="https://garage.maemo.org/forum/?group_id=29">web forums</a> in the <a href="http://garage.maemo.org/">Garage</a> project page.<br>
The other option is of course <a href="http://talk.maemo.org/">talk.maemo.org</a>; but there's always the risk that if the application has its own project page somewhere else, they might not be checking the maemo forums frequently (this is especially the case of applications which were not especially developed for maemo only). Anyway, as far as I am concerned, I'm trying to be as active as possible in the maemo forums as well — but that depends a lot on my free time (usually I've just time to browse out of curiosity, but not to answer).</p>
<h4>When to talk to the developer directly</h4>
<p>Practically never. Well, this is a bit exaggerated now, but in practice if the application has its own user base there should almost be no reasons why you'd want to write the developer directly. Except thanking him, if you feel like doing it: a short message in with you express your gratefulness is always welcome. :-)<br>
Other than that, <b>why would you want to write a message to the developers which other people cannot see</b>? Unless it's something secret, don't. Just think about the opposite question then: is there anyone else who could be interested in the discussion? In most cases, the answer it <em>yes</em>! Then don't be shy (or selfish?), and instead ask the question on a public forum. One of the advantages of doing that is that everybody could answer you, not just the developers (who might be busy, or simply unwilling to answer private messages); you might get the answer earlier, and the answer will stay there in the forum, publicly available to any other users who would otherwise ask the same thing later.</p>
<p>The bigger the user base, the more you are saving developers' time, and let them work on their projects. Speaking of which...</p>
<h4>So what's new about Mappero?</h4>
<p>It has been a rather long development cycle: I've been changing many thing on how Mappero works internally (now it's split into an application, a library and dynamically loadable plugins), which you probably won't notice now but has been quite a big work which hopefully will bring some sweet fruits soon. Other than that:</p>
<ul>
<li>Finnish topographic maps (you don't need to upgrade to get them; just follow <a href="http://wiki.maemo.org/Maemo-mapper_topomaps">these instructions)</a></li>
<li>The localized voice navigation should finally work.</li>
<li>Added voice samples for German (contributed by <a href="http://talk.maemo.org/member.php?u=40748">jav_maemo</a>) and Finnish (by <a href="http://talk.maemo.org/member.php?u=41396">Steffe69</a>)</li>
<li>Reduced memory usage by a few megabytes (about 3-4, according to top)</li>
<li>Add support for KML files, make Mappero handle GPX and KML links directly from your N900 browser</li>
</ul>
All this is in version <tt>3.0+beta9</tt>, which is now available in Extras-devel repository and soon in Extras-testing too. Due to the deep changes in the code, I'm almost sure that some new bug has been introduced, so I'm not pushing you to install this version, unless you want to help with testing.Mappero brings you turn-by-turn navigation in your favourite languagehttp://mardy.it/it/blog/2010/05/mappero-brings-you-turn-by-turn.html2010-05-26T16:40:00+04:002010-05-26T16:40:00+04:00Alberto Mardegan<p>If your favourite language is <em><a href="http://www.interlingua.com">interlingua</a></em>, that is. Or if you are willing to record your voice and submit it for inclusion, chances are that the next version of mappero will support your language, with your voice too! :-)<br><br>
Just follow the <a href="http://talk.maemo.org/showthread.php?p=679792">detailed instructions in this thread</a>, and have the community enjoy your voice. :-) All languages supported by the N900 are supported by Mappero voice navigation too.</p><p><b>Mappero 3.0+beta7 is now in <a href="http://wiki.maemo.org/Extras-testing">extras-testing</a></b>, and with the advent of the PR1.2 release it shouldn't make the device unstable anymore. Please install it, test it, and <a href="http://maemo.org/packages/package_instance/view/fremantle_extras-testing_free_armel/maemo-mapper/3.0+beta7/">report your feedback</a> and hopefully it will get promoted to Maemo extras soon.</p><p>If your favourite language is <em><a href="http://www.interlingua.com">interlingua</a></em>, that is. Or if you are willing to record your voice and submit it for inclusion, chances are that the next version of mappero will support your language, with your voice too! :-)<br><br>
Just follow the <a href="http://talk.maemo.org/showthread.php?p=679792">detailed instructions in this thread</a>, and have the community enjoy your voice. :-) All languages supported by the N900 are supported by Mappero voice navigation too.</p><p><b>Mappero 3.0+beta7 is now in <a href="http://wiki.maemo.org/Extras-testing">extras-testing</a></b>, and with the advent of the PR1.2 release it shouldn't make the device unstable anymore. Please install it, test it, and <a href="http://maemo.org/packages/package_instance/view/fremantle_extras-testing_free_armel/maemo-mapper/3.0+beta7/">report your feedback</a> and hopefully it will get promoted to Maemo extras soon.</p>Le estate ha arrivate!http://mardy.it/it/blog/2010/05/le-estate-ha-arrivate.html2010-05-18T18:29:00+04:002010-05-18T18:29:00+04:00Alberto Mardegan<div class="separator" style="clear: both; text-align: center;"><a href="http://www.mardy.it/archivos/imagines/mappero-2010-05-18.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="320" src="http://www.mardy.it/archivos/imagines/mappero-2010-05-18.png" width="192"></a></div>In iste dies Finlandia es, apparentemente, un del paises le plus calide de Europa; durante le die, le temperatura in le sud del Finlandia es circa 22 grados, e in le nord (Lapponia) il ha 26 grados, un calor probabilemente insupportabile per ille homines de glacie.<br>
Iste vespere, le splendor del sol me ha incoragiate a exir del casa e currer un poco. De facto, io ha currite multo plus que io expectava, e sin troppo de effortio (benque io initiava a sentir alicun micrissime dolor in mi gambas); io mesmo extendeva le route que io habeva programmate, perque le climate e le natura esseva tanto agradabile que io non poteva stoppar. Al fin, io ha currite per quasi un hora — quasi vinti minutas plus que mi standard. E si io considera que io non curreva desde plure septimanas, io debe vermente congratular con me ipse. Ma vamos vider si deman io pote ancora levar me del lecto.<div class="separator" style="clear: both; text-align: center;"><a href="http://www.mardy.it/archivos/imagines/mappero-2010-05-18.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="320" src="http://www.mardy.it/archivos/imagines/mappero-2010-05-18.png" width="192"></a></div>In iste dies Finlandia es, apparentemente, un del paises le plus calide de Europa; durante le die, le temperatura in le sud del Finlandia es circa 22 grados, e in le nord (Lapponia) il ha 26 grados, un calor probabilemente insupportabile per ille homines de glacie.<br>
Iste vespere, le splendor del sol me ha incoragiate a exir del casa e currer un poco. De facto, io ha currite multo plus que io expectava, e sin troppo de effortio (benque io initiava a sentir alicun micrissime dolor in mi gambas); io mesmo extendeva le route que io habeva programmate, perque le climate e le natura esseva tanto agradabile que io non poteva stoppar. Al fin, io ha currite per quasi un hora — quasi vinti minutas plus que mi standard. E si io considera que io non curreva desde plure septimanas, io debe vermente congratular con me ipse. Ma vamos vider si deman io pote ancora levar me del lecto.