<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.8" -->
<?xml-stylesheet href="https://baszerr.eu/lib/exe/css.php?s=feed" type="text/css"?>
<rss version="2.0">
    <channel xmlns:g="http://base.google.com/ns/1.0">
        <title>BaSzErr - blog:2024:11:25</title>
        <description></description>
        <link>https://baszerr.eu/</link>
        <lastBuildDate>Thu, 16 Apr 2026 01:18:14 +0000</lastBuildDate>
        <generator>FeedCreator 1.8</generator>
        <image>
            <url>https://baszerr.eu/lib/exe/fetch.php?media=wiki:dokuwiki.svg</url>
            <title>BaSzErr</title>
            <link>https://baszerr.eu/</link>
        </image>
        <item>
            <title>2024-11-25_-_proper_version.hpp_with_cmake</title>
            <link>https://baszerr.eu/doku.php?id=blog:2024:11:25:2024-11-25_-_proper_version.hpp_with_cmake</link>
            <description>
&lt;h1 class=&quot;sectionedit1&quot; id=&quot;proper_versionhpp_with_cmake&quot;&gt;2024-11-25 - proper version.hpp with cmake&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;p&gt;
while working on &lt;a href=&quot;https://github.com/el-bart/yals&quot; class=&quot;urlextern&quot; title=&quot;https://github.com/el-bart/yals&quot; rel=&quot;ugc nofollow&quot;&gt;YALS&lt;/a&gt; i reached a point, where it would make sense to add some final touches. i wanted to generate &lt;code&gt;version.hpp&lt;/code&gt; header, that&amp;#039;d have all the stuff inside.
&lt;/p&gt;

&lt;p&gt;
first things first – getting version info. &lt;abbr title=&quot;In my humble opinion&quot;&gt;IMHO&lt;/abbr&gt; the nicest way of doing this in &lt;code&gt;git&lt;/code&gt; is:
&lt;/p&gt;
&lt;pre class=&quot;code bash&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;git describe&lt;/span&gt; &lt;span class=&quot;re5&quot;&gt;--always&lt;/span&gt; &lt;span class=&quot;re5&quot;&gt;--abbrev&lt;/span&gt;=&lt;span class=&quot;nu0&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;re5&quot;&gt;--dirty&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
this can return stuff like:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;v1.2&lt;/code&gt; – i.e. this version is tagged as &lt;code&gt;v1.2&lt;/code&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;v1.2-42-g5a61f67add&lt;/code&gt; – i.e. 42 commits away from &lt;code&gt;v1.2&lt;/code&gt;, i.e. commit hash &lt;code&gt;5a61f67add&lt;/code&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;v1.2-42-g5a61f67add-dirty&lt;/code&gt; – 42 commits away from &lt;code&gt;v1.2&lt;/code&gt;, i.e. commit hash &lt;code&gt;5a61f67add&lt;/code&gt;, with some local (unversioned) changes&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
i like this output – let&amp;#039;s stick with it for this example. now it&amp;#039;s time to integrate this with cmake.
&lt;/p&gt;

&lt;p&gt;
btw: note that i deliberately only focus on version only and not time / date of build. the reason is to ensure &lt;a href=&quot;https://en.wikipedia.org/wiki/reproducible builds&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/reproducible builds&quot;&gt;reproducible builds&lt;/a&gt;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;2024-11-25 - proper version.hpp with cmake&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;proper_versionhpp_with_cmake&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:1,&amp;quot;range&amp;quot;:&amp;quot;1-993&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit2&quot; id=&quot;the_cmake_way&quot;&gt;the cmake way&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
the canonical way of doing it is to create a file like this:
&lt;/p&gt;
&lt;pre class=&quot;code C&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// version.hpp&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#pragma once&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define MY_SW_VERSION &amp;quot;@GIT_VERSION_INFO@&amp;quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
and generate it with a &lt;a href=&quot;https://en.wikipedia.org/wiki/CMake&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/CMake&quot;&gt;cmake&lt;/a&gt;&amp;#039;s build-in &lt;a href=&quot;https://cmake.org/cmake/help/latest/command/configure_file.html&quot; class=&quot;urlextern&quot; title=&quot;https://cmake.org/cmake/help/latest/command/configure_file.html&quot; rel=&quot;ugc nofollow&quot;&gt;configure_file()&lt;/a&gt; function:
&lt;/p&gt;
&lt;pre class=&quot;code cmake&quot;&gt;&lt;a href=&quot;http://www.cmake.org/cmake/help/cmake2.6docs.html#command:configure_file&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;configure_file&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;sy0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_SOURCE_DIR}&lt;/span&gt;/version.hpp.in&amp;quot;&lt;/span&gt;
               &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_BINARY_DIR}&lt;/span&gt;/version.hpp&amp;quot;&lt;/span&gt;
               @ONLY&lt;span class=&quot;sy0&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
…and call it a day.
&lt;/p&gt;

&lt;p&gt;
there are however issues with this approach:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;version.hpp&lt;/code&gt; is a header, thus string will effectively be copy-and-pasted all over the code (that could be an issue for small embedded system)&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;version.hpp&lt;/code&gt; is a header, this any change to its content will force major recompilation (these kinds of headers tend to be include in a lot of places)&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; cmake will regenerate this file only when it does not exist&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
first 2 are major annoyances, but the last one is just horrible, as it means that the built-in version info may be outdated on incremental builds… which means you cannot really trust it… which defeats the whole purpose of putting this info into binary in a first place.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;the cmake way&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;the_cmake_way&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:2,&amp;quot;range&amp;quot;:&amp;quot;994-2181&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit3&quot; id=&quot;addressing_size_and_build_times&quot;&gt;addressing size and build times&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
addressing first 2 issues is simple – instead of having variable definition in a header, just move this into a &lt;code&gt;*.cpp&lt;/code&gt; like this:
&lt;/p&gt;
&lt;pre class=&quot;code C&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// version.hpp&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#pragma once&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;*&lt;/span&gt; my_sw_version&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;code C&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// version.cpp&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;quot;version.hpp&amp;quot;&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;*&lt;/span&gt; my_sw_version&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;@GIT_VERSION_INFO@&amp;quot;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
this way the string lives in only 1 object file. the only cmake different is that we now generate &lt;code&gt;version.cpp&lt;/code&gt; instead of &lt;code&gt;version.hpp&lt;/code&gt;… and that solves both issues at the same time. nice. :)
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;addressing size and build times&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;addressing_size_and_build_times&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:3,&amp;quot;secid&amp;quot;:3,&amp;quot;range&amp;quot;:&amp;quot;2182-2758&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit4&quot; id=&quot;ensuring_versioncpp_is_up_to_date&quot;&gt;ensuring version.cpp is up to date&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
this one is tricky. one could write a rule such that it will regenerate &lt;code&gt;version.cpp&lt;/code&gt; each time, to make sure it&amp;#039;s up to date. that would however cause re-link of all binaries every time we build. that&amp;#039;s not acceptable.
&lt;/p&gt;

&lt;p&gt;
there is however a trick in cmake one could use. first create a helper cmake file:
&lt;/p&gt;
&lt;pre class=&quot;code cmake&quot;&gt;&lt;span class=&quot;co1&quot;&gt;# version_proxy.cmake &lt;/span&gt;
&lt;a href=&quot;http://www.cmake.org/cmake/help/cmake2.6docs.html#command:execute_process&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;execute_process&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;sy0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw3&quot;&gt;COMMAND&lt;/span&gt; git describe --always --abbrev=10 --dirty
  &lt;span class=&quot;kw3&quot;&gt;WORKING_DIRECTORY&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_SOURCE_DIR}&lt;/span&gt;&amp;quot;&lt;/span&gt;
  OUTPUT_VARIABLE GIT_VERSION_INFO
  OUTPUT_STRIP_TRAILING_WHITESPACE
&lt;span class=&quot;sy0&quot;&gt;)&lt;/span&gt;
&lt;a href=&quot;http://www.cmake.org/cmake/help/cmake2.6docs.html#command:configure_file&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;configure_file&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;sy0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${SRC}&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${DST}&lt;/span&gt;&amp;quot;&lt;/span&gt; @ONLY&lt;span class=&quot;sy0&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
now inside the main &lt;code&gt;CMakeLists.txt&lt;/code&gt; call it out:
&lt;/p&gt;
&lt;pre class=&quot;code cmake&quot;&gt;&lt;span class=&quot;co1&quot;&gt;# CMakeLists.txt&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;# ...&lt;/span&gt;
&lt;a href=&quot;http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_custom_target&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;add_custom_target&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;sy0&quot;&gt;(&lt;/span&gt;version_proxy
 &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_COMMAND}&lt;/span&gt;&amp;quot;&lt;/span&gt; -D &lt;span class=&quot;st0&quot;&gt;&amp;quot;SRC=&lt;span class=&quot;es1&quot;&gt;${CMAKE_SOURCE_DIR}&lt;/span&gt;/version.cpp.in&amp;quot;&lt;/span&gt;
                    -D &lt;span class=&quot;st0&quot;&gt;&amp;quot;DST=&lt;span class=&quot;es1&quot;&gt;${CMAKE_BINARY_DIR}&lt;/span&gt;/version.cpp&amp;quot;&lt;/span&gt;
                    -P &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_SOURCE_DIR}&lt;/span&gt;/version_proxy.cmake&amp;quot;&lt;/span&gt;
  SOURCES    &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_SOURCE_DIR}&lt;/span&gt;/version.cpp.in&amp;quot;&lt;/span&gt;
  BYPRODUCTS &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_BINARY_DIR}&lt;/span&gt;/version.cpp&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sy0&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;# ...&lt;/span&gt;
&lt;a href=&quot;http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_executable&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;add_executable&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;sy0&quot;&gt;(&lt;/span&gt;foo_bar main.cpp &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es1&quot;&gt;${CMAKE_CURRENT_BINARY_DIR}&lt;/span&gt;/version.cpp&amp;quot;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;)&lt;/span&gt;
&lt;a href=&quot;http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_dependencies&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;add_dependencies&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;sy0&quot;&gt;(&lt;/span&gt;foo_bar version_proxy&lt;span class=&quot;sy0&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;# ...&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
the trick is to add dependency on &lt;code&gt;foo_bar&lt;/code&gt; target, that reference &lt;code&gt;version_proxy&lt;/code&gt; custom target, that in turn calls &lt;code&gt;cmake&lt;/code&gt; explicitly, from command line, defining source, destination and what&amp;#039;s expected as input and output files. this way cmake will always get called to re-evaluate the &lt;code&gt;version_proxy.cmake&lt;/code&gt;… that in turn does the generation the smart way – only if destination file would actually change.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;ensuring version.cpp is up to date&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;ensuring_versioncpp_is_up_to_date&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:5,&amp;quot;secid&amp;quot;:4,&amp;quot;range&amp;quot;:&amp;quot;2759-4344&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit5&quot; id=&quot;final_thoughts&quot;&gt;final thoughts&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
this solution ticks all the boxes – it rebuilds &lt;code&gt;version.cpp&lt;/code&gt; every time when version string changes… and only when it changes. it does a minimal rebuild (1 cpp + linking of dependent binaries). it does not proliferate copies of strings all over the binary.
&lt;/p&gt;

&lt;p&gt;
the interesting thing is that generating a &lt;code&gt;version.hpp&lt;/code&gt; is such an obvious feature, yet event today &lt;code&gt;cmake&lt;/code&gt; does not support it gracefully out of the box. the good news is that there is a reliable way of doing it, even if a bit verbose. ;)
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;final thoughts&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;final_thoughts&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:7,&amp;quot;secid&amp;quot;:5,&amp;quot;range&amp;quot;:&amp;quot;4345-&amp;quot;} --&gt;</description>
            <author>anonymous@undisclosed.example.com (Anonymous)</author>
            <pubDate>Fri, 10 Oct 2025 18:29:29 +0000</pubDate>
        </item>
    </channel>
</rss>
