<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pierre Gradot</title>
    <description>The latest articles on DEV Community by Pierre Gradot (@pgradot).</description>
    <link>https://dev.to/pgradot</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F355179%2F1f81fee5-db27-458a-a943-39402c915cc0.jpg</url>
      <title>DEV Community: Pierre Gradot</title>
      <link>https://dev.to/pgradot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pgradot"/>
    <language>en</language>
    <item>
      <title>User-Defined Deduction Guides for Class Templates in C++</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Mon, 25 Aug 2025 13:56:35 +0000</pubDate>
      <link>https://dev.to/pgradot/user-defined-deduction-guides-for-class-templates-in-c-2p3p</link>
      <guid>https://dev.to/pgradot/user-defined-deduction-guides-for-class-templates-in-c-2p3p</guid>
      <description>&lt;p&gt;I remember when I first got serious about modern C++. It was in 2017, my company was starting a new project from scratch, and we chose the latest standard: C++17, which had just been released. Diving into all the modern features of C++, I remember one feature that left me particularly puzzled: &lt;a href="https://en.cppreference.com/w/cpp/language/ctad.html#User-defined_deduction_guides" rel="noopener noreferrer"&gt;user-defined deduction guides&lt;/a&gt;. They are used to influence &lt;a href="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction.html" rel="noopener noreferrer"&gt;CTAD (Class Template Argument Deduction)&lt;/a&gt;, which was a major feature of C++17. I was puzzled because I couldn't understand why anyone would ever need to write such a guide by hand...&lt;/p&gt;

&lt;p&gt;Last year, after 7 years of C++17 and above, I finally needed to write my very first own template deduction guide! 🤯 &lt;/p&gt;

&lt;p&gt;I know, it took me 15 months to write an article on this topic, but here it is!&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;I was working on a plugin for &lt;a href="https://www.qemu.org/docs/master/system/target-arm.html" rel="noopener noreferrer"&gt;QEMU's ARM system emulator&lt;/a&gt; to record ("trace") the execution of an &lt;a href="https://eshard.com/posts/android-trace-execution-recording-for-doing-time-travel-analysis" rel="noopener noreferrer"&gt;ARM system running Android&lt;/a&gt;. I wrote a generic trace generator, and then 2 specializations for ARM 32-bit or 64-bit variants, all in the same plugin. The code avoided &lt;code&gt;virtual&lt;/code&gt; functions as much as possible because the application was highly performance-sensitive and I didn't want to pay for the cost of &lt;a href="https://dev.tocontent/posts/2024/vtables-1-concepts"&gt;vtables and virtual calls&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Genericity was mainly achieved by using templates. A &lt;em&gt;lot&lt;/em&gt; of templates. Most of these templates worked well with the automatic template deduction rules. Most of them, but not &lt;em&gt;all&lt;/em&gt; of them. This is the context where I needed my own deduction guide: writing templates to trace the execution of a CPU, with all the modifications to its registers and to the system memory.&lt;/p&gt;

&lt;p&gt;In the following, I will of course not show the real code, but a minimal dummy code to illustrate the situation. It will really be a &lt;em&gt;dummy&lt;/em&gt; code: don't expect well-designed classes, just plausible code where a "user-defined deduction guide" is necessary. However, I think that somehow realistic code samples will be more instructive than &lt;code&gt;Foo&lt;/code&gt;-&lt;code&gt;Bar&lt;/code&gt; examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Example Where CTAD Fails
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Base class template
&lt;/h3&gt;

&lt;p&gt;Let's start with the base class template for a generic trace generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;tuple&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Registers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TraceGenerator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="n"&gt;TraceGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;registers_m&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;readers_m&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;TraceGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;__PRETTY_FUNCTION__&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;some_architecture_specific_function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="c1"&gt;// Let's omit the code that uses registers_m and readers_m, for the sake of simplicity&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;Registers&lt;/span&gt; &lt;span class="n"&gt;registers_m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readers_m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;some_architecture_specific_function&lt;/span&gt;&lt;span class="p"&gt;()&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The template has 2 parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a type &lt;code&gt;Registers&lt;/code&gt;, with the registers of the target architecture / CPU.&lt;/li&gt;
&lt;li&gt;a list of types &lt;code&gt;MemoryReaders&lt;/code&gt;, to read the memories of the target machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is one pure virtual function so this "class" must be inherited to implement the function. Yes, I said that I avoided &lt;code&gt;virtual&lt;/code&gt; as much as possible, not at all 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Specialization for ARM
&lt;/h3&gt;

&lt;p&gt;Android runs on ARM processors. We need something for Android.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ArmRegisters&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArmTraceGenerator&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TraceGenerator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ArmRegisters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;TraceGenerator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ArmRegisters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;TraceGenerator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;some_architecture_specific_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;__PRETTY_FUNCTION__&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We implement the pure virtual function, we set the &lt;code&gt;Registers&lt;/code&gt; template parameter, but we still have a class template: the &lt;code&gt;MemoryReaders&lt;/code&gt; pack still have to be set to create an actual class. Because constructors are not automatically inherited in C++, we must add this &lt;code&gt;using&lt;/code&gt; declaration to expose the base class constructors (see section "Inheriting constructors" from &lt;a href="https://en.cppreference.com/w/cpp/language/using_declaration.html" rel="noopener noreferrer"&gt;"Using-declaration" on cppreference&lt;/a&gt;). And yes: because the content of &lt;code&gt;Registers&lt;/code&gt; is not actually used here, an empty structure is enough for our example.&lt;/p&gt;

&lt;p&gt;Finally, we can write a simple &lt;code&gt;main()&lt;/code&gt; that uses this class template to create an actual generator for our target. Let's say this machine has 2 memories, one RAM, one FLASH. We create two reader classes, a tuple with an instance of one of each these classes, and we can finally create the trace generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;RamReader&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;FlashReader&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArmTraceGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;RamReader&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;FlashReader&lt;/span&gt;&lt;span class="p"&gt;{}});&lt;/span&gt;
    &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create our object with &lt;code&gt;auto generator = ArmTraceGenerator(...)&lt;/code&gt; without explicitly specifying the types in the parameter pack. This means we are asking the compiler to deduce the &lt;code&gt;MemoryReaders&lt;/code&gt; parameter pack and instantiate the appropriate &lt;code&gt;ArmTraceGenerator&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;However, as beautiful and valid as this code seems, it doesn't compile (*):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main.cpp: In function ‘int main()’:
main.cpp:46:79: error: class template argument deduction failed:
   46 |         auto generator = ArmTraceGenerator(std::tuple{RamReader{}, FlashReader{}});
      |                                                                               ^

(... followed by many other template errors, as always with templates)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why? Because CTAD is not applicable in this situation, as explained in &lt;a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2582r1.pdf" rel="noopener noreferrer"&gt;P2582R1&lt;/a&gt; :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In C++17, deduction guides (implicit and explicit) are not inherited when constructors are inherited&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1021r6.html" rel="noopener noreferrer"&gt;P1021R6&lt;/a&gt; already suggested to change this behavior for C++20, but it "was not finalized in time". P2582R1 also proposed a similar change, and it was accepted for C++23. However, the &lt;a href="https://en.cppreference.com/w/cpp/compiler_support.html" rel="noopener noreferrer"&gt;compiler support is still very poor for P2582R1 "Class template argument deduction from inherited constructors"&lt;/a&gt;: GCC implements it since version 14, but Clang and MSVC don't.&lt;/p&gt;

&lt;p&gt;(*) = so "it doesn't compile" on my machine because I am compiling this example with GCC 12.2 and &lt;code&gt;-std=c++20&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this code to compile, we have 4 solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use GCC 14+ and &lt;code&gt;-std=c++23&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Don't rely on CTAD: specify the types explicitly with &lt;code&gt;auto generator = ArmTraceGenerator&amp;lt;RamReader, FlashReader&amp;gt;(...)&lt;/code&gt;. This is fine here, as there are only 2 types in the parameter pack. Nevertheless, listing all the actual types can become a nightmare. In my real code, I had a parameter pack with more than 1000 elements, so CTAD was essential.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remove the &lt;code&gt;using TraceGenerator&amp;lt;ArmRegisters, MemoryReaders...&amp;gt;::TraceGenerator&lt;/code&gt; to stop inheriting constructors and provide a compatible constructor directly in the derived class:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="n"&gt;ArmTraceGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TraceGenerator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ArmRegisters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readers&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write a user-defined deduction guide.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's explore this last possibility (as it's the topic of this blog post 😂).&lt;/p&gt;

&lt;h3&gt;
  
  
  User-Defined Deduction Guide
&lt;/h3&gt;

&lt;p&gt;Since the compiler cannot deduce the template arguments, we can write a deduction guide to help it. This is surprisingly simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nc"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;ArmTraceGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ArmTraceGenerator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MemoryReaders&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, this guide explains that creating an &lt;code&gt;ArmTraceGenerator&lt;/code&gt; object from a &lt;code&gt;tuple&amp;lt;MemoryReaders...&amp;gt;&lt;/code&gt; in fact creates an &lt;code&gt;ArmTraceGenerator&amp;lt;MemoryReaders...&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As with everything in C++, user-defined deduction guides must be known when they are to be used, so this guide must be &lt;em&gt;before&lt;/em&gt; the &lt;code&gt;main()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The code now compiles and prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void TraceGenerator&amp;lt;Registers, MemoryReaders&amp;gt;::generate() [with Registers = ArmRegisters; MemoryReaders = {RamReader, FlashReader}]
void ArmTraceGenerator&amp;lt;MemoryReaders&amp;gt;::some_architecture_specific_function() [with MemoryReaders = {RamReader, FlashReader}]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other Examples
&lt;/h2&gt;

&lt;p&gt;You might be thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OK, fine. You've shown an example where CTAD fails, but C++23 solved the issue and a user-defined guide was not even required, as they were workarounds even in C++17. Do you have any other (more solid) examples?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes 🥳&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Where CTAD Fails Without a Workaround (*)
&lt;/h3&gt;

&lt;p&gt;(*) = At least, I haven't found any.&lt;/p&gt;

&lt;p&gt;Let's consider another class template to handle chunks of memory. It encapsulates an &lt;a href="https://dev.to/pgradot/let-s-try-c-20-std-span-1682"&gt;&lt;code&gt;std::span&lt;/code&gt;&lt;/a&gt; over caller-owned data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_integral_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MemoryChunk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;chunk_m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;__PRETTY_FUNCTION__&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;print_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;__PRETTY_FUNCTION__&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chunk_m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Memory size = "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" bytes"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chunk_m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()};&lt;/span&gt;
    &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_info&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works perfectly fine, CTAD is possible and &lt;code&gt;T&lt;/code&gt; is deduced to be &lt;code&gt;int&lt;/code&gt;, as shown in the program output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MemoryChunk&amp;lt;T&amp;gt;::MemoryChunk(T*, std::size_t) [with T = int; std::size_t = long unsigned int]
void MemoryChunk&amp;lt;T&amp;gt;::print_info() const [with T = int]
Memory size = 64 bytes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's say we want construct &lt;code&gt;MemoryChunk&lt;/code&gt;s from various types of iterators. We can add a templated constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;contiguous_iterator&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;chunk_m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;__PRETTY_FUNCTION__&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, we clearly see that CTAD won't work here: &lt;code&gt;T&lt;/code&gt; doesn't appear so the compiler cannot deduce it and will require a user-defined deduction guide.&lt;/p&gt;

&lt;p&gt;We must find a way to deduce &lt;code&gt;T&lt;/code&gt; from &lt;code&gt;Iterator&lt;/code&gt;. Our first attempt could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can try this new constructor in our &lt;code&gt;main()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()};&lt;/span&gt;
    &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_info&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sadly, this code doesn't compile... For once, the last template errors are the most informative (in general, we just read the first one and ignore everything after it 😅):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main.cpp:34:1: error: template constraint failure for ‘template&amp;lt;class T&amp;gt;  requires  is_integral_v&amp;lt;T&amp;gt; class MemoryChunk’
main.cpp:34:1: note: constraints not satisfied
main.cpp: In substitution of ‘template&amp;lt;class T&amp;gt;  requires  is_integral_v&amp;lt;T&amp;gt; class MemoryChunk [with T = int&amp;amp;]’:
main.cpp:34:1:   required by substitution of ‘template&amp;lt;class Iterator&amp;gt; MemoryChunk(Iterator, Iterator)-&amp;gt; MemoryChunk&amp;lt;decltype (* begin)&amp;gt; [with Iterator = int*]’
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The last line shows that the compiler is trying to use our guide&lt;/li&gt;
&lt;li&gt;The first line tells that the &lt;code&gt;requires&lt;/code&gt; clause on &lt;code&gt;T&lt;/code&gt; is not satisfied.&lt;/li&gt;
&lt;li&gt;The third line shows that &lt;code&gt;T&lt;/code&gt; is &lt;code&gt;int&amp;amp;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;T&lt;/code&gt; is deduced as &lt;code&gt;int&amp;amp;&lt;/code&gt;, not just &lt;code&gt;int&lt;/code&gt;. Indeed, &lt;code&gt;*data.begin()&lt;/code&gt; returns a reference, not a copy of the first element. An assertion like &lt;code&gt;static_assert(std::is_same_v&amp;lt;decltype(*data.begin()), int&amp;amp;&amp;gt;);&lt;/code&gt; doesn't fail.&lt;/p&gt;

&lt;p&gt;We just have to modify the rule to remove the reference and the code works fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template &amp;lt;typename Iterator&amp;gt;
MemoryChunk(Iterator begin, Iterator end) -&amp;gt; MemoryChunk&amp;lt;std::remove_reference_t&amp;lt;decltype(*begin)&amp;gt;&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that guides are SFINAE friendly. We can have both rules and the code works.&lt;/p&gt;

&lt;p&gt;You could even add an obviously incorrect rule like the one below, and the code would still work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MemoryChunk&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;dummy_static_field_that_doesnt_exist&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example to Overwrite the Deduced Type
&lt;/h3&gt;

&lt;p&gt;For this last example, let's imagine a super basic &lt;code&gt;Metadata&lt;/code&gt; class template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use it with a string literal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name of something"&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assertion shows that CTAD has deduced &lt;code&gt;const char*&lt;/code&gt;, which is the correct type for a string literal.&lt;/p&gt;

&lt;p&gt;But let's imagine that we want to modify the name in the metadata afterward. &lt;code&gt;metadata.name[0] = 'N';&lt;/code&gt; doesn't compile: &lt;code&gt;error: assignment of read-only location ‘* metadata.Metadata&amp;lt;const char*&amp;gt;::name’&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can influence CTAD by writing a deduction guide that forces &lt;code&gt;T&lt;/code&gt; to be &lt;code&gt;std::string&lt;/code&gt; instead of &lt;code&gt;const char*&lt;/code&gt;. Unlike our previous guides, it's not templated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;MemoryMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MemoryMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous assertion fails and must be replaced with &lt;code&gt;static_assert(std::is_same_v&amp;lt;decltype(metadata), Metadata&amp;lt;std::string&amp;gt;&amp;gt;);&lt;/code&gt;. And as desired, &lt;code&gt;metadata.name[0] = 'N';&lt;/code&gt; now compiles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Class Template Argument Deduction  (CTAD) was one of the most powerful features of C++17. It greatly simplifies the use of class templates by eliminating the need to explicitly specify template arguments. However, there are situations in which CTAD fails.&lt;/p&gt;

&lt;p&gt;User-defined deduction guides are the solution in these cases. They are fairly simple to write and allow you to restore deduction behavior, or even influence it when the default rules do not meet your requirements. You may never need them, but now you know how to write them and in which situations they can be useful.&lt;/p&gt;

</description>
      <category>cpp</category>
    </item>
    <item>
      <title>How to Fix "Low Disk Space on /boot" on Linux</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Tue, 17 Jun 2025 12:56:11 +0000</pubDate>
      <link>https://dev.to/pgradot/how-to-fix-low-disk-space-on-boot-on-linux-2n6n</link>
      <guid>https://dev.to/pgradot/how-to-fix-low-disk-space-on-boot-on-linux-2n6n</guid>
      <description>&lt;p&gt;One day, you power up your computer, wait for Linux to boot, log in... and this message pops up:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2125rln4ubxp3qj9re72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2125rln4ubxp3qj9re72.png" alt="low space disk on boot" width="506" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might decide to ignore it, or you might think this is an issue worth looking into. And you’d be right!&lt;/p&gt;

&lt;p&gt;However, clicking "Examine" doesn't really tell you how to fix the issue. It "just" shows you the disk usage analysis of the &lt;code&gt;/boot&lt;/code&gt; partition:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowrgmamh843agc3qw6ho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowrgmamh843agc3qw6ho.png" alt="disk usage analyzer before cleanup" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This might look a little cryptic if you're not familiar with Linux internals...&lt;/p&gt;

&lt;p&gt;This article breaks down what this message means and how to clean up the partition safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is &lt;code&gt;/boot&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;/boot&lt;/code&gt; directory is a special partition that contains the files needed to start the operating system. It typically resides on its own partition.&lt;/p&gt;

&lt;p&gt;When you click "Examine" the Disk Analyzer tool displays files from this partition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grub&lt;/code&gt;: the directory with the files for the &lt;a href="https://en.wikipedia.org/wiki/GNU_GRUB" rel="noopener noreferrer"&gt;GRUB&lt;/a&gt; bootloader, the first program that runs when you power on your computer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;initrd.img-*&lt;/code&gt;: the initial RAM disk, a small temporary filesystem loaded into memory before the actual filesystem can be mounted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vmlinuz-*&lt;/code&gt;: the compressed Linux kernel, which is the core of the operating system.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;System.map-*&lt;/code&gt;: a symbol table that maps kernel functions to memory addresses (mostly useful for debugging).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;config-*&lt;/code&gt;: the kernel configuration file used to build each kernel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each kernel version comes with its own set of these files. That’s why you might see several groups with version numbers: 6.12.27, 6.12.22, 6.10.11, etc. The latest one is probably the kernel currently in use, while the others were left behind after system updates.&lt;/p&gt;

&lt;p&gt;Over time, these accumulate and can fill up the partition. This is exactly what the message is telling us: the partition &lt;code&gt;/boot&lt;/code&gt; is almost full.&lt;/p&gt;

&lt;p&gt;You probably got it: the files in this partition are critical for the system, and it's important to have space available for new kernel updates, as they often include security fixes.&lt;/p&gt;

&lt;p&gt;In the next section, we’ll identify which files are still needed, and which ones can be safely removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Resolve The Issue?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1: Expand The Partition
&lt;/h3&gt;

&lt;p&gt;If a partition is almost full, one possible solution is increase its size. I've written &lt;a href="https://dev.to/blog/posts/2024/resize-fs/"&gt;a comprehensive guide on resizing partitions on Linux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, I don't believe it's a good solution here. New kernel are regularly installed, so you'll likely run out of space again. Furthermore, old kernel are generally no longer needed and can be removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  2: Use Synaptic Package Manager
&lt;/h3&gt;

&lt;p&gt;The easiest solution is to manually select and remove old kernel packages using Synaptic Package Manager.&lt;/p&gt;

&lt;p&gt;Open it with root privileges, click the "Search" button, and search for "linux-image":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc2k5uil3v8knnoo7fqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc2k5uil3v8knnoo7fqc.png" alt="search for linux-image" width="312" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sort the packages by installed version in descending order (the latest versions will appear at the top of the list):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh83kv1bj8mrtok9unkji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh83kv1bj8mrtok9unkji.png" alt="list of installed packages in synaptic" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's wise to keep 2 or 3 kernels, just in case a newer kernel causes issues. Yes, a new kernel can break something on your computer. For example, read &lt;a href="https://dev.to/blog/posts/2025/linux-driver-wifi/"&gt;this story&lt;/a&gt; where I describe how my Wi-Fi stop working after an update from 6.10.11 to 6.11.10 and how I installed a new driver manually to restore connectivity.&lt;/p&gt;

&lt;p&gt;Select the old kernels, right-click on them, and select "Mark for complete removal":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8x224y7rdss8orfuc2ka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8x224y7rdss8orfuc2ka.png" alt="packages marked for removal" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, I decided to keep 6.10.11 (where my Wi-Fi was still working out-of-the-box) and the 2 latest versions.&lt;/p&gt;

&lt;p&gt;Finally, click on the apply button to remove them.&lt;/p&gt;

&lt;h3&gt;
  
  
  3: Use The Command Line
&lt;/h3&gt;

&lt;p&gt;If you prefer command lines over GUIs, you can manually search for and remove the packages manually from a terminal.&lt;/p&gt;

&lt;p&gt;First, list the installed packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;apt list &lt;span class="nt"&gt;--installed&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;linux-image

WARNING: apt does not have a stable CLI interface. Use with caution &lt;span class="k"&gt;in &lt;/span&gt;scripts.

linux-image-6.10.11+bpo-amd64/now 6.10.11-1~bpo12+1 amd64 &lt;span class="o"&gt;[&lt;/span&gt;installed,local]
linux-image-6.12.22+bpo-amd64/stable-backports,now 6.12.22-1~bpo12+1 amd64 &lt;span class="o"&gt;[&lt;/span&gt;installed,automatic]
linux-image-6.12.27+bpo-amd64/stable-backports,now 6.12.27-1~bpo12+1 amd64 &lt;span class="o"&gt;[&lt;/span&gt;installed,automatic]
linux-image-amd64/stable-backports,now 6.12.27-1~bpo12+1 amd64 &lt;span class="o"&gt;[&lt;/span&gt;installed]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm running this command on my computer after removing old kernels with Synaptic Package Manager, and we can see that 6.10.5 and 6.5.0 are no longer present.&lt;/p&gt;

&lt;p&gt;Second, delete the packages you want with &lt;code&gt;sudo apt remove linux-image-&amp;lt;version&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4: The Automatic Way
&lt;/h3&gt;

&lt;p&gt;Another solution is to run &lt;code&gt;sudo apt autoremove --purge&lt;/code&gt; from a terminal.&lt;/p&gt;

&lt;p&gt;This command removes unused packages, typically dependencies that were automatically installed and are now unused. The &lt;code&gt;--purge&lt;/code&gt; flag goes one step further by removing their configuration files as well.&lt;/p&gt;

&lt;p&gt;However, this approach is somewhat indirect: you’re not specifically targeting old kernels, you just hope that the package manager considers them as unused and will remove them automatically. In my case, it wasn't enough: the free space went from 11 to 19 MB, and the message reappeared at the next boot.&lt;/p&gt;

&lt;p&gt;If I run the command now on my computer, here's what I get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoremove &lt;span class="nt"&gt;--purge&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; password &lt;span class="k"&gt;for &lt;/span&gt;pierre: 
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages will be REMOVED:
  linux-headers-6.10.6+bpo-common&lt;span class="k"&gt;*&lt;/span&gt; linux-kbuild-6.10.6+bpo&lt;span class="k"&gt;*&lt;/span&gt;
0 upgraded, 0 newly installed, 2 to remove and 11 not upgraded.
After this operation, 63.6 MB disk space will be freed.
Do you want to &lt;span class="k"&gt;continue&lt;/span&gt;? &lt;span class="o"&gt;[&lt;/span&gt;Y/n] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that no &lt;code&gt;linux-image&lt;/code&gt; packages are selected for removal, not even 6.10.11 which is &lt;a href="https://www.kernel.org/pub/linux/kernel/v6.x/" rel="noopener noreferrer"&gt;relatively old&lt;/a&gt; (it was released in September 2024, and I'm writing these lines in June 2025).&lt;/p&gt;

&lt;p&gt;Still, it's a good idea to run this command after using one of the previous solutions, to be sure to clean up any leftover packages related to an uninstalled kernel (like this &lt;code&gt;linux-headers-6.10.6+bpo-common&lt;/code&gt; here).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After cleanup, we can check the results with the Disk Usage Analyzer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifov0j1nwhnvpey9tde7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifov0j1nwhnvpey9tde7.png" alt="disk usage analyzer after cleanup" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, 430 MB were used. Now, it's down to 273 MB. The &lt;code&gt;df&lt;/code&gt; command shows the percentage of free space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; /boot
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  456M  260M  171M  61% /boot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problem solved! Until &lt;code&gt;/boot&lt;/code&gt; is full again 😉&lt;/p&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>clang-tidy, const &amp; (N)RVO</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Fri, 06 Jun 2025 06:47:23 +0000</pubDate>
      <link>https://dev.to/pgradot/clang-tidy-const-nrvo-gep</link>
      <guid>https://dev.to/pgradot/clang-tidy-const-nrvo-gep</guid>
      <description>&lt;p&gt;Almost one year ago, clang-tidy threw an unexpected and unfamiliar message in my face: &lt;code&gt;warning: constness of 'str' prevents automatic move [performance-no-automatic-move]&lt;/code&gt; (documented &lt;a href="https://clang.llvm.org/extra/clang-tidy/checks/performance/no-automatic-move.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;). The incriminated code looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... do some work with 'str'...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- the warning was here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn’t have time to investigate, so I wrote down a note, swore I would look into it later, and just forgot... Until today. I thought it would be simple. It was not. Because, as always, C++ is full of surprises.&lt;/p&gt;

&lt;p&gt;Let me tell you the story of &lt;code&gt;clang-tidy&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt; and (N)RVO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Almost Always Const Auto (AACA)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Almost Always Auto&lt;/em&gt; (or AAA) is a very common practice in modern C++. The acronym was coined by Herb Sutter in &lt;a href="https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/" rel="noopener noreferrer"&gt;episode 94&lt;/a&gt; of Guru Of The Week (GotW) series.&lt;/p&gt;

&lt;p&gt;Another common practice is to use &lt;code&gt;const&lt;/code&gt; (almost) by default. In Scott Meyers's &lt;em&gt;Effective C++&lt;/em&gt;, item 3 is "use const whenever possible" and another &lt;a href="http://www.gotw.ca/gotw/006.htm" rel="noopener noreferrer"&gt;episode of GotW&lt;/a&gt; begins with "always use &lt;code&gt;const&lt;/code&gt; as much as possible, but no more".&lt;/p&gt;

&lt;p&gt;In his book &lt;em&gt;C++ Best Practices&lt;/em&gt;, Jason Turner includes 3 rules about &lt;code&gt;auto&lt;/code&gt; and &lt;code&gt;const(expr)&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rule 12: "&lt;code&gt;const&lt;/code&gt; Everything That’s Not &lt;code&gt;constexpr&lt;/code&gt;"&lt;/li&gt;
&lt;li&gt;Rule 13: "&lt;code&gt;constexpr&lt;/code&gt; Everything Known at Compile Time"&lt;/li&gt;
&lt;li&gt;Rule 14: "Prefer auto in Many Cases"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine these two principles, and we have coined another acronym: Almost Always Const Auto (AACA). I have been using this coding style for a few years now, especially after discovering Rust. In Rust, variables are constant by default, and we must use the &lt;code&gt;mut&lt;/code&gt; modifier to make them mutable, which the opposite of C++ with &lt;code&gt;const&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is why in the code sample from the introduction, I declare &lt;code&gt;str&lt;/code&gt; with &lt;code&gt;const auto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;auto&lt;/code&gt; is not relevant when decoding &lt;code&gt;clang-tidy&lt;/code&gt;'s warning message. &lt;code&gt;const&lt;/code&gt; is. Apparently, I should not use &lt;code&gt;const&lt;/code&gt; here, as it prevents the value from being moved when it's returned from the function.&lt;/p&gt;

&lt;p&gt;Have I been wrong to use &lt;code&gt;const&lt;/code&gt; so much during all these years? I'm not the only developer following the advice of the C++ legends mentioned above. For instance, see &lt;a href="https://www.youtube.com/watch?v=xIelg0R46MM" rel="noopener noreferrer"&gt;here&lt;/a&gt;, &lt;a href="https://stackoverflow.com/questions/22285773/use-const-wherever-possible-in-c" rel="noopener noreferrer"&gt;here&lt;/a&gt;, &lt;a href="https://huixie90.github.io/Almost-always-const-auto-ref/" rel="noopener noreferrer"&gt;here&lt;/a&gt; or &lt;a href="https://belaycpp.com/2021/06/30/should-every-variable-be-const-by-default/" rel="noopener noreferrer"&gt;there&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Example
&lt;/h2&gt;

&lt;p&gt;Let’s write a complete example that we can run and analyze. I’ve chosen to avoid &lt;code&gt;auto&lt;/code&gt; because I want to focus on &lt;code&gt;const&lt;/code&gt;, and you don’t have the type overlays from my IDE showing the deduced types 😉 (of course, in real life, I would use &lt;code&gt;auto&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.cpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fmt/std.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... do some work with 'str'...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my/base/dir"&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code compiles perfectly and prints &lt;code&gt;my/base/dir/output/0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can run &lt;code&gt;clang-tidy&lt;/code&gt; on this file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;clang-tidy &lt;span class="nt"&gt;-p&lt;/span&gt; cmake-build-debug &lt;span class="nt"&gt;--checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"clang-*,performance-*"&lt;/span&gt; main.cpp
106 warnings generated.
/home/pierre/cpp/main.cpp:9:9: warning: constness of &lt;span class="s1"&gt;'str'&lt;/span&gt; prevents automatic move &lt;span class="o"&gt;[&lt;/span&gt;performance-no-automatic-move]
        &lt;span class="k"&gt;return &lt;/span&gt;str&lt;span class="p"&gt;;&lt;/span&gt;
               ^
Suppressed 105 warnings &lt;span class="o"&gt;(&lt;/span&gt;105 &lt;span class="k"&gt;in &lt;/span&gt;non-user code&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Use &lt;span class="nt"&gt;-header-filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.&lt;span class="k"&gt;*&lt;/span&gt; to display errors from all non-system headers. Use &lt;span class="nt"&gt;-system-headers&lt;/span&gt; to display errors from system headers as well.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to &lt;code&gt;clang-tidy&lt;/code&gt;, the string cannot be moved. It means it is copied, which is slower.&lt;/p&gt;

&lt;p&gt;Because we use &lt;code&gt;std::string&lt;/code&gt;, it's not easy to check what the compiler is actually doing. The simplest solution is to replace &lt;code&gt;std::string&lt;/code&gt; with our own type so that we can print messages in its constructors.&lt;/p&gt;

&lt;h2&gt;
  
  
  With A Custom Class
&lt;/h2&gt;

&lt;p&gt;Let's introduce a new class called &lt;code&gt;Path&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fmt/std.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Constructor called"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Copy constructor called"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;

        &lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Move constructor called"&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="n"&gt;nodiscard&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;value_m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;// ... do some work with 'path'...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my/base/dir"&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enhanced code compiles perfectly too and produces the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Constructor called
my/base/dir/output/0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great: &lt;code&gt;path&lt;/code&gt; is not copied; it's not even moved. Otherwise, we would see the text printed from their bodies.&lt;/p&gt;

&lt;p&gt;And yet, &lt;code&gt;clang-tidy&lt;/code&gt; still emits the same warning on &lt;code&gt;return path;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This feels a little awkward. On the one hand, our static analyzer warns that we might hit a performance penalty; on the other hand, our compiler generates optimal code. We can use &lt;a href="https://godbolt.org/z/331o1zMbc" rel="noopener noreferrer"&gt;Compiler Explorer&lt;/a&gt; to check whether this behavior is consistent across several compilers and versions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;clang&lt;/th&gt;
&lt;th&gt;gcc&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20.1.0 ✅&lt;/td&gt;
&lt;td&gt;15.1 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.0.0 ✅&lt;/td&gt;
&lt;td&gt;8.1 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As I write these lines, these are the latest versions and fairly old versions.&lt;/p&gt;

&lt;p&gt;To understand what’s going on here, it’s time to introduce the third character of this story: (N)RVO.&lt;/p&gt;

&lt;h2&gt;
  
  
  (Named) Return Value Optimization
&lt;/h2&gt;

&lt;p&gt;RVO (Return Value Optimization) and NRVO (Named Return Value Optimization) are two common optimizations that the compiler may use when returning a local variable from a function. Since C++17, RVO is even mandatory. PVS-Studio has a great &lt;a href="https://pvs-studio.com/en/blog/terms/6516/" rel="noopener noreferrer"&gt;post&lt;/a&gt; explaining how these optimizations work and what the difference is between them. People tend to use both terms interchangeably, but in some cases (like our case today), the difference is relevant.&lt;/p&gt;

&lt;p&gt;Our code is an exact match for NRVO: we have a named local variable whose type exactly matches the return type of the function, and we return this variable. The compiler optimizes the code by neither copying nor moving the variable &lt;code&gt;path&lt;/code&gt;. Instead, it constructs the object directly in place, into &lt;code&gt;dir&lt;/code&gt; in the &lt;code&gt;main&lt;/code&gt; function. Hence the program output: we don't see any messages from the copy or move constructors, because they are not called.&lt;/p&gt;

&lt;p&gt;Note that we can use a slightly modified version of our code (removing the use of the &lt;a href="https://github.com/fmtlib/fmt" rel="noopener noreferrer"&gt;&lt;br&gt;
&lt;code&gt;fmt&lt;/code&gt; library&lt;/a&gt;) with &lt;a href="https://cppinsights.io/lnk?code=I2luY2x1ZGUgPHN0cmluZz4KCmNsYXNzIFBhdGggewpwdWJsaWM6CglleHBsaWNpdCBQYXRoKHN0ZDo6c3RyaW5nIHBhdGgpIDoKCQl2YWx1ZV9te3N0ZDo6bW92ZShwYXRoKX0gewoJfQoKCVBhdGgoY29uc3QgUGF0aCYgb3RoZXIpIDoKCQl2YWx1ZV9te290aGVyLnZhbHVlX219IHsKCX0KCglQYXRoKFBhdGgmJiBvdGhlcikgbm9leGNlcHQgOgoJCXZhbHVlX217c3RkOjptb3ZlKG90aGVyLnZhbHVlX20pfSB7Cgl9CgoJW1tub2Rpc2NhcmRdXSBjb25zdCBzdGQ6OnN0cmluZyYgdmFsdWUoKSBjb25zdCB7CgkJcmV0dXJuIHZhbHVlX207Cgl9Cgpwcml2YXRlOgoJc3RkOjpzdHJpbmcgdmFsdWVfbTsKfTsKClBhdGggYnVpbGRfcGF0aChjb25zdCBzdGQ6OnN0cmluZyYgYmFzZWRpciwgaW50IGluZGV4KSB7Cgljb25zdCBQYXRoIHBhdGggPSBQYXRoKGJhc2VkaXIpOwoJcmV0dXJuIHBhdGg7Cn0KCmludCBtYWluKCkgewoJY29uc3QgUGF0aCBkaXIgPSBidWlsZF9wYXRoKCJteS9iYXNlL2RpciIsIDApOwp9Cg==&amp;amp;insightsOptions=cpp17&amp;amp;std=cpp17&amp;amp;rev=1.0" rel="noopener noreferrer"&gt;cppinsights&lt;/a&gt;. It tells us that &lt;code&gt;path&lt;/code&gt; is indeed an "NRVO variable":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng94ftjpjdiaum333mjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng94ftjpjdiaum333mjz.png" alt="cppinsight tells that path is an NRVO variable" width="623" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Can we say that &lt;code&gt;clang-tidy&lt;/code&gt;'s warning is a false positive? In this specific case, we can probably assume so.&lt;/p&gt;

&lt;p&gt;Can we blindly disable the warning by adding &lt;code&gt;-performance-no-automatic-move&lt;/code&gt; to our command-line or &lt;code&gt;.clang-tidy&lt;/code&gt; file? Probably not... But we need to look at more complex cases to understand why.&lt;/p&gt;
&lt;h2&gt;
  
  
  NRVO is optional
&lt;/h2&gt;

&lt;p&gt;This is an important point that I want to stress again: &lt;strong&gt;NRVO is optional&lt;/strong&gt;. We have no guarantee that the future versions of &lt;code&gt;clang&lt;/code&gt; or &lt;code&gt;gcc&lt;/code&gt; will still optimize our code the same way. That's why I used the word "assume" in the previous section.&lt;/p&gt;

&lt;p&gt;How easy it to fall into situations where the optimization is no longer applied? Let's experiment by modifying &lt;code&gt;build_path()&lt;/code&gt; and observing how the program's output changes. Each variation can then be tested using Compiler Explorer with the same compilers as before. For each variation, I indicate whether NRVO is applied or whether a constructor (copy or move) is called.&lt;/p&gt;
&lt;h3&gt;
  
  
  Variation 1
&lt;/h3&gt;

&lt;p&gt;We just add an early return (for which RVO will/must be applied). Try it &lt;a href="https://godbolt.org/z/P3TEqoaYT" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&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="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;// ... do some work with 'path'...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;clang&lt;/th&gt;
&lt;th&gt;gcc&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20.1.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;15.1 =&amp;gt; ❌ copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.0.0 =&amp;gt; ❌ copy&lt;/td&gt;
&lt;td&gt;8.1 =&amp;gt; ❌ copy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Variation 2
&lt;/h3&gt;

&lt;p&gt;We don't name the variable and return temporary in both branches. Try it &lt;a href="https://godbolt.org/z/sb5G5vrPY" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&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="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;clang&lt;/th&gt;
&lt;th&gt;gcc&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20.1.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;15.1 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.0.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;8.1 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is in fact RVO, not NRVO. This behavior is guaranteed since C++17. However, adding &lt;code&gt;-std=c++17&lt;/code&gt; doesn't change the outputs in Compiler Explorer. It's very likely that every decent compiler use RVO in this case, even before C++17.&lt;/p&gt;

&lt;h3&gt;
  
  
  Variation 3
&lt;/h3&gt;

&lt;p&gt;This is the same as variation 1, except that the variable is not used locally, it's just returned. Try it &lt;a href="https://godbolt.org/z/bzd988GGo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&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="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;clang&lt;/th&gt;
&lt;th&gt;gcc&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20.1.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;15.1 =&amp;gt; ❌ copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.0.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;8.1 =&amp;gt; ❌ copy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Variation 4
&lt;/h3&gt;

&lt;p&gt;This is the same as variation 3, but &lt;code&gt;path&lt;/code&gt; is not &lt;code&gt;const&lt;/code&gt; . Try it &lt;a href="https://godbolt.org/z/T8KjrKrsW" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;build_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&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="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}/output/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;path&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;clang&lt;/th&gt;
&lt;th&gt;gcc&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20.1.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;15.1 =&amp;gt; ⚠️ move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.0.0 =&amp;gt; ✅ NRVO&lt;/td&gt;
&lt;td&gt;8.1 =&amp;gt; ⚠️ move&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;clang&lt;/code&gt; applies NRVO more aggressively and consistently than &lt;code&gt;gcc&lt;/code&gt;. Minor alterations of the code may prevent from applying NRVO, and we switch for an optimal situation to either a probably cheap move operation or a maybe-no-so-cheap copy operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Warning Is Not About NRVO
&lt;/h2&gt;

&lt;p&gt;Does &lt;code&gt;clang-tidy&lt;/code&gt; emit a warning for all variations? No:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variation&lt;/th&gt;
&lt;th&gt;Warning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Yes ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;No ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Yes ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;No ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Maybe I blurred the lines earlier, so let me clarify: the warning is &lt;strong&gt;not&lt;/strong&gt; about NRVO failing to apply. It's about the fact that a move operation is inhibited, and that a copy will be made instead. Hence its name: &lt;code&gt;performance-no-automatic-move&lt;/code&gt; 😉&lt;/p&gt;

&lt;p&gt;This is exactly what the previous table illustrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;clang-tidy&lt;/code&gt; emits a warning, &lt;code&gt;gcc&lt;/code&gt; performs a copy.&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;clang-tidy&lt;/code&gt; is silent, &lt;code&gt;gcc&lt;/code&gt; performs a move.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This behavior is consistent with what PVS-Studio explains:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The C++11 standard says that if a compiler cannot apply an optional optimization, it must do the following. First, it must apply the move constructor. Then apply the copy constructor for local variables or formal function parameters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;const&lt;/code&gt; objects cannot be moved. When a variable is declared &lt;code&gt;const&lt;/code&gt; and NRVO is not applied, moving it is impossible, so the compiler has no choice but to copy. That’s exactly what we observe in variation 3: &lt;code&gt;gcc&lt;/code&gt; uses the copy constructor because the object is &lt;code&gt;const&lt;/code&gt;, while it performs a &lt;code&gt;move&lt;/code&gt; in variation 4.&lt;/p&gt;

&lt;p&gt;(You might think that I am shaming &lt;code&gt;gcc&lt;/code&gt; here, but &lt;code&gt;clang&lt;/code&gt; was also doing a copy for variation 1 before version 15.0...)&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Handle The Warning
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;clang-tidy&lt;/code&gt; cannot possibly know whether NRVO will be applied or not, so it must assume it won't. If a move operation is impossible because of &lt;code&gt;const&lt;/code&gt; (as in variation 3), it emits a warning; otherwise, it remains silent (as in variation 4).&lt;/p&gt;

&lt;p&gt;Let's get back to our question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we blindly disable the warning by adding &lt;code&gt;-performance-no-automatic-move&lt;/code&gt; to our command-line or &lt;code&gt;.clang-tidy&lt;/code&gt; file?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is "no, we can't". If NRVO is actually performed, it's a false positive. Otherwise, it's not, and we may want to change our code to avoid a copy in favor of a move.&lt;/p&gt;

&lt;p&gt;In my opinion, there is no universal solution. It depends entirely on the context. Here are a few points to help decide: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the entire project does not have strong performance requirements, and we receive many warnings, we might disable it entirely.&lt;/li&gt;
&lt;li&gt;If the function is not performance-critical, we can just &lt;a href="https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics" rel="noopener noreferrer"&gt;suppress the warning locally&lt;/a&gt; by adding &lt;code&gt;// NOLINT(performance-no-automatic-move)&lt;/code&gt; on the same line as the &lt;code&gt;return&lt;/code&gt;. For example, I originally discovered this warning on a function that builds the output path of the application. This function is called once at startup, and the process then runs several minutes or hours. Copying a string was acceptable (NRVO was applied anyway).&lt;/li&gt;
&lt;li&gt;If we target specific compilers, we can manually analyze the code and/or experiment with Compiler Explorer to determine if NRVO is likely to be applied (as we did earlier in this post). If the answer is "yes", we can add &lt;code&gt;// NOLINT(performance-no-automatic-move)&lt;/code&gt; too.&lt;/li&gt;
&lt;li&gt;If this specific compiler is &lt;code&gt;gcc&lt;/code&gt; 14 or newer, we can enable the &lt;code&gt;-Wnrvo&lt;/code&gt; flag to help decide (see next section).&lt;/li&gt;
&lt;li&gt;If performance is important, and we target any compiler, we might prefer to remove &lt;code&gt;const&lt;/code&gt;. It's better to add a comment explaining why, otherwise someone will probably reintroduce &lt;code&gt;const&lt;/code&gt; afterwards. This is especially true for libraries, since we have no idea how people will use them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The great Bartłomiej Filipek from &lt;a href="https://www.cppstories.com/" rel="noopener noreferrer"&gt;C++ Stories&lt;/a&gt; wrote &lt;a href="https://www.cppstories.com/2017/01/const-move-and-rvo/" rel="noopener noreferrer"&gt;a post&lt;/a&gt; "Const, Move and RVO". I could not agree more with his last piece of advice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Still, if you’re unsure and you’re working with some larger objects (that have move enabled), it’s best to measure measure measure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Be Warned When NRVO Is Not Possible
&lt;/h2&gt;

&lt;p&gt;Released in &lt;a href="https://gcc.gnu.org/gcc-14/" rel="noopener noreferrer"&gt;May 2024&lt;/a&gt;, &lt;code&gt;gcc&lt;/code&gt; 14 &lt;a href="https://gcc.gnu.org/gcc-14/changes.html" rel="noopener noreferrer"&gt;introduced a new compiler flag&lt;/a&gt;: &lt;code&gt;-Wnrvo&lt;/code&gt;. From the &lt;a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wnrvo" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warn if the compiler does not elide the copy from a local variable to the return value of a function in a context where it is allowed by [class.copy.elision]. This elision is commonly known as the Named Return Value Optimization. For instance, in the example below the compiler cannot elide copies from both v1 and v2, so it elides neither.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jason Turner has dedicated &lt;a href="https://www.youtube.com/watch?v=PTCFddZfnXc" rel="noopener noreferrer"&gt;episode 434 of his C++Weekly series&lt;/a&gt; to this feature.&lt;/p&gt;

&lt;p&gt;Let's try recompiling every version of our code with this flag:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Warning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Original&lt;/td&gt;
&lt;td&gt;No ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variation1&lt;/td&gt;
&lt;td&gt;Yes ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variation2&lt;/td&gt;
&lt;td&gt;No ✅  =&amp;gt; this is not NRVO anyway, it is RVO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variation3&lt;/td&gt;
&lt;td&gt;Yes ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variation4&lt;/td&gt;
&lt;td&gt;Yes ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The compiler's output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;source&amp;gt;: In function 'Path build_path(const std::string&amp;amp;, int)':
&amp;lt;source&amp;gt;:33:24: warning: not eliding copy on return in 'Path build_path(const std::string&amp;amp;, int)' [-Wnrvo]
   33 |                 return path;
      |   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great to handle &lt;code&gt;clang-tidy&lt;/code&gt;'s warning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If both &lt;code&gt;gcc&lt;/code&gt; and &lt;code&gt;clang-tidy&lt;/code&gt; complains, we know we are paying for a copy instead of a move.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;gcc&lt;/code&gt; is silent but &lt;code&gt;clang-tidy&lt;/code&gt; complains, adding &lt;code&gt;// NOLINT(performance-no-automatic-move)&lt;/code&gt; is perfectly fine.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;gcc&lt;/code&gt; complains but &lt;code&gt;clang-tidy&lt;/code&gt; is silent, it probably means the type is not moveable. Since &lt;code&gt;performance-no-automatic-move&lt;/code&gt; is not applicable, &lt;code&gt;clang-tidy&lt;/code&gt; has nothing to report. But because NRVO is not applied, a copy will be made.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, as of June 2025, &lt;code&gt;clang&lt;/code&gt; does not offer an equivalent flag in any released version. However, the in-progress changelog for upcoming version (21.0.0) says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;New option -Wnrvo added and disabled by default to warn about missed NRVO opportunities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stay tuned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disabling (N)RVO with &lt;code&gt;-fno-elide-constructors&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you are curious, you can disable (N)RVO entirely.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcc&lt;/code&gt; and &lt;code&gt;clang&lt;/code&gt; provide a flag to prevent constructor elision when it is allowed (but not required) by the standard: &lt;code&gt;-fno-elide-constructors&lt;/code&gt;. According to &lt;code&gt;gcc&lt;/code&gt;'s &lt;a href="https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The C++ standard allows an implementation to omit creating a temporary that is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases. This option also causes G++ to call trivial member functions which otherwise would be expanded inline.&lt;/p&gt;

&lt;p&gt;In C++17, the compiler is required to omit these temporaries, but this option still affects trivial member functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s examine its effect on our original code, and a slightly modified version where &lt;code&gt;path&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; &lt;code&gt;const&lt;/code&gt;, for both C++14 and C++17.&lt;/p&gt;

&lt;h3&gt;
  
  
  C++14
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Original code:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Constructor called
Move constructor called
my/base/dir/output/0
Copy constructor called &amp;lt;-- There is a copy (just like `clang-tidy` warns)
Move constructor called
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Original code without the &lt;code&gt;const&lt;/code&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Constructor called
Move constructor called
my/base/dir/output/0
Move constructor called  &amp;lt;-- The copy is now a move
Move constructor called
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  C++17
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Original code:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Constructor called
my/base/dir/output/0
Copy constructor called &amp;lt;-- Same copy as before
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Original code without the &lt;code&gt;const&lt;/code&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Constructor called
my/base/dir/output/0
Move constructor called &amp;lt;-- Same move as before
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apart from educational purpose or curiosity, this flag can be useful is to experiment with "the worst case scenario" of a compiler that (almost) never performs constructor elision. See this &lt;a href="https://stackoverflow.com/questions/27086573/when-and-why-would-i-use-fno-elide-constructors" rel="noopener noreferrer"&gt;discussion on stackoverflow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Whew! You're still here! 😅 This article was a real challenge to write, and probably not the easiest to read either. Thanks &amp;amp; kudos for making it through.&lt;/p&gt;

&lt;p&gt;We’ve explored how NRVO behaves, how it’s affected by &lt;code&gt;const&lt;/code&gt;, and what &lt;code&gt;clang-tidy&lt;/code&gt;'s &lt;code&gt;performance-no-automatic-move]&lt;/code&gt; warning really means. Because NRVO (and RVO before C++17) is optional, small changes to a function can unexpectedly inhibit optimizations and introduce costly copies. This is also why having automated benchmarks in your CI is a good practice.&lt;/p&gt;

&lt;p&gt;The warning by &lt;code&gt;clang-tidy&lt;/code&gt; might be a false positive. Well, it's not really a false positive: actually, the code &lt;em&gt;does&lt;/em&gt; inhibit a move; it's just that the compiler might just invalidate the warning by applying NRVO. Depending on the situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The warning may be irrelevant in practice (because we can ensure that NRVO is reliably applied), and we can safely suppress it locally.&lt;/li&gt;
&lt;li&gt;We can decide that we don't want to change the code, that the performance penalty is acceptable, and we suppress it locally as well.&lt;/li&gt;
&lt;li&gt;We change the code to guarantee optimal performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this knowledge, you’re now better equipped to ensure your code behaves as expected and performs at its best. Happy optimized coding! 👋&lt;/p&gt;

</description>
      <category>cpp</category>
    </item>
    <item>
      <title>Manually Install WiFi Drivers on Linux</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Mon, 24 Mar 2025 11:19:41 +0000</pubDate>
      <link>https://dev.to/pgradot/manually-install-wifi-driver-on-linux-3lb4</link>
      <guid>https://dev.to/pgradot/manually-install-wifi-driver-on-linux-3lb4</guid>
      <description>&lt;p&gt;On December 24th, 2024, Debian had a gift for me: it installed Linux kernel 6.11.10, and suddenly the WiFi module of my laptop stopped working. I quickly found a workaround (selecting an older kernel with GRUB during boot) and hoped that the problem would be fixed by the next kernel update or by a firmware update from my laptop's manufacturer. Sadly, kernel 6.12 arrived and nothing changed. I finally took some time to really investigate the issue.&lt;/p&gt;

&lt;p&gt;In this article, I will explain how I diagnosed and fixed the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: I downloaded and manually installed drivers from &lt;a href="https://web.git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/" rel="noopener noreferrer"&gt;kernel.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Symptoms
&lt;/h2&gt;

&lt;p&gt;With kernel 6.11, the WiFi was simply absent from the GUI of Debian's settings. My laptop wasn't just unable to connect to the network, the WiFi was simply gone! With kernel 6.12, the entry was present in the GUI, but only to tell me that no network adapter was available.&lt;/p&gt;

&lt;p&gt;The time to open a terminal and investigate had come.&lt;/p&gt;

&lt;p&gt;Several commands can help determine the state of the WiFi adapter, such as &lt;code&gt;lshw -C network&lt;/code&gt; or &lt;code&gt;lspci&lt;/code&gt;. On my laptop, the latter showed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;lspci &lt;span class="nt"&gt;-k&lt;/span&gt;
...
00:14.3 Network controller: Intel Corporation Raptor Lake PCH CNVi WiFi &lt;span class="o"&gt;(&lt;/span&gt;rev 01&lt;span class="o"&gt;)&lt;/span&gt;
    Subsystem: Intel Corporation Raptor Lake PCH CNVi WiFi
    Kernel modules: iwlwifi
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-k&lt;/code&gt; option shows "kernel drivers handling each device and also kernel modules capable of handling it" according to the man pages. The network controller was detected, but something was clearly wrong: unlike other devices, there was no line saying "&lt;code&gt;Kernel driver in use: [name-of-the-driver]&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;The kernel's log provides detailed information about modules and drivers being loaded. By inspecting the log and searching for the module indicated by &lt;code&gt;lspci&lt;/code&gt;, I noticed that the module was indeed not properly loaded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dmesg | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; iwlwifi
&lt;span class="o"&gt;[&lt;/span&gt;  264.172078] iwlwifi 0000:00:14.3: Detected crf-id 0x400410, cnv-id 0x80400 wfpm &lt;span class="nb"&gt;id &lt;/span&gt;0x80000020
&lt;span class="o"&gt;[&lt;/span&gt;  264.172136] iwlwifi 0000:00:14.3: PCI dev 51f1/0090, &lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x370, &lt;span class="nv"&gt;rfid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x2010d000
&lt;span class="o"&gt;[&lt;/span&gt;  264.172137] iwlwifi 0000:00:14.3: Detected Intel&lt;span class="o"&gt;(&lt;/span&gt;R&lt;span class="o"&gt;)&lt;/span&gt; Wi-Fi 6E AX211 160MHz
&lt;span class="o"&gt;[&lt;/span&gt;  264.172742] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-89.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172747] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-89.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172748] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-89.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172754] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-88.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172757] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-88.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172758] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-88.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172761] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-87.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172764] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-87.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172765] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-87.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172769] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-86.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172771] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-86.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172772] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-86.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172775] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-85.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172778] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-85.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172779] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-85.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172782] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-84.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172785] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-84.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172786] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-84.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172789] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-83.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172792] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-83.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172792] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-83.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172796] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-82.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172799] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-82.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172800] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-82.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172803] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-81.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172806] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-81.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172807] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-81.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172810] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-80.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172813] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-80.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172814] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-80.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172817] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-79.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172820] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-79.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172821] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-79.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172825] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-78.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172827] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-78.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172828] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-78.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172832] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-77.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172834] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-so-a0-gf-a0-77.ucode &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172835] iwlwifi 0000:00:14.3: Direct firmware load &lt;span class="k"&gt;for &lt;/span&gt;iwlwifi-so-a0-gf-a0-77.ucode failed with error &lt;span class="nt"&gt;-2&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  264.172836] iwlwifi 0000:00:14.3: no suitable firmware found!
&lt;span class="o"&gt;[&lt;/span&gt;  264.172838] iwlwifi 0000:00:14.3: minimum version required: iwlwifi-so-a0-gf-a0-77
&lt;span class="o"&gt;[&lt;/span&gt;  264.172839] iwlwifi 0000:00:14.3: maximum version supported: iwlwifi-so-a0-gf-a0-89
&lt;span class="o"&gt;[&lt;/span&gt;  264.172839] iwlwifi 0000:00:14.3: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output also confirmed the model of the WiFi controller from the website of my laptop's manufacturer: it's an &lt;code&gt;Intel® Wi-Fi 6E AX211&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned before, the WiFi controller was still working fine with kernel 6.10. The same &lt;code&gt;dmesg&lt;/code&gt; command was showing similar errors, but the kernel was trying to load more modules. Eventually, it succeeded in loading version 72:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;   17.290059] iwlwifi 0000:00:14.3: loaded firmware version 72.daa05125.0 so-a0-gf-a0-72.ucode op_mode iwlmvm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.intel.com/content/www/us/en/products/sku/204837/intel-wifi-6e-ax211-gig/specifications.html" rel="noopener noreferrer"&gt;Intel's website&lt;/a&gt; states that this controller is supported by Linux. It even mentions that it is &lt;a href="https://www.intel.com/content/www/us/en/download/824804/intel-wireless-wi-fi-drivers-for-linux.html" rel="noopener noreferrer"&gt;supported by kernel 6.11+&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A discussion thread from &lt;a href="https://community.intel.com/t5/Wireless/AX211-160MHz-wifi-problem-on-proxmox-pve-debian/td-p/1562446" rel="noopener noreferrer"&gt;Intel's forum&lt;/a&gt; was helpful: you can manually download drivers from &lt;a href="https://web.git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/" rel="noopener noreferrer"&gt;kernel.org&lt;/a&gt; and install them by simply copying them to &lt;code&gt;/lib/firmware&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What was already installed on my laptop? I listed the files matching the pattern from &lt;code&gt;dmesg&lt;/code&gt; with &lt;code&gt;ll /lib/firmware/iwlwifi-so-a0-gf-*.ucode&lt;/code&gt; and found only one result: &lt;code&gt;/lib/firmware/iwlwifi-so-a0-gf-a0-72.ucode&lt;/code&gt;. The &lt;code&gt;dmesg&lt;/code&gt; output had mentioned that "&lt;code&gt;minimum version required: iwlwifi-so-a0-gf-a0-77&lt;/code&gt;" and "&lt;code&gt;maximum version supported: iwlwifi-so-a0-gf-a0-89&lt;/code&gt;". Conclusion: the driver was failing to load not because it was invalid, but simply because it was missing a version in the required range.&lt;/p&gt;

&lt;p&gt;I knew the files I needed, so I headed to &lt;a href="https://web.git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/" rel="noopener noreferrer"&gt;kernel.org&lt;/a&gt; and downloaded both versions &lt;a href="https://web.git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/intel/iwlwifi/iwlwifi-ty-a0-gf-a0-77.ucode" rel="noopener noreferrer"&gt;77&lt;/a&gt; and &lt;a href="https://web.git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/intel/iwlwifi/iwlwifi-ty-a0-gf-a0-89.ucode" rel="noopener noreferrer"&gt;89&lt;/a&gt;, which are the minimum required and maximum supported versions for the kernel I was trying to load. In reality, only version 89 would have been sufficient.&lt;/p&gt;

&lt;p&gt;I simply copied these files to &lt;code&gt;/lib/firmware&lt;/code&gt;, rebooted my computer, and... the WiFi was back! :)&lt;/p&gt;

&lt;p&gt;Now, &lt;code&gt;dmesg&lt;/code&gt; confirms that a driver is correctly loaded with &lt;code&gt;[  183.837486] iwlwifi 0000:00:14.3: loaded firmware version 89.1a492d28.0 so-a0-gf-a0-89.ucode op_mode iwlmvm&lt;/code&gt; and the output of &lt;code&gt;lspci&lt;/code&gt; shows that there a kernel driver in use (and yes, this is very significant difference):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;lspci &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; 14.3
00:14.3 Network controller: Intel Corporation Raptor Lake PCH CNVi WiFi &lt;span class="o"&gt;(&lt;/span&gt;rev 01&lt;span class="o"&gt;)&lt;/span&gt;
        Subsystem: Intel Corporation Raptor Lake PCH CNVi WiFi
        Kernel driver &lt;span class="k"&gt;in &lt;/span&gt;use: iwlwifi
        Kernel modules: iwlwifi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Sometimes, newer kernels don't come with the required drivers. In my case, it was the WiFi driver, but it can the driver for types of other devices.&lt;/p&gt;

&lt;p&gt;If you find yourself in a similar situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the exact model of your device.&lt;/li&gt;
&lt;li&gt;Check kernel logs to find error messages to determine what files are missing.&lt;/li&gt;
&lt;li&gt;Manually download and install the required driver.&lt;/li&gt;
&lt;li&gt;Reboot your machine and hope for the best.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS: there is a package named &lt;code&gt;firmware-iwlwifi&lt;/code&gt; in &lt;a href="https://packages.debian.org/bookworm/firmware-iwlwifi" rel="noopener noreferrer"&gt;Debian non-free repository&lt;/a&gt;. Installing should provide automatic updates for Intel WiFi firmware in the future. However, this package seems clearly outdated (which is not a big surprise, as Debian is sometimes slow to update its packages):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;firmware-iwlwifi
&lt;span class="o"&gt;[&lt;/span&gt;...]]
firmware-iwlwifi is already the newest version &lt;span class="o"&gt;(&lt;/span&gt;20230210-5&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
0 upgraded, 0 newly installed, 0 to remove and 86 not upgraded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh, by the way: &lt;code&gt;iwlwifi&lt;/code&gt; probably stands for "&lt;strong&gt;I&lt;/strong&gt;ntel &lt;strong&gt;W&lt;/strong&gt;ire*&lt;em&gt;L&lt;/em&gt;*ess WiFI".&lt;/p&gt;

</description>
      <category>linux</category>
      <category>debian</category>
      <category>driver</category>
      <category>wifi</category>
    </item>
    <item>
      <title>Resizing Partitions on Linux</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Thu, 29 Aug 2024 09:33:25 +0000</pubDate>
      <link>https://dev.to/pgradot/resizing-partitions-on-linux-408o</link>
      <guid>https://dev.to/pgradot/resizing-partitions-on-linux-408o</guid>
      <description>&lt;p&gt;Sometimes, you need to resize your partitions on Linux. And this may not be as easy as you think...&lt;/p&gt;

&lt;p&gt;When I installed Debian on my work computer a few months ago, the wizard suggested creating 2 separate partitions: one for root (with the OS itself), another for home (with my personal data). Alas! The suggested sizes (that I naively accepted) were highly unsuitable and a month later, the root partition (only 40 Go) was full. I had to resize them. It turns out that now, 5 months later, the home is full (I really generate a lot of data for my current project). It's time to resize my partitions again but this time I will keep track of the entire procedure in this article. Who knows when I will have to resize them one more time...&lt;/p&gt;

&lt;h2&gt;
  
  
  Current State and Goal
&lt;/h2&gt;

&lt;p&gt;My computer as a single encrypted SSD disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % lsblk
NAME                    MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
nvme0n1                 259:0    0  3.6T  0 disk 
├─nvme0n1p1             259:1    0  512M  0 part  /boot/efi
├─nvme0n1p2             259:2    0  488M  0 part  /boot
└─nvme0n1p3             259:3    0  3.6T  0 part 
  └─nvme0n1p3_crypt     253:0    0  3.6T  0 crypt 
    ├─debian--vg-root   253:1    0  2.6T  0 lvm   /
    ├─debian--vg-swap_1 253:2    0  976M  0 lvm   &lt;span class="o"&gt;[&lt;/span&gt;SWAP]
    └─debian--vg-home   253:3    0    1T  0 lvm   /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fdisk -l&lt;/code&gt; shows similar information.&lt;/p&gt;

&lt;p&gt;As I said, my home partition is full. However, the root partition is almost empty:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;debian
Filesystem                   Size  Used Avail Use% Mounted on
/dev/mapper/debian--vg-root  2.6T  202G  2.3T   8% /
/dev/mapper/debian--vg-home 1007G  937G   19G  99% /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My goal is to resize the partitions so that root is 1T and home occupies the rest of the disk. This will be a 2-step process: first, shrink root ; second, extend home.&lt;/p&gt;

&lt;p&gt;Apparently, I can't do this from the graphical disk utility (note "Edit Partition..." and "Resize..." being greyed out):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftk0l6fd444wgishg16ky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftk0l6fd444wgishg16ky.png" alt="disk utility" width="740" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's time to open a terminal and input some weird commands!&lt;/p&gt;

&lt;h2&gt;
  
  
  Shrinking Root
&lt;/h2&gt;

&lt;p&gt;Because I want to resize the root partition, it seems that &lt;a href="https://www.casesup.com/category/knowledgebase/howtos/how-to-shrink-an-lvm-volume-safely-on-linux" rel="noopener noreferrer"&gt;I can't directly work&lt;/a&gt; from my installed Debian. I put my hands back on my bootable USB drive (the one I used to install Debian in the first place) and I reboot my computer on it. It doesn't provide a live Debian mode, so I have to use the rescue mode to get a shell:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsdikikr46ubmdx2e1gq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsdikikr46ubmdx2e1gq.jpg" alt="advanced option" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygfj0iixr94rrvhsc3mm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygfj0iixr94rrvhsc3mm.jpg" alt="rescue mode" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, I took pictures on my laptop's screen.&lt;/p&gt;

&lt;p&gt;Once I have configured my language and keyboard layout, and skipped the network configuration, I can finally enter the rescue mode for real:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6vqywyd2r91e8252dqk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6vqywyd2r91e8252dqk.jpg" alt="rescue mode again" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have to enter my passphrase because my disk is encrypted, and I now have a shell. Hooray!&lt;/p&gt;

&lt;p&gt;Resizing a "partition" is not a single-step operation. Indeed, there are in fact a logical volume and a filesystem on top of it. Both need to be resized in the correct order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, reduce the filesystem&lt;/strong&gt; with &lt;a href="https://linux.die.net/man/8/resize2fs" rel="noopener noreferrer"&gt;the &lt;code&gt;resize2fs&lt;/code&gt; command&lt;/a&gt;. In this first step, I use a temporary size, not the desired size. It must be big enough to hold all the files but smaller that the desired size. The output &lt;code&gt;df -h&lt;/code&gt; above shows that 202G are used on root. The desired size is 1T. Hence, 300G seems fine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resize2fs /dev/mapper/debian--vg-root 300G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am asked to &lt;a href="https://linux.die.net/man/8/e2fsck" rel="noopener noreferrer"&gt;check the filesystem&lt;/a&gt; first with &lt;code&gt;e2fsck -f /dev/mapper/debian--vg-home&lt;/code&gt;. Once the check and possible fixes are done, I can call &lt;code&gt;resize2fs&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second, reduce the volume&lt;/strong&gt; to the desired size (1T) with &lt;a href="https://linux.die.net/man/8/lvreduce" rel="noopener noreferrer"&gt;the &lt;code&gt;lvreduce&lt;/code&gt; command&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lvreduce &lt;span class="nt"&gt;-L&lt;/span&gt; 1T /dev/vgroot/lvroot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Third (and last), extend the filesystem&lt;/strong&gt; to use the entire volume. This is done by passing only the volume to &lt;code&gt;resize2fs&lt;/code&gt; because if the "size parameter is not specified, it will default to the size of the partition".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resize2fs /dev/vgroot/lvroot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how it looks like in real life:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu2x7t8d6a307un4ryrr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu2x7t8d6a307un4ryrr.jpg" alt="commands in shell" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that step 3 may be performed directly in step 2, because &lt;code&gt;lvreduce&lt;/code&gt; has an option that seems to do it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;-r&lt;/code&gt;, &lt;code&gt;--resizefs&lt;/code&gt;&lt;br&gt;
   Resize underlying filesystem together with the logical volume using &lt;code&gt;fsadm&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be honest, I wasn't really keen to try on my work computer, I can't afford any data loss. So I stuck a procedure that I knew to work, but I encourage you to test it 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking Root
&lt;/h2&gt;

&lt;p&gt;Now, I shut down my computer, I remove the USB drive, I reboot to my actual system, and I'm glad to see that it still works 😄&lt;/p&gt;

&lt;p&gt;I can check the state of my disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;mapper
/dev/mapper/debian--vg-root 1008G  202G  756G  22% /
/dev/mapper/debian--vg-home 1007G  937G   19G  99% /home

 % lsblk
NAME                    MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
nvme0n1                 259:0    0  3.6T  0 disk  
├─nvme0n1p1             259:1    0  512M  0 part  /boot/efi
├─nvme0n1p2             259:2    0  488M  0 part  /boot
└─nvme0n1p3             259:3    0  3.6T  0 part  
  └─nvme0n1p3_crypt     253:0    0  3.6T  0 crypt 
    ├─debian--vg-root   253:1    0    1T  0 lvm   /
    ├─debian--vg-swap_1 253:2    0  976M  0 lvm   &lt;span class="o"&gt;[&lt;/span&gt;SWAP]
    └─debian--vg-home   253:3    0    1T  0 lvm   /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root partition is fine. Of course, the home partition is unchanged. Let's resize it now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending Home
&lt;/h2&gt;

&lt;p&gt;This time, I don't need to boot on my USB drive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, extend the volume with &lt;a href="https://linux.die.net/man/8/lvextend" rel="noopener noreferrer"&gt;the &lt;code&gt;lvextend&lt;/code&gt; command&lt;/a&gt;. I don't have to calculate the remaining size, I just ask to &lt;a href="https://unix.stackexchange.com/questions/691627/how-can-i-extend-logical-volume-to-100" rel="noopener noreferrer"&gt;add 100% of the free space&lt;/a&gt; of the disk to the volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;sudo &lt;/span&gt;lvextend &lt;span class="nt"&gt;-l&lt;/span&gt; +100%FREE /dev/mapper/debian--vg-home      
  Size of logical volume debian-vg/home changed from 1.00 TiB &lt;span class="o"&gt;(&lt;/span&gt;262144 extents&lt;span class="o"&gt;)&lt;/span&gt; to &amp;lt;2.64 TiB &lt;span class="o"&gt;(&lt;/span&gt;691219 extents&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
  Logical volume debian-vg/home successfully resized.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the option is &lt;code&gt;-l&lt;/code&gt; (lowercase) not &lt;code&gt;-L&lt;/code&gt; (uppercase), unlike with &lt;code&gt;lvreduce&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second (and last), resize the filesystem&lt;/strong&gt; to use the entire volume (same as last operation for root):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;sudo &lt;/span&gt;resize2fs /dev/mapper/debian--vg-home
resize2fs 1.47.0 &lt;span class="o"&gt;(&lt;/span&gt;5-Feb-2023&lt;span class="o"&gt;)&lt;/span&gt;
Filesystem at /dev/mapper/debian--vg-home is mounted on /home&lt;span class="p"&gt;;&lt;/span&gt; on-line resizing required
old_desc_blocks &lt;span class="o"&gt;=&lt;/span&gt; 128, new_desc_blocks &lt;span class="o"&gt;=&lt;/span&gt; 338
The filesystem on /dev/mapper/debian--vg-home is now 707808256 &lt;span class="o"&gt;(&lt;/span&gt;4k&lt;span class="o"&gt;)&lt;/span&gt; blocks long.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Checking Home
&lt;/h2&gt;

&lt;p&gt;Finally, I have reached my goal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;mapper                       
/dev/mapper/debian--vg-root 1008G  202G  756G  22% /
/dev/mapper/debian--vg-home  2.6T  937G  1.6T  37% /home

 % lsblk                                           
NAME                    MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
nvme0n1                 259:0    0  3.6T  0 disk  
├─nvme0n1p1             259:1    0  512M  0 part  /boot/efi
├─nvme0n1p2             259:2    0  488M  0 part  /boot
└─nvme0n1p3             259:3    0  3.6T  0 part  
  └─nvme0n1p3_crypt     253:0    0  3.6T  0 crypt 
    ├─debian--vg-root   253:1    0    1T  0 lvm   /
    ├─debian--vg-swap_1 253:2    0  976M  0 lvm   &lt;span class="o"&gt;[&lt;/span&gt;SWAP]
    └─debian--vg-home   253:3    0  2.6T  0 lvm   /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I have to be honest, it was quite scary to resize partitions 😱 Of course, I backed up my important data, but I can't really back up a full system with all the installed tools and settings I have as a software developer on my machine.&lt;/p&gt;

&lt;p&gt;At the end of the day, I left this uncomfortable situation:&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;mapper       
Filesystem                   Size  Used Avail Use% Mounted on
/dev/mapper/debian--vg-root  2.6T  202G  2.3T   8% /
/dev/mapper/debian--vg-home 1007G  937G   19G  99% /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I have reached with much more cozy one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; % &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;mapper                       
/dev/mapper/debian--vg-root 1008G  202G  756G  22% /
/dev/mapper/debian--vg-home  2.6T  937G  1.6T  37% /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this was the last time I had to resize my partitions on this computer! 😁&lt;/p&gt;

</description>
      <category>linux</category>
      <category>todayisearched</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>CMake on SMT32 | Episode 8: build with Docker</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Mon, 18 Mar 2024 10:57:35 +0000</pubDate>
      <link>https://dev.to/pgradot/cmake-on-smt32-episode-8-build-with-docker-16jm</link>
      <guid>https://dev.to/pgradot/cmake-on-smt32-episode-8-build-with-docker-16jm</guid>
      <description>&lt;p&gt;In this episode, we will use Docker to set up and manage our build environment.&lt;/p&gt;

&lt;p&gt;The embedded world doesn't always embrace the latest software development techniques. I acknowledged this in the previous &lt;a href="https://dev.to/pgradot/cmake-on-smt32-episode-7-unit-tests-13gj"&gt;episode about unit tests&lt;/a&gt;. Four years ago, when I started this series, I was totally unaware of Docker for instance. Since then, I have used it for non-embedded projects and I think it could have solved some issues I encountered in the past. I would like to share my experience and demonstrate that it can perfectly fit in an MCU project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In fact, every I will say here applies to hosted C / C++ projects too!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Dependencies to build our project
&lt;/h2&gt;

&lt;p&gt;Let's take a moment to look back and review all the tools required on our machine to build the project presented in this series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cmake&lt;/code&gt;: obviously, this is the quintessence of this series.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;make&lt;/code&gt;: in the first episode, we chose to use &lt;code&gt;-G "MinGW Makefiles"&lt;/code&gt; as our generator. We may have chosen another generator, for instance &lt;code&gt;-G Ninja&lt;/code&gt;, and have another dependency (&lt;code&gt;ninja&lt;/code&gt;, namely).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;arm-none-eabi-gcc&lt;/code&gt;: this is the toolchain to compile our embedded code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gcc&lt;/code&gt;: we need another toolchain for the unit tests to run on the host computer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git&lt;/code&gt;: CMake's &lt;code&gt;FetchContent&lt;/code&gt; module needs Git to fetch Catch2 from GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list may seem relatively small for the moment, but for sure it will grow in the future. We will probably want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write scripts with &lt;code&gt;python&lt;/code&gt; and need &lt;code&gt;pip&lt;/code&gt; to install packages.&lt;/li&gt;
&lt;li&gt;debug the units tests with &lt;code&gt;gdb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;analyze our code with &lt;code&gt;clang-tidy&lt;/code&gt; and format it with &lt;code&gt;clang-format&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each developer on the project needs to install everything on their machine. Each time the team decides to upgrade a tool to a newer version or to use a new tool, everyone must update their setup. Not to mention the CI environment (if you have maintained a Jenkins machine once in your life, you know what I mean).&lt;/p&gt;

&lt;p&gt;Should I say that everyone may have a different version of everything on their machine? Things could turn into a nightmare.&lt;/p&gt;

&lt;p&gt;This is where Docker comes into play to help tackle this complexity. The purpose is to create a Docker image with everything the team needs to work. Instead of having to install many applications, we just need Docker (and obviously a VCS client, probably Git, to clone the central repository).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is not meant to be a crash course to Docker. If you don't have the basic knowledge, you should probably read a tutorial. This may be optional though, as you will probably get the concepts and the process I will describe anyway.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Dockerfile
&lt;/h2&gt;

&lt;p&gt;We create a &lt;code&gt;Dockerfile&lt;/code&gt; (yes, that the name of the file) next to our &lt;code&gt;CMakeLists.txt&lt;/code&gt;, at the root of our project. We use the latest image of Ubuntu as the base image, and we install the packages we need. Here is the content of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:latest&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;                        build-essential &lt;span class="se"&gt;\
&lt;/span&gt;                        cmake &lt;span class="se"&gt;\
&lt;/span&gt;                        gcc-arm-none-eabi &lt;span class="se"&gt;\
&lt;/span&gt;                        gdb &lt;span class="se"&gt;\
&lt;/span&gt;                        git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://packages.ubuntu.com/jammy/build-essential" rel="noopener noreferrer"&gt;&lt;code&gt;build-essential&lt;/code&gt; package&lt;/a&gt; includes &lt;code&gt;gcc&lt;/code&gt; and &lt;code&gt;make&lt;/code&gt;. Note that I have included &lt;code&gt;gdb&lt;/code&gt;, which isn't yet mandatory, but CLion asks for it (and we will see that this Docker image can be used seamlessly within CLion).&lt;/p&gt;

&lt;p&gt;And... that's it! We have everything we need! We will see later how we can improve this file by using explicit versions. For the moment, let's try to build our firmware and our unit tests!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the Docker image
&lt;/h2&gt;

&lt;p&gt;This &lt;code&gt;Dockerfile&lt;/code&gt; describes our image, and we have to build it now. We just need to execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; cmake-on-stm32 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-t&lt;/code&gt; is short for &lt;code&gt;--tag&lt;/code&gt;. It gives the image a name (in fact, &lt;a href="https://docs.docker.com/engine/reference/commandline/image_build/#tag" rel="noopener noreferrer"&gt;a tag&lt;/a&gt;), and this will make our life easier in the next commands.&lt;/p&gt;

&lt;p&gt;If &lt;a href="https://docs.docker.com/engine/reference/commandline/image_ls/" rel="noopener noreferrer"&gt;we list the images&lt;/a&gt;, we see our image and its base image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker images
REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
cmake-on-stm32    latest    1ed7f1257600   48 minutes ago   3.12GB
ubuntu            latest    e34e831650c1   5 weeks ago      77.9MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image can now be used to run containers, which are the actual runners for this Dockerized build environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the container from the terminal
&lt;/h2&gt;

&lt;p&gt;We have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get a shell inside the container and work inside the container.&lt;/li&gt;
&lt;li&gt;Ask the container to run commands and work from the host.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Get a shell inside the container
&lt;/h3&gt;

&lt;p&gt;For the first option, we just have to run the following command to get a shell inside the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/:/nucleo/ &lt;span class="nt"&gt;-w&lt;/span&gt; /nucleo/ cmake-on-stm32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; requires Docker to &lt;a href="https://docs.docker.com/engine/reference/commandline/container_run/#rm" rel="noopener noreferrer"&gt;remove the container&lt;/a&gt; when it exits.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-it&lt;/code&gt; is short for &lt;code&gt;--interactive&lt;/code&gt; + &lt;code&gt;--tty&lt;/code&gt;. This is the option that takes us straight inside the container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v&lt;/code&gt; to &lt;a href="https://docs.docker.com/engine/reference/commandline/container_run/#volume" rel="noopener noreferrer"&gt;mount the current directory&lt;/a&gt; as &lt;code&gt;/nucleo/&lt;/code&gt; in the container. Indeed, the container is isolated from the host. If we want to share directories between the host and the container, volumes are the way to go.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w&lt;/code&gt; is optional, it just sets the &lt;a href="https://docs.docker.com/engine/reference/commandline/container_run/#workdir" rel="noopener noreferrer"&gt;working directory&lt;/a&gt; so that the shell starts in a handy location.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NOTE: if you always use the same working directory, you can set it directly in the &lt;code&gt;Dockerfile&lt;/code&gt; with the &lt;code&gt;WORKDIR&lt;/code&gt; &lt;a href="https://docs.docker.com/reference/dockerfile/#workdir" rel="noopener noreferrer"&gt;instruction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To demonstrate the usage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3padekesov8g3dwmig98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3padekesov8g3dwmig98.png" alt="prompts" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how the prompt changes and how the &lt;code&gt;arm-none-eabi-gcc&lt;/code&gt; is found or not. &lt;code&gt;exit&lt;/code&gt; exits the shell and hence the container.&lt;/p&gt;

&lt;p&gt;Now, we can just follow the process that has been described throughout this series: generate the project, build the firmware, build the tests, run the tests, etc. The commands are the same, we just execute them inside the container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Execute commands from the host
&lt;/h3&gt;

&lt;p&gt;We can remove the &lt;code&gt;-it&lt;/code&gt; option and add more arguments to the command. The container will execute them. Here is an example with &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;arm-none-eabi-gcc --version&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb49sg9z5cq600d7vjq3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb49sg9z5cq600d7vjq3.png" alt="commands from host" width="800" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tend to prefer the first technique, because the commands can get very long with this second technique. Furthermore, the host can't auto-complete the commands because it doesn't know what the container supports. Nevertheless, I guess in some cases, mixing both techniques can be interesting. It's up to you to define how you want to interact with the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplify the command-line with Docker Compose
&lt;/h2&gt;

&lt;p&gt;The above commands may seem a bit "heavy", mostly because of the options to mount the volume and to set the working directory. It's likely that more options will be added, making the commands even longer.&lt;/p&gt;

&lt;p&gt;We can take advantage of &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; to simplify things a little. &lt;code&gt;compose&lt;/code&gt; is a subcommand of &lt;code&gt;docker&lt;/code&gt;, there is no new software to install on the host machine. We can write a &lt;a href="https://docs.docker.com/compose/compose-file/" rel="noopener noreferrer"&gt;simple &lt;code&gt;docker-compose.yml&lt;/code&gt; file&lt;/a&gt; to describe what we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cmake-on-stm32&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/nucleo/&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/nucleo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use &lt;a href="https://docs.docker.com/reference/cli/docker/compose/run/" rel="noopener noreferrer"&gt;the &lt;code&gt;docker compose run&lt;/code&gt; command&lt;/a&gt; (instead of just &lt;code&gt;docker run&lt;/code&gt;) and omit the options that are described in &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3guqos541622kfhxdjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3guqos541622kfhxdjl.png" alt="docker compose run" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;a href="https://stackoverflow.com/a/36265910" rel="noopener noreferrer"&gt;the &lt;code&gt;-it&lt;/code&gt; option is not required to use the container interactively&lt;/a&gt; with &lt;code&gt;docker compose&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the container from CLion
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/pgradot/cmake-on-stm32-episode-2-build-with-clion-2lae"&gt;episode 2&lt;/a&gt;, we learned how to build our CMake project for STM32 with &lt;a href="https://www.jetbrains.com/clion/" rel="noopener noreferrer"&gt;CLion by Jetbrains&lt;/a&gt;. I have good news: CLion supports &lt;a href="https://www.jetbrains.com/help/clion/clion-toolchains-in-docker.html" rel="noopener noreferrer"&gt;Docker toolchains&lt;/a&gt; out-of-the-box! I tried and it worked perfectly in minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I added a new Docker toolchain that uses &lt;code&gt;cmake-on-stm32:latest&lt;/code&gt; as its image.&lt;/li&gt;
&lt;li&gt;I created 2 profiles to build the project:

&lt;ol&gt;
&lt;li&gt;For the units tests: I used all default values except for the toolchain where I selected my Docker toolchain.&lt;/li&gt;
&lt;li&gt;For the embedded code: same except that I added &lt;code&gt;-DCMAKE_TOOLCHAIN_FILE=arm-none-eabi-gcc.cmake&lt;/code&gt; in the &lt;code&gt;CMake options&lt;/code&gt; field.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And voilà! We can then work within CLion without noticing that Docker is involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve user management
&lt;/h2&gt;

&lt;p&gt;There is a little catch with the commands above: inside the container, the user is &lt;code&gt;root&lt;/code&gt;. Consequence: all files and directories created from the container are owned by &lt;code&gt;root&lt;/code&gt;. For instance when building in &lt;code&gt;build-docker&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwdbsyxz5oij3am6zzvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuwdbsyxz5oij3am6zzvh.png" alt="files listing with root as owners" width="554" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of the time, this is not a real issue, except when we want to &lt;a href="https://dille.name/blog/2018/07/16/handling-file-permissions-when-writing-to-volumes-from-docker-containers/" rel="noopener noreferrer"&gt;delete them&lt;/a&gt; because we don't have the appropriate permissions. On Linux, it means we will need &lt;code&gt;sudo&lt;/code&gt; to perform the deletion.&lt;/p&gt;

&lt;p&gt;To get around this issue, we can add the &lt;code&gt;--user&lt;/code&gt; option to specify the user and group we want when calling &lt;code&gt;docker run&lt;/code&gt;. For instance on Linux, &lt;code&gt;--user $(id -u):$(id -g)&lt;/code&gt; will use our user and group. We will then be the owner of the generated files and directories:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvuvbmvon45hrij0bx5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvuvbmvon45hrij0bx5g.png" alt="files listing with pierre as owner" width="560" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user and group can also be set in Docker Compose. Read &lt;a href="https://blog.giovannidemizio.eu/2021/05/24/how-to-set-user-and-group-in-docker-compose/" rel="noopener noreferrer"&gt;"How to set user and group in Docker Compose" by Giovanni De Mizio&lt;/a&gt; to learn how to do this.&lt;/p&gt;

&lt;p&gt;Note that CLion does this in background, so the ownership of the files is correct without any further options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin versions of dependencies
&lt;/h2&gt;

&lt;p&gt;In our &lt;code&gt;Dockerfile&lt;/code&gt;, we have simply chosen the latest Ubuntu version as the base image (with &lt;code&gt;FROM ubuntu:latest&lt;/code&gt;) and have blissfully installed the packages. This is cool when testing things but there is one major drawback: we have absolutely no idea what versions of the tools we will get!&lt;/p&gt;

&lt;h3&gt;
  
  
  Pin the base image
&lt;/h3&gt;

&lt;p&gt;As of February 29th 2024 (as I'm writing these lines), &lt;a href="https://hub.docker.com/_/ubuntu" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt; says that the &lt;code&gt;ubuntu:latest&lt;/code&gt; is &lt;a href="https://releases.ubuntu.com/jammy/" rel="noopener noreferrer"&gt;Jammy Jellyfish&lt;/a&gt; (aka 22.04, the current LTS). In April 2024 Noble Numbat (aka 24.04, the next LTS release) will be out and will probably become the new &lt;code&gt;latest&lt;/code&gt; version. It will come (almost for sure) with new versions of the tools. Who knows if our code will still compile under Noble Numbat? We really don't want our project to suddenly stop building because a new release of Ubuntu is out.&lt;/p&gt;

&lt;p&gt;The obvious first counter-measure is to choose a version of Ubuntu explicitly. We just have to replace &lt;code&gt;ubuntu:latest&lt;/code&gt; with &lt;code&gt;ubuntu:jammy&lt;/code&gt; or any other version. Pinning the base image will also (normally) pin the versions of the tools because each release of Ubuntu is quite conservative about the versions of the programs in the packages (Debian is even more). &lt;a href="https://packages.ubuntu.com/" rel="noopener noreferrer"&gt;Ubuntu Packages Search&lt;/a&gt; website tells us the content of the packages we can install with &lt;code&gt;apt-get&lt;/code&gt;. Thanks to this knowledge, we can decide which Ubuntu version is good for us, if we want to upgrade to the next version or not, etc. For instance with &lt;code&gt;gcc&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ubuntu&lt;/th&gt;
&lt;th&gt;&lt;code&gt;gcc&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;gcc-arm-none-eabi&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Jammy Jellyfish&lt;/td&gt;
&lt;td&gt;&lt;a href="https://packages.ubuntu.com/jammy/gcc" rel="noopener noreferrer"&gt;11.2&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://packages.ubuntu.com/jammy/gcc-arm-none-eabi" rel="noopener noreferrer"&gt;10.3&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lunar Lobster&lt;/td&gt;
&lt;td&gt;&lt;a href="https://packages.ubuntu.com/lunar/gcc" rel="noopener noreferrer"&gt;12.2&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://packages.ubuntu.com/lunar/gcc-arm-none-eabi" rel="noopener noreferrer"&gt;12.2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mantic Minotaur&lt;/td&gt;
&lt;td&gt;&lt;a href="https://packages.ubuntu.com/mantic/gcc" rel="noopener noreferrer"&gt;13.2&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://packages.ubuntu.com/mantic/gcc-arm-none-eabi" rel="noopener noreferrer"&gt;12.2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Select more specific packages
&lt;/h3&gt;

&lt;p&gt;On Mantic Minotaur (23.10, the latest version of Ubuntu as I write these lines), the &lt;code&gt;gcc-arm-none-eabi&lt;/code&gt; package installs GCC 12.2 (for ARM), while the &lt;code&gt;gcc&lt;/code&gt; package installs GCC 13.2 (for x86-64). We would like our hosted and embedded toolchains to use the same version GCC (at least the same major version). There is a solution: the &lt;a href="https://packages.ubuntu.com/mantic/gcc-12" rel="noopener noreferrer"&gt;&lt;code&gt;gcc-12&lt;/code&gt; packages&lt;/a&gt; installs GCC 12.3. That is a better match with the embedded toolchain. Note that there are packages for &lt;a href="https://packages.ubuntu.com/mantic/gcc-9" rel="noopener noreferrer"&gt;gcc-9&lt;/a&gt; up to &lt;a href="https://packages.ubuntu.com/mantic/gcc-13" rel="noopener noreferrer"&gt;gcc-13&lt;/a&gt; on Mantic Minotaur.&lt;/p&gt;

&lt;p&gt;A better &lt;code&gt;Dockerfile&lt;/code&gt; would probably be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:mantic&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;                        make &lt;span class="se"&gt;\
&lt;/span&gt;                        cmake &lt;span class="se"&gt;\
&lt;/span&gt;                        gcc-12 &lt;span class="se"&gt;\
&lt;/span&gt;                        gcc-arm-none-eabi &lt;span class="se"&gt;\
&lt;/span&gt;                        gdb &lt;span class="se"&gt;\
&lt;/span&gt;                        git

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; gcc-12 /usr/bin/gcc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I should probably explain the link creation. The &lt;a href="https://packages.ubuntu.com/mantic/cmake" rel="noopener noreferrer"&gt;&lt;code&gt;cmake&lt;/code&gt; package&lt;/a&gt; has &lt;code&gt;gcc&lt;/code&gt; in its list of recommended packages. Because we haven't used the option &lt;code&gt;--no-install-recommends&lt;/code&gt;, it will install GCC 13 and create a link &lt;code&gt;/usr/bin/gcc&lt;/code&gt; that points to &lt;code&gt;/usr/bin/gcc-13&lt;/code&gt; (which is itself a link). The last line of the &lt;code&gt;Dockerfile&lt;/code&gt; is here to overwrite this link. Oh! by the way: the &lt;code&gt;gcc-12&lt;/code&gt; package won't create the link anyway, so we really need this line. &lt;/p&gt;

&lt;h3&gt;
  
  
  Select exact versions of the packages
&lt;/h3&gt;

&lt;p&gt;As I said, each release of Ubuntu is quite conservative. It's very unlikely that the version of GCC in the &lt;code&gt;gcc-arm-none-eabi&lt;/code&gt; in the repositories will change. Unlikely doesn't mean impossible (it could be a patch version). In case &lt;a href="https://askubuntu.com/questions/92019/how-to-install-specific-ubuntu-deb-packages-with-exact-version" rel="noopener noreferrer"&gt;we &lt;em&gt;really&lt;/em&gt; want to be sure to stick to an exact version&lt;/a&gt;, we can add the version of the package in the &lt;code&gt;apt-get&lt;/code&gt; command and use &lt;code&gt;gcc-arm-none-eabi=15:12.2.rel1-1&lt;/code&gt; instead of just &lt;code&gt;gcc-arm-none-eabi&lt;/code&gt; (with Mantic Minotaur). The version string can be found in the title of &lt;a href="https://packages.ubuntu.com/mantic/gcc-arm-none-eabi" rel="noopener noreferrer"&gt;package's page&lt;/a&gt; for each release of Ubuntu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual installations
&lt;/h2&gt;

&lt;p&gt;It's possible that the Ubuntu packages won't provide with the versions we want. We can them fallback to manual installations. Let's say to we want the latest release of CMake (which is &lt;a href="https://github.com/Kitware/CMake/releases/tag/v3.29.0-rc2" rel="noopener noreferrer"&gt;3.29.0-rc2&lt;/a&gt; at the moment), we can script the installation from GitHub in the &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is our new &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:mantic&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;                        make &lt;span class="se"&gt;\
&lt;/span&gt;                        gcc-12 &lt;span class="se"&gt;\
&lt;/span&gt;                        gcc-arm-none-eabi&lt;span class="o"&gt;=&lt;/span&gt;15:12.2.rel1-1 &lt;span class="se"&gt;\
&lt;/span&gt;                        gdb &lt;span class="se"&gt;\
&lt;/span&gt;                        git &lt;span class="se"&gt;\
&lt;/span&gt;                        wget

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; gcc-12 /usr/bin/gcc

&lt;span class="k"&gt;RUN &lt;/span&gt;wget https://github.com/Kitware/CMake/releases/download/v3.29.0-rc2/cmake-3.29.0-rc2-linux-x86_64.sh
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;u+x cmake-3.29.0-rc2-linux-x86_64.sh
&lt;span class="k"&gt;RUN &lt;/span&gt;./cmake-3.29.0-rc2-linux-x86_64.sh &lt;span class="nt"&gt;--skip-license&lt;/span&gt; &lt;span class="nt"&gt;--include-subdir&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH="${PATH}:/cmake-3.29.0-rc2-linux-x86_64/bin"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We update the &lt;code&gt;PATH&lt;/code&gt; &lt;a href="https://stackoverflow.com/questions/27093612/in-a-dockerfile-how-to-update-path-environment-variable" rel="noopener noreferrer"&gt;environment variable&lt;/a&gt; so that &lt;code&gt;cmake&lt;/code&gt; (and its associated binaries, such as &lt;code&gt;ctest&lt;/code&gt;) is available from the path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assessing our solution
&lt;/h2&gt;

&lt;p&gt;In my opinion, this Docker-centered approach has a lot of benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's much easier to set our computer when we join a new project. Install Git (and SVN or whatever we need), install Docker, clone the repository, and we're good to build!&lt;/li&gt;
&lt;li&gt;Everyone in the team has the same environment (including Jenkins or whatever CI service we use), assuming that everyone rebuilds the Docker image regularly.&lt;/li&gt;
&lt;li&gt;It is very easy to try a new version of a compiler (or any other tool) without smashing our current environment. We create new branch in our VCS, we update the &lt;code&gt;Dockerfile&lt;/code&gt; to fetch the new compiler and we can work. We can then seamlessly switch back to our original branch and have our "normal" compiler back.&lt;/li&gt;
&lt;li&gt;On the same computer, we can work on several projects that use different versions of the same tool, without conflicts (eg: project A uses GCC 12 while project B uses GCC 13) thanks to the isolation that Docker offers.&lt;/li&gt;
&lt;li&gt;It's easier to rebuild old versions of the project. When we check out an old commit, we can rebuild a Docker image to get the tools that the project required back then, and then rebuild the project with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, there is no magic in real life and every solution comes with some downsides: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We now have yet another tool in our environment. We have to learn it, we will run into Docker-specific issues, we have to maintain Docker code.&lt;/li&gt;
&lt;li&gt;It may be difficult to integrate some tools in the image if their installations aren't scriptable.&lt;/li&gt;
&lt;li&gt;We can't force people to regularly rebuild their local Docker image, so there may still be inconsistency among the team's machines.&lt;/li&gt;
&lt;li&gt;We never know if our &lt;code&gt;docker build&lt;/code&gt; command will work tomorrow. We rely on the Docker registry to download the Ubuntu images, on the Ubuntu repository to download the compilers and so on. It's not really a daily issue for the HEAD of an active repository. However, we have no guarantee that a given &lt;code&gt;Dockerfile&lt;/code&gt; we will still build in X months. That's why I have written "it's &lt;em&gt;easier&lt;/em&gt; to rebuild old versions of the project", instead of "you can rebuild any old versions of the project".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I have showed one way to use Docker. The repository contains a &lt;code&gt;Dockerfile&lt;/code&gt; to create the build environment from scratch, making the repository somehow able to build itself. This is a nice approach because the repository is self-sufficient.&lt;/p&gt;

&lt;p&gt;We can proceed differently to mitigate the last two downsides. For instance, we can manage the creations of the images separately from the project(s) that will use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat Docker images as a separate project
&lt;/h2&gt;

&lt;p&gt;Creating build environments can be considered as a separate project.&lt;/p&gt;

&lt;p&gt;On the one hand, we create images with revisions. Instead of always tagging the images as "latest" with &lt;code&gt;docker build -t cmake-on-stm32 .&lt;/code&gt;, we use explicit version numbers with &lt;code&gt;docker build -t cmake-on-stm32:0.1 .&lt;/code&gt;, &lt;code&gt;docker build -t cmake-on-stm32:0.2 .&lt;/code&gt;, etc. Each version of the image corresponds to a set of tools at known versions. If we need a new version of CMake (for instance), we update the &lt;code&gt;Dockerfile&lt;/code&gt; and release image &lt;code&gt;0.3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, we fetch the exact Docker image we need in our STM32-based project. We can create build scripts to wrap the commands shown in this article to force people to use the correct Docker image at any revision of the repository.&lt;/p&gt;

&lt;p&gt;Sharing the Docker images can be manual, using &lt;a href="https://docs.docker.com/reference/cli/docker/image/save/" rel="noopener noreferrer"&gt;&lt;code&gt;docker image save&lt;/code&gt;&lt;/a&gt; + &lt;a href="https://docs.docker.com/reference/cli/docker/image/load/" rel="noopener noreferrer"&gt;&lt;code&gt;docker image load&lt;/code&gt;&lt;/a&gt; + a shared drive. The images can also be pushed to the DockerHub or self-hosted registry with &lt;a href="https://docs.docker.com/reference/cli/docker/image/push/" rel="noopener noreferrer"&gt;&lt;code&gt;docker image push&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this episode, we have seen how we can leverage Docker to seamlessly set up and manage our build environment. Instead of having to install several applications on our computer, we now only need Docker to build the project. We have also seen there are several ways to include Docker in the process. It's up to you to find how you want to use it in your project. I really wished I could go back in time and try Docker on some of my previous projects! Tell me in the comments how you use/would like to use Docker for your projects!&lt;/p&gt;

</description>
      <category>embedded</category>
      <category>cpp</category>
      <category>cmake</category>
      <category>docker</category>
    </item>
    <item>
      <title>CMake on SMT32 | Episode 7: unit tests</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Thu, 15 Feb 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/pgradot/cmake-on-smt32-episode-7-unit-tests-13gj</link>
      <guid>https://dev.to/pgradot/cmake-on-smt32-episode-7-unit-tests-13gj</guid>
      <description>&lt;p&gt;It's been almost four years, and it's about time to revive this series on CMake and STM32 (or MCUs in general, STM32 just serves as a tangible example).&lt;/p&gt;

&lt;p&gt;Funny enough, I'm not working with microcontrollers anymore.... This is a very recent change in my professional career, even if I think I will probably work again with MCUs sooner or later. However, I still use CMake to build C++ projects! The real reason to resume this series is my desire to write an article Docker for builds. In 2020, I had never used Docker at all. Today, I use it very often, and I'm convinced it could have solved some build and environment issues back then.&lt;/p&gt;

&lt;p&gt;But hey, you might be wondering why I'm talking about Docker. Isn't this article supposed to be about unit tests? Yep, it is. I originally planned to cover unit tests back in 2020, but things didn't pan out. It seems logical to write about this topic first. It will give us even more reasons to use Docker (subscribe so you don't miss the next episode)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why unit tests?
&lt;/h2&gt;

&lt;p&gt;I don't want to get into a lengthy debate about pros &amp;amp; cons about unit tests. Sure, they can be misused (so badly), but I believe they are a very powerful tool to improve software quality. There are tons of great articles on this topic out there if you want to if you want to delve into this topic. If you speak (or at least understand) French, &lt;a href="https://www.younup.fr/blog/podcast-tests-unitaires-vraiment-utiles" rel="noopener noreferrer"&gt;I was invited on a podcast to talk about unit tests&lt;/a&gt;, and I explained why I believe they are a crucial part of software development.&lt;/p&gt;

&lt;p&gt;After 13+ years as a software developer, mostly working projects with MCUs (and especially STM32), I must say that unit tests aren't very common in the embedded world. Embedded projects sometimes feel more like electronics-with-some-code projects than modern software projects. Hardware can be a real constraint too, so we tend to think that unit tests aren't for us.&lt;/p&gt;

&lt;p&gt;In this article, I want to show that it doesn't have to be necessarily that way. With CMake, we can easily build unit tests for our embedded projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running tests on board
&lt;/h2&gt;

&lt;p&gt;Since we're dealing with electronic devices, our first thought is naturally to run tests directly on the board.&lt;/p&gt;

&lt;p&gt;Running unit tests on board is great, because the same compiler and processor are used for both the tests and the real application. The tests are very close to the real usage of the code.&lt;/p&gt;

&lt;p&gt;To do this, we will need to create an additional firmware dedicated solely to running tests and generating a test report. This means we have to add another &lt;code&gt;add_executable()&lt;/code&gt; in your &lt;code&gt;CMakeLists.txt&lt;/code&gt;. Similar to the real application's target, we have call &lt;code&gt;target_compile_definitions()&lt;/code&gt;, &lt;code&gt;target_include_directories()&lt;/code&gt;, &lt;code&gt;target_link_options()&lt;/code&gt;, and so on, to generate a suitable firmware for the board. This process is not different from what we covered in the previous episodes.&lt;/p&gt;

&lt;p&gt;However, running tests on board presents several challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A test framework that compiles for the target must be found.&lt;/li&gt;
&lt;li&gt;Tests may need to be split into several executables so that each one fits within the flash memory of the MCU.&lt;/li&gt;
&lt;li&gt;The standard output of your board must be captured to get the test report.&lt;/li&gt;
&lt;li&gt;Running tests takes time, simply because you have to program the board.&lt;/li&gt;
&lt;li&gt;Integration in CI pipeline may be problematic because it may not be feasible to connect a board to the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While these challenges are not insurmountable, the following section will explore the advantages of running tests on your computer, eliminating these constraints and offering additional benefits.&lt;/p&gt;

&lt;p&gt;If you want to learn more about embedded tests, the great &lt;em&gt;MCU on Eclipse&lt;/em&gt; blog has recently published &lt;a href="https://mcuoneclipse.com/2023/12/18/modern-on-target-embedded-system-testing-with-cmake-and-ctest/" rel="noopener noreferrer"&gt;an article on this topic&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running tests on your computer
&lt;/h2&gt;

&lt;p&gt;Instead of running the tests directly on board, an alternative approach is to compile them using a compiler for PC and execute them on our computer. This eliminates the constraints mentioned earlier.&lt;/p&gt;

&lt;p&gt;You may argue that we are using different compiler, and this won't accurately reflect of the real usage of the code. And in some ways, you're absolutely right. Indeed, even something as "basic" as the size of an integer could differ between &lt;code&gt;arm-none-eabi-gcc&lt;/code&gt; and regular &lt;code&gt;gcc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But that's actually the silver lining! Compiling our project with another compiler may raise new warnings, highlighting non-portable constructs. Running on a different CPU may reveal undefined behaviors in our code. Finally, being able to compile a significant part of the project for another target demonstrates that the abstraction from the hardware layers are well-designed. Naturally, this also implies that we won't be able to test the parts that are tightly coupled to hardware features.&lt;/p&gt;

&lt;p&gt;In the remainder of this article, I will demonstrate how to use CMake to build an embedded firmware and PC-based tests within the same &lt;code&gt;CMakeLists.txt&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;

&lt;p&gt;The structure of the project is as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frywlj843xnch729ucggh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frywlj843xnch729ucggh.png" alt="tree of the project" width="493" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most elements are simply the result of the previous episodes. I have just added a directory (&lt;code&gt;tests&lt;/code&gt;) and two files (&lt;code&gt;compute.hpp&lt;/code&gt; and &lt;code&gt;test_compute.cpp&lt;/code&gt;), because... we need something to test!&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple test case
&lt;/h2&gt;

&lt;p&gt;The purpose here is to demonstrate some CMake features, don't expect amazing code.&lt;/p&gt;

&lt;p&gt;First, we need something to test. For instance a simple &lt;a href="https://en.wikipedia.org/wiki/Quadratic_function" rel="noopener noreferrer"&gt;quadratic function&lt;/a&gt; implementation. This is a good candidate for PC-based tests, because it doesn't have any dependencies to the BSP. The code goes into &lt;code&gt;compute.hpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;quadratic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests are written in a separate file, &lt;code&gt;test_compute.cpp&lt;/code&gt;. For this example, I have decided a use &lt;a href="https://github.com/catchorg/Catch2" rel="noopener noreferrer"&gt;Catch2&lt;/a&gt;, a great unit testing framework for C++ that I have been using for the last 5 years.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;catch2/catch_test_macros.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"compute.hpp"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;TEST_CASE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Compute quadratic function"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;quadratic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;quadratic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;quadratic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;quadratic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;True story: I found that my function had a bug when I wrote these tests. I had mistakenly written &lt;code&gt;a * a * x&lt;/code&gt; instead of &lt;code&gt;a * x * x&lt;/code&gt; in the implementation of &lt;code&gt;compute::quadratic()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the executable for the tests
&lt;/h2&gt;

&lt;p&gt;Similar to adding tests for on-board execution, we have to add another &lt;code&gt;add_executable()&lt;/code&gt; in our &lt;code&gt;CMakeLists.txt&lt;/code&gt;. However, things are sightly different: we need to handle two different compilers now. Fortunately, CMake makes it straightforward to determine whether we are &lt;a href="https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html" rel="noopener noreferrer"&gt;cross-compiling&lt;/a&gt; (to create our STM32-based firmware) or not (to create our PC-based program), thanks to &lt;a href="https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING.html" rel="noopener noreferrer"&gt;the variable &lt;code&gt;CMAKE_CROSSCOMPILING&lt;/code&gt;&lt;/a&gt;. We will see in the next section that this variable is set when we provide CMake with a toolchain file.&lt;/p&gt;

&lt;p&gt;The structure of our &lt;code&gt;CMakeLists.txt&lt;/code&gt; will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;cmake_minimum_required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;VERSION 3.15.3&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;nucleo-f413zh&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;enable_language&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;C CXX ASM&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_C_STANDARD 99&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_C_STANDARD_REQUIRED ON&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_C_EXTENSIONS OFF&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CXX_STANDARD 17&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CXX_STANDARD_REQUIRED ON&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CXX_EXTENSIONS OFF&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CROSSCOMPILING&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;STATUS &lt;span class="s2"&gt;"Cross compiling for board..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Here goes the code from the previous episodes&lt;/span&gt;

&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;STATUS &lt;span class="s2"&gt;"Compiling for PC..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Here goes the code to build the unit tests&lt;/span&gt;
        &lt;span class="c1"&gt;# See below :)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Catch2 is available on &lt;a href="https://github.com/catchorg/Catch2" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. You can get a copy of its source code and integrate it into your project source tree. You can also use &lt;a href="https://cmake.org/cmake/help/latest/module/FetchContent.html" rel="noopener noreferrer"&gt;&lt;code&gt;FetchContent&lt;/code&gt; module&lt;/a&gt; to get it from GitHub directly during the build process, as suggested in Catch2's &lt;a href="https://github.com/catchorg/Catch2/blob/devel/docs/cmake-integration.md" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;. We will use this technique here.&lt;/p&gt;

&lt;p&gt;Let's complete the &lt;code&gt;else()&lt;/code&gt; clause from the previous snippet to create our executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;STATUS &lt;span class="s2"&gt;"Compiling for PC..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get Catch2&lt;/span&gt;
&lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;FetchContent&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;FetchContent_Declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        Catch2
        GIT_REPOSITORY https://github.com/catchorg/Catch2.git
        GIT_TAG v3.5.2
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;FetchContent_MakeAvailable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;Catch2&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create executable&lt;/span&gt;
&lt;span class="nb"&gt;add_executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;tests
        tests/test_compute.cpp&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;target_include_directories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;tests PRIVATE
        source&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;tests PRIVATE
        Catch2::Catch2WithMain&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build and run the tests
&lt;/h2&gt;

&lt;p&gt;As mentioned before, passing a toolchain file to CMake from the command-line automatically set &lt;code&gt;CMAKE_CROSSCOMPILING&lt;/code&gt;. We will hence have to generate two "projects" from a single &lt;code&gt;CMakeLists.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On one side, we generate a project for the &lt;code&gt;arm-none-eabi-gcc&lt;/code&gt; toolchain, just like in the first episode of this series. From the &lt;code&gt;nucleo&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cmake &lt;span class="nt"&gt;-B&lt;/span&gt; build-embedded &lt;span class="nt"&gt;-DCMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Debug &lt;span class="nt"&gt;-DCMAKE_TOOLCHAIN_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-none-eabi-gcc.cmake
&lt;span class="nt"&gt;--&lt;/span&gt; The C compiler identification is GNU 10.3.1
&lt;span class="nt"&gt;--&lt;/span&gt; The CXX compiler identification is GNU 10.3.1
&lt;span class="nt"&gt;--&lt;/span&gt; Detecting C compiler ABI info
&lt;span class="nt"&gt;--&lt;/span&gt; Detecting C compiler ABI info - &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Check &lt;span class="k"&gt;for &lt;/span&gt;working C compiler: /usr/bin/arm-none-eabi-gcc - skipped
...
&lt;span class="nt"&gt;--&lt;/span&gt; Cross compiling &lt;span class="k"&gt;for &lt;/span&gt;board...
...

&lt;span class="nv"&gt;$ &lt;/span&gt;cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build-embedded/
Scanning dependencies of target nucleo-f413zh.out
&lt;span class="o"&gt;[&lt;/span&gt;  3%] Building C object CMakeFiles/nucleo-f413zh.out.dir/BSP/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c.obj
&lt;span class="o"&gt;[&lt;/span&gt;  7%] Building C object CMakeFiles/nucleo-f413zh.out.dir/BSP/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c.obj
&lt;span class="o"&gt;[&lt;/span&gt; 11%] Building C object CMakeFiles/nucleo-f413zh.out.dir/BSP/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c.obj
...
&lt;span class="o"&gt;[&lt;/span&gt;100%] Linking CXX executable nucleo-f413zh.out
   text    data     bss     dec     hex filename
   7868      20    2892   10780    2a1c nucleo-f413zh.out
&lt;span class="o"&gt;[&lt;/span&gt;100%] Built target nucleo-f413zh.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other side, we generate another project to build with our default system compiler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cmake &lt;span class="nt"&gt;-B&lt;/span&gt; build-tests &lt;span class="nt"&gt;-DCMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Release                                             
&lt;span class="nt"&gt;--&lt;/span&gt; The C compiler identification is GNU 11.4.0
&lt;span class="nt"&gt;--&lt;/span&gt; The CXX compiler identification is GNU 11.4.0
&lt;span class="nt"&gt;--&lt;/span&gt; Detecting C compiler ABI info
&lt;span class="nt"&gt;--&lt;/span&gt; Detecting C compiler ABI info - &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; Check &lt;span class="k"&gt;for &lt;/span&gt;working C compiler: /usr/bin/cc - skipped
...
&lt;span class="nt"&gt;--&lt;/span&gt; Compiling &lt;span class="k"&gt;for &lt;/span&gt;PC...
...

&lt;span class="nv"&gt;$ &lt;/span&gt;cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build-tests/
&lt;span class="o"&gt;[&lt;/span&gt;  0%] Building CXX object _deps/catch2-build/src/CMakeFiles/Catch2.dir/catch2/benchmark/catch_chronometer.cpp.o
&lt;span class="o"&gt;[&lt;/span&gt;  1%] Building CXX object _deps/catch2-build/src/CMakeFiles/Catch2.dir/catch2/benchmark/detail/catch_analyse.cpp.o
&lt;span class="o"&gt;[&lt;/span&gt;  2%] Building CXX object _deps/catch2-build/src/CMakeFiles/Catch2.dir/catch2/benchmark/detail/catch_benchmark_function.cpp.o
&lt;span class="o"&gt;[&lt;/span&gt;  3%] Building CXX object _deps/catch2-build/src/CMakeFiles/Catch2.dir/catch2/benchmark/detail/catch_run_for_at_least.cpp.o
...
 96%] Built target Catch2
&lt;span class="o"&gt;[&lt;/span&gt; 97%] Building CXX object _deps/catch2-build/src/CMakeFiles/Catch2WithMain.dir/catch2/internal/catch_main.cpp.o
&lt;span class="o"&gt;[&lt;/span&gt; 98%] Linking CXX static library libCatch2Main.a
&lt;span class="o"&gt;[&lt;/span&gt; 98%] Built target Catch2WithMain
&lt;span class="o"&gt;[&lt;/span&gt; 99%] Building CXX object CMakeFiles/tests.dir/tests/test_compute.cpp.o
&lt;span class="o"&gt;[&lt;/span&gt;100%] Linking CXX executable tests
&lt;span class="o"&gt;[&lt;/span&gt;100%] Built target tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because our executable depends on Catch2, CMake builds the library before.&lt;/p&gt;

&lt;p&gt;Our tests are now ready to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="n"&gt;CMakeCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;  &lt;span class="n"&gt;CMakeFiles&lt;/span&gt;  &lt;span class="n"&gt;Makefile&lt;/span&gt;  &lt;span class="n"&gt;_deps&lt;/span&gt;  &lt;span class="n"&gt;cmake_install&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmake&lt;/span&gt;  &lt;span class="n"&gt;tests&lt;/span&gt;

&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tests&lt;/span&gt; 
&lt;span class="n"&gt;Randomness&lt;/span&gt; &lt;span class="n"&gt;seeded&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;179865564&lt;/span&gt;
&lt;span class="o"&gt;===============================================================================&lt;/span&gt;
&lt;span class="n"&gt;All&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="n"&gt;passed&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="n"&gt;assertions&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hurray! The tests passed!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this episode, we have discussed unit tests for embedded projects.&lt;/p&gt;

&lt;p&gt;We have seen that running tests on board is great, but there are some difficulties to overcome. Running tests on PC don't have these difficulties and may even offer additional benefits. If you have the chance to do both, do it!&lt;/p&gt;

&lt;p&gt;We've seen how to manage both an STM32-based firmware and a PC-based program within the same &lt;code&gt;CMakeLists.txt&lt;/code&gt;. We generate two separate build directories, one for each compiler and hence one for each executable. &lt;/p&gt;

&lt;p&gt;I hope that this episode convinced you to add unit tests to your STM32 (or any other MCU) projects. Happy tests!&lt;/p&gt;

</description>
      <category>embedded</category>
      <category>cpp</category>
      <category>microcontrollers</category>
      <category>cmake</category>
    </item>
    <item>
      <title>vtable under the surface | Episode 3 - How virtual functions are actually called</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Tue, 23 Jan 2024 15:57:43 +0000</pubDate>
      <link>https://dev.to/pgradot/vtable-under-the-surface-actually-calling-virtual-functions-1p8b</link>
      <guid>https://dev.to/pgradot/vtable-under-the-surface-actually-calling-virtual-functions-1p8b</guid>
      <description>&lt;p&gt;In this episode, we will see how invoking a virtual function in C++ translates into assembly instructions. We will see how our class instance is constructed and how it relates to the vtable. Then, we will see how this vtable is used to call the appropriate function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In you have actually built the project and analyzed the binary in the previous episode, don't forget to remove the &lt;code&gt;-fno-rtti&lt;/code&gt; option and to rebuild the project. I will use this binary as a reference here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Execute the Program with &lt;code&gt;gdb&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To understand how vtables are used in assembly, disassembling the binary with &lt;code&gt;objdump --dissassemble&lt;/code&gt; could have been an option, but instead, I decided to use &lt;code&gt;gdb&lt;/code&gt; to actually execute the program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gdb a.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, &lt;code&gt;gdb&lt;/code&gt; uses AT&amp;amp;T syntax to disassemble the code, but I prefer Intel flavor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) set disassembly-flavor intel
(gdb) show disassembly-flavor
The disassembly flavor is "intel".

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enabling name demangling will make it easier to understand the symbols being manipulated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) set print asm-demangle
(gdb) show print asm-demangle
Demangling of C++/ObjC names in disassembly listings is on.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run to the main:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) break main
Breakpoint 1 at 0x1139: file /home/pierre/CLionProjects/untitled/main.cpp, line 3.
(gdb) run
Starting program: /home/pierre/CLionProjects/untitled/cmake-build-debug/a.out 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at /home/pierre/CLionProjects/untitled/main.cpp:3
3       int main() {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now disassemble the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) disas
Dump of assembler code for function main():
=&amp;gt; 0x0000555555555139 &amp;lt;+0&amp;gt;:     sub    rsp,0x18
   0x000055555555513d &amp;lt;+4&amp;gt;:     mov    DWORD PTR [rsp+0x8],0x0
   0x0000555555555145 &amp;lt;+12&amp;gt;:    mov    DWORD PTR [rsp+0xc],0x0
   0x000055555555514d &amp;lt;+20&amp;gt;:    lea    rax,[rip+0x2c44]        # 0x555555557d98 &amp;lt;vtable for Derived+16&amp;gt;
   0x0000555555555154 &amp;lt;+27&amp;gt;:    mov    QWORD PTR [rsp],rax
   0x0000555555555158 &amp;lt;+31&amp;gt;:    mov    rdi,rsp
   0x000055555555515b &amp;lt;+34&amp;gt;:    call   0x5555555551c1 &amp;lt;use(Base const&amp;amp;)&amp;gt;
   0x0000555555555160 &amp;lt;+39&amp;gt;:    mov    eax,0x0
   0x0000555555555165 &amp;lt;+44&amp;gt;:    add    rsp,0x18
   0x0000555555555169 &amp;lt;+48&amp;gt;:    ret
End of assembler dump.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can clearly see the call to &lt;code&gt;use()&lt;/code&gt;. The immediately preceding line prepares the first and only argument of this function (it puts it in the &lt;code&gt;rdi&lt;/code&gt; register). The other lines above are the initialisation of &lt;code&gt;obj&lt;/code&gt;, our instance of &lt;code&gt;Derived&lt;/code&gt;. We can't understand how &lt;code&gt;use()&lt;/code&gt; is called and uses the vtable to call &lt;code&gt;Derived::foo()&lt;/code&gt; if we don't understand how &lt;code&gt;obj&lt;/code&gt; is initialized and how it is connected to the vtable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clarification About Addresses
&lt;/h2&gt;

&lt;p&gt;Before we dive in a line-by-line assembly analysis, I want to clarify why the address of &lt;code&gt;use()&lt;/code&gt; in the &lt;code&gt;call&lt;/code&gt; instruction is 0x005555555551c1 and not 0x00000000000011c1 (as in the symbol table from the previous episode, or in the disassembly produced by &lt;code&gt;obdjump --disassemble&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;When the binary is loaded in memory and executed, it's not placed at address 0x0000000000000000 but somewhere else. The addresses in the ELF file are relative from this "somewhere else".&lt;/p&gt;

&lt;p&gt;We can compute this offset with a simple subtraction: 0x005555555551c1 - 0x00000000000011c1 = 0x00555555554000. The same translation can be applied to any other symbols. We can verify this offset with the address of &lt;code&gt;main&lt;/code&gt;. We need the address of &lt;code&gt;main&lt;/code&gt; in the binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt; objdump &lt;span class="nt"&gt;--syms&lt;/span&gt; a.out | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'main'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'.text'&lt;/span&gt;
0000000000001139 g     F .text  0000000000000031              main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we add the offset to this address, the result is the first address in the disassembly above: 0x0000000000001139 + 0x00555555554000 = 0x0000555555555139.&lt;/p&gt;

&lt;h2&gt;
  
  
  Construction of the Object
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;main()&lt;/code&gt;, &lt;code&gt;obj&lt;/code&gt; is initialized by these instructions (note that &lt;code&gt;=&amp;gt;&lt;/code&gt; indicates the line where &lt;code&gt;gdb&lt;/code&gt; is paused):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=&amp;gt; 0x0000555555555139 &amp;lt;+0&amp;gt;:     sub    rsp,0x18
   0x000055555555513d &amp;lt;+4&amp;gt;:     mov    DWORD PTR [rsp+0x8],0x0
   0x0000555555555145 &amp;lt;+12&amp;gt;:    mov    DWORD PTR [rsp+0xc],0x0
   0x000055555555514d &amp;lt;+20&amp;gt;:    lea    rax,[rip+0x2c44]        # 0x555555557d98 &amp;lt;vtable for Derived+16&amp;gt;
   0x0000555555555154 &amp;lt;+27&amp;gt;:    mov    QWORD PTR [rsp],rax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line moves the stack pointer, allocating space to store &lt;code&gt;obj&lt;/code&gt;. We can execute a few commands to verify this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) info reg rsp
rsp            0x7fffffffddd8      0x7fffffffddd8
(gdb) nexti
4           auto obj = Derived();
(gdb) info reg rsp
rsp            0x7fffffffddc0      0x7fffffffddc0
(gdb) print &amp;amp;obj
$2 = (Derived *) 0x7fffffffddc0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After these commands, &lt;code&gt;gdb&lt;/code&gt; is paused on the second line, at the address 0x000055555555513d. The address of &lt;code&gt;obj&lt;/code&gt; is the same as the value of the &lt;code&gt;rsp&lt;/code&gt; register. At this moment, the object is created but not initialized:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) print obj
$3 = {&amp;lt;Base&amp;gt; = {_vptr.Base = 0x0, dummy_base = 1431671456}, dummy_derived = 21845}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not surprising to see &lt;code&gt;dummy_base&lt;/code&gt; and &lt;code&gt;dummy_derived&lt;/code&gt;, as they are the member data of &lt;code&gt;Derived&lt;/code&gt;. But what is &lt;code&gt;_vptr.Base&lt;/code&gt;? This is the "virtual pointer". It's automatically inserted by the compiler to reference the vtable. It doesn't point to (the beginning of) the vtable actually, but to a location that the &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components" rel="noopener noreferrer"&gt;ABI's specification&lt;/a&gt; refers to as the "virtual table address point", &lt;em&gt;inside&lt;/em&gt; the vtable. This point corresponds to the first function pointer in the vtable. We will get back to this pointer later. &lt;/p&gt;

&lt;p&gt;The next instructions are here to initialize &lt;code&gt;obj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, &lt;code&gt;dummy_base&lt;/code&gt; and &lt;code&gt;dummy_derived&lt;/code&gt; are set to 0 by the two &lt;code&gt;mov&lt;/code&gt; instructions (yes, even though our code doesn't require to initialize them). A C++ equivalent of &lt;code&gt;mov    DWORD PTR [rsp+0x8],0x0&lt;/code&gt; would ressemble something like &lt;code&gt;*(rsp + 0x8) = 0x0&lt;/code&gt;. At this point, the value of &lt;code&gt;rsp&lt;/code&gt; is 0x007fffffffddc0, confirming that &lt;code&gt;rsp+0x8&lt;/code&gt; and &lt;code&gt;rsp+0xc&lt;/code&gt; are indeed the addresses of the data members:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) print &amp;amp;obj.dummy_base
$5 = (int *) 0x7fffffffddc8
(gdb) print &amp;amp;obj.dummy_derived
$6 = (int *) 0x7fffffffddcc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The initialization of the virtual pointer is slightly more complex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   0x000055555555514d &amp;lt;+20&amp;gt;:    lea    rax,[rip+0x2c44]        # 0x555555557d98 &amp;lt;vtable for Derived+16&amp;gt;
   0x0000555555555154 &amp;lt;+27&amp;gt;:    mov    QWORD PTR [rsp],rax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://www.felixcloutier.com/x86/lea" rel="noopener noreferrer"&gt;&lt;code&gt;lea&lt;/code&gt; instruction&lt;/a&gt; with an operand that is relative to the &lt;code&gt;rip&lt;/code&gt; register is classic compiler technique to get the address of something that is inside the binary being executed. &lt;code&gt;gdb&lt;/code&gt; kindly shows the result of the computation. It even tells us that this is the address of &lt;code&gt;vtable for Derived+16&lt;/code&gt;. In the previous episode, we noted that the first function address in the vtable comes after 8 bytes for the offset and 8 bytes for the pointer to the RTTI, hence a total of 16 bytes. You should understand now why the virtual pointer is set to &lt;code&gt;vtable for Derived+16&lt;/code&gt;: this is the "virtual table address point".&lt;/p&gt;

&lt;p&gt;This address is temporarily stored into &lt;code&gt;rax&lt;/code&gt; before being moved on the stack to complete the initialization of &lt;code&gt;obj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can execute these instructions with &lt;code&gt;gdb&lt;/code&gt; to run the initialization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) ni
(gdb) ni
(gdb) ni
(gdb) ni
(gdb) print obj
$7 = {&amp;lt;Base&amp;gt; = {_vptr.Base = 0x555555557d98 &amp;lt;vtable for Derived+16&amp;gt;, dummy_base = 0}, dummy_derived = 0}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to verify what is being pointed to by the virtual pointer, we have 2 options.&lt;/p&gt;

&lt;p&gt;The first solution is the manual, tedious one. We can &lt;a href="https://sourceware.org/gdb/current/onlinedocs/gdb.html/Memory.html" rel="noopener noreferrer"&gt;dump the memory&lt;/a&gt; located at this address and compare the dumped values to the addresses of the member functions of &lt;code&gt;Derived&lt;/code&gt;. We need to dump 2 sets of 8 bytes each (since a function pointer is 8-byte wide):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) x/2gx 0x555555557d98
0x555555557d98 &amp;lt;vtable for Derived+16&amp;gt;: 0x0000555555555196      0x00005555555551ac
(gdb) print 'Derived::foo'
$8 = {void (const Derived * const)} 0x555555555196 &amp;lt;Derived::foo() const&amp;gt;
(gdb) print 'Derived::bar'
$9 = {void (const Derived * const)} 0x5555555551ac &amp;lt;Derived::bar() const&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second solution is just using the &lt;a href="https://visualgdb.com/gdbreference/commands/info_vtbl" rel="noopener noreferrer"&gt;dedicated command&lt;/a&gt; provided by &lt;code&gt;gdb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) info vtbl obj
vtable for 'Derived' @ 0x555555557d98 (subobject @ 0x7fffffffddc0):
[0]: 0x555555555196 &amp;lt;Derived::foo() const&amp;gt;
[1]: 0x5555555551ac &amp;lt;Derived::bar() const&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calling &lt;code&gt;use()&lt;/code&gt; from &lt;code&gt;main()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The object is now ready, and &lt;code&gt;gdb&lt;/code&gt; is paused here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) disas
(...)
=&amp;gt; 0x0000555555555158 &amp;lt;+31&amp;gt;:    mov    rdi,rsp
   0x000055555555515b &amp;lt;+34&amp;gt;:    call   0x5555555551c1 &amp;lt;use(Base const&amp;amp;)&amp;gt;
(...)
End of assembler dump.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Linux-x64, the calling convention for functions uses the &lt;code&gt;rdi&lt;/code&gt; register as the first parameter. We've seen in the previous section that &lt;code&gt;rsp&lt;/code&gt; holds the address of &lt;code&gt;obj&lt;/code&gt; at this point. This address is moved in the &lt;code&gt;rdi&lt;/code&gt; register and the function is ready to be called. Indeed, a reference in C++ is often just an address in assembly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Virtual Function is Actually Called
&lt;/h2&gt;

&lt;p&gt;We can reach the beginning of &lt;code&gt;use()&lt;/code&gt; with &lt;code&gt;ni&lt;/code&gt; (to execute the &lt;code&gt;mov&lt;/code&gt;) and &lt;code&gt;si&lt;/code&gt; (to step into the &lt;code&gt;call&lt;/code&gt;). We can disassemble the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) disas
Dump of assembler code for function _Z3useRK4Base:
=&amp;gt; 0x00005555555551c1 &amp;lt;+0&amp;gt;:     sub    rsp,0x8
   0x00005555555551c5 &amp;lt;+4&amp;gt;:     mov    rax,QWORD PTR [rdi]
   0x00005555555551c8 &amp;lt;+7&amp;gt;:     call   QWORD PTR [rax]
   0x00005555555551ca &amp;lt;+9&amp;gt;:     add    rsp,0x8
   0x00005555555551ce &amp;lt;+13&amp;gt;:    ret
End of assembler dump.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The virtual call is right here!&lt;/p&gt;

&lt;p&gt;We have seen that the value of &lt;code&gt;rdi&lt;/code&gt; is the virtual pointer and that the first entry in the array pointed to by this virtual pointer is the address of &lt;code&gt;Derived::foo()&lt;/code&gt;. The value pointed to by &lt;code&gt;rdi&lt;/code&gt; is moved into &lt;code&gt;rax&lt;/code&gt;, and then the value pointed to by &lt;code&gt;rax&lt;/code&gt; is called. The function &lt;code&gt;Derived::foo()&lt;/code&gt; executes and prints &lt;code&gt;Derived =&amp;gt; foo()&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;You can try to change the code to call &lt;code&gt;bar()&lt;/code&gt; instead of &lt;code&gt;foo()&lt;/code&gt;. The &lt;code&gt;call&lt;/code&gt; instruction will be different. You will have &lt;code&gt;call   QWORD PTR [rax+0x8]&lt;/code&gt; instead, to get the next pointer in the array of function pointers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indirect Call
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;use()&lt;/code&gt;, the instruction &lt;code&gt;call   QWORD PTR [rax]&lt;/code&gt; is an indirect call because the value of a register is used. The instruction &lt;code&gt;call   0x5555555551c1&lt;/code&gt; to call &lt;code&gt;use()&lt;/code&gt; from &lt;code&gt;main()&lt;/code&gt; is a direct call. The mnemonic is the same (&lt;code&gt;call&lt;/code&gt;) but the opcodes (the binary values used to translate the mnemonic) are different.&lt;/p&gt;

&lt;p&gt;We can examine the memory with &lt;code&gt;gdb&lt;/code&gt; to see the difference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) x /1bx use+7
0x5555555551c8 &amp;lt;use(Base const&amp;amp;)+7&amp;gt;:    0xff
(gdb) x /1bx main+34
0x55555555515b &amp;lt;main()+34&amp;gt;:     0xe8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indirect calls are typically used to implement function pointer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this episode, we discovered that the compiler adds a hidden field for each instance of a class with virtual functions. This field is the "virtual pointer" (or "vptr" in short). Thanks to this pointer, we can get a function pointer inside the vtable, and the desired function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will publish the episodes as I write them. Subscribe to be notified! 💃🏽&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>cpp</category>
      <category>computerscience</category>
      <category>todayilearned</category>
      <category>todayisearched</category>
    </item>
    <item>
      <title>vtables under the surface | Episode 2 - ELF files</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Fri, 05 Jan 2024 09:07:47 +0000</pubDate>
      <link>https://dev.to/pgradot/vtables-in-elf-files-4n2l</link>
      <guid>https://dev.to/pgradot/vtables-in-elf-files-4n2l</guid>
      <description>&lt;p&gt;In this episode, we will explore what vtables mean in terms of bytes within ELF files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Output
&lt;/h2&gt;

&lt;p&gt;On Linux, GCC produces ELF files as the result of the compilation process. In our project, the file is &lt;code&gt;a.out&lt;/code&gt;, and we can use the &lt;code&gt;file&lt;/code&gt; command to get details about it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;file a.out 
a.out: ELF 64-bit LSB pie executable, x86-64, version 1 &lt;span class="o"&gt;(&lt;/span&gt;SYSV&lt;span class="o"&gt;)&lt;/span&gt;, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]&lt;span class="o"&gt;=&lt;/span&gt;a87e1cb2356338a14f1a9aa2fef85fb7036bee65, &lt;span class="k"&gt;for &lt;/span&gt;GNU/Linux 3.2.0, not stripped

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the compiler has generated vtables for &lt;code&gt;Base&lt;/code&gt; and &lt;code&gt;Derived&lt;/code&gt;, there must be corresponding symbols and bytes in the binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect the Symbols
&lt;/h2&gt;

&lt;p&gt;Let's identify the symbols related to these classes. We can use &lt;code&gt;objdump&lt;/code&gt; to get the symbol table, employ &lt;code&gt;sort&lt;/code&gt; to order the symbols by addresses, and filter the output to retain only what relates to &lt;code&gt;Base&lt;/code&gt; and &lt;code&gt;Derived&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;objdump &lt;span class="nt"&gt;--syms&lt;/span&gt; &lt;span class="nt"&gt;--demangle&lt;/span&gt; a.out | &lt;span class="nb"&gt;sort&lt;/span&gt; | egrep &lt;span class="s2"&gt;"Base|Derived"&lt;/span&gt;
000000000000116a g     F .text  0000000000000015              Base::foo&lt;span class="o"&gt;()&lt;/span&gt; const
0000000000001180 g     F .text  0000000000000015              Base::bar&lt;span class="o"&gt;()&lt;/span&gt; const
0000000000001196 g     F .text  0000000000000015              Derived::foo&lt;span class="o"&gt;()&lt;/span&gt; const
00000000000011ac g     F .text  0000000000000015              Derived::bar&lt;span class="o"&gt;()&lt;/span&gt; const
00000000000011c1 g     F .text  000000000000000e              use&lt;span class="o"&gt;(&lt;/span&gt;Base const&amp;amp;&lt;span class="o"&gt;)&lt;/span&gt;
0000000000002042  w    O .rodata        0000000000000006              typeinfo name &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000002048  w    O .rodata        0000000000000009              typeinfo name &lt;span class="k"&gt;for &lt;/span&gt;Derived
0000000000003d68  w    O .data.rel.ro   0000000000000020              vtable &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000003d88  w    O .data.rel.ro   0000000000000020              vtable &lt;span class="k"&gt;for &lt;/span&gt;Derived
0000000000003da8  w    O .data.rel.ro   0000000000000010              typeinfo &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000003db8  w    O .data.rel.ro   0000000000000018              typeinfo &lt;span class="k"&gt;for &lt;/span&gt;Derived
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are not familiar with the output format of &lt;code&gt;objdump --syms&lt;/code&gt;, you can refer to the &lt;a href="https://manpages.ubuntu.com/manpages/kinetic/en/man1/objdump.1.html" rel="noopener noreferrer"&gt;man pages&lt;/a&gt; of the command. The help of the &lt;code&gt;--syms&lt;/code&gt; options provide with detailed information about each column.&lt;/p&gt;

&lt;p&gt;We see the addresses of our 4 member functions, as well as &lt;code&gt;use()&lt;/code&gt;. These functions are stored in the &lt;code&gt;.text&lt;/code&gt; section, which is the dedicated section for code. We also see several objects (notice the &lt;code&gt;O&lt;/code&gt; in the third column) for the information about the types and... the virtual tables! Let's dig into the contents of these tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives to &lt;code&gt;objdump&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Before we move to the hard values, I just want to briefly mention alternatives to &lt;code&gt;objdump&lt;/code&gt;. Unfortunately, neither display the sections along with the symbols (please leave a comment if I have missed the magic options!).&lt;/p&gt;

&lt;p&gt;Alternative 1 = &lt;code&gt;nm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nm &lt;span class="nt"&gt;--demangle&lt;/span&gt; &lt;span class="nt"&gt;--print-size&lt;/span&gt; a.out | &lt;span class="nb"&gt;sort&lt;/span&gt; | egrep &lt;span class="s2"&gt;"Base|Derived"&lt;/span&gt;
000000000000116a 0000000000000015 T Base::foo&lt;span class="o"&gt;()&lt;/span&gt; const
0000000000001180 0000000000000015 T Base::bar&lt;span class="o"&gt;()&lt;/span&gt; const
0000000000001196 0000000000000015 T Derived::foo&lt;span class="o"&gt;()&lt;/span&gt; const
00000000000011ac 0000000000000015 T Derived::bar&lt;span class="o"&gt;()&lt;/span&gt; const
00000000000011c1 000000000000000e T use&lt;span class="o"&gt;(&lt;/span&gt;Base const&amp;amp;&lt;span class="o"&gt;)&lt;/span&gt;
0000000000002042 0000000000000006 V typeinfo name &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000002048 0000000000000009 V typeinfo name &lt;span class="k"&gt;for &lt;/span&gt;Derived
0000000000003d68 0000000000000020 V vtable &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000003d88 0000000000000020 V vtable &lt;span class="k"&gt;for &lt;/span&gt;Derived
0000000000003da8 0000000000000010 V typeinfo &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000003db8 0000000000000018 V typeinfo &lt;span class="k"&gt;for &lt;/span&gt;Derived
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternative 2 : &lt;code&gt;readelf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;readelf &lt;span class="nt"&gt;--syms&lt;/span&gt; &lt;span class="nt"&gt;--demangle&lt;/span&gt; a.out | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;: &lt;span class="nt"&gt;-f2-&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | egrep &lt;span class="s2"&gt;"Base|Derived"&lt;/span&gt;
 000000000000116a    21 FUNC    GLOBAL DEFAULT   15 Base::foo&lt;span class="o"&gt;()&lt;/span&gt; const
 0000000000001180    21 FUNC    GLOBAL DEFAULT   15 Base::bar&lt;span class="o"&gt;()&lt;/span&gt; const
 0000000000001196    21 FUNC    GLOBAL DEFAULT   15 Derived::foo&lt;span class="o"&gt;()&lt;/span&gt; const
 00000000000011ac    21 FUNC    GLOBAL DEFAULT   15 Derived::bar&lt;span class="o"&gt;()&lt;/span&gt; const
 00000000000011c1    14 FUNC    GLOBAL DEFAULT   15 use&lt;span class="o"&gt;(&lt;/span&gt;Base const&amp;amp;&lt;span class="o"&gt;)&lt;/span&gt;
 0000000000003d68    32 OBJECT  WEAK   DEFAULT   22 vtable &lt;span class="k"&gt;for &lt;/span&gt;Base
 0000000000003d88    32 OBJECT  WEAK   DEFAULT   22 vtable &lt;span class="k"&gt;for &lt;/span&gt;Derived
 0000000000003da8    16 OBJECT  WEAK   DEFAULT   22 typeinfo &lt;span class="k"&gt;for &lt;/span&gt;Base
 0000000000003db8    24 OBJECT  WEAK   DEFAULT   22 typeinfo &lt;span class="k"&gt;for &lt;/span&gt;Derived
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To sort by addresses, we must remove the symbol number at the beginning of each line. Indeed, a line is formatted as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22: 0000000000001180    21 FUNC    GLOBAL DEFAULT   15 Base::bar() const
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that typeinfo name for &lt;code&gt;Base&lt;/code&gt; and &lt;code&gt;Derived&lt;/code&gt; are missing here (again, if you know why, leave a comment below!).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bytes in Vtables
&lt;/h2&gt;

&lt;p&gt;Vtables and typeinfo symbols reside in the &lt;code&gt;.data.rel.ro&lt;/code&gt; section. We need to examine the raw data of this section to understand their content. &lt;code&gt;readelf&lt;/code&gt; can produce a hexdump of a section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;readelf &lt;span class="nt"&gt;--hex-dump&lt;/span&gt; .data.rel.ro a.out

Hex dump of section &lt;span class="s1"&gt;'.data.rel.ro'&lt;/span&gt;:
  0x00003d68 00000000 00000000 a83d0000 00000000 .........&lt;span class="o"&gt;=&lt;/span&gt;......
  0x00003d78 6a110000 00000000 80110000 00000000 j...............
  0x00003d88 00000000 00000000 b83d0000 00000000 .........&lt;span class="o"&gt;=&lt;/span&gt;......
  0x00003d98 96110000 00000000 ac110000 00000000 ................
  0x00003da8 00000000 00000000 42200000 00000000 ........B ......
  0x00003db8 00000000 00000000 48200000 00000000 ........H ......
  0x00003dc8 a83d0000 00000000                   .&lt;span class="o"&gt;=&lt;/span&gt;......
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;These are little-endian hexadecimal data. Hence, &lt;code&gt;a83d0000 00000000&lt;/code&gt; on the last line is in fact 0x0000000000003da8.&lt;/li&gt;
&lt;li&gt;The same dump can be created with &lt;code&gt;objdump --section=.data.rel.ro --full-contents a.out&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's inspect these bytes.&lt;/p&gt;

&lt;p&gt;How? By navigating through the symbol table to obtain the addresses and sizes of the symbols, and utilizing hexdumps to find out the bytes at these addresses. We will then gain a better understanding of these symbols.&lt;/p&gt;

&lt;p&gt;Stay calm and take a deep breath, there will be a lot a hexadecimal numbers. &lt;/p&gt;

&lt;h3&gt;
  
  
  Vtables
&lt;/h3&gt;

&lt;p&gt;According to the symbol table, both vtables are 32-byte wide (this is 0x20 in hexadecimal) and their addresses are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0x0000000000003d68 for the vtable for &lt;code&gt;Base&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;0x0000000000003d88 for the vtable for &lt;code&gt;Derived&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since each line in the hexdump holds 16 bytes, we can deduce that, in the hexdump:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lines 1 and 2 show the vtable for &lt;code&gt;Base&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lines 3 and 4 show the vtable for &lt;code&gt;Derived&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components" rel="noopener noreferrer"&gt;ABI's specification&lt;/a&gt; (or this &lt;a href="https://llvm.org/devmtg/2021-11/slides/2021-RelativeVTablesinC.pdf" rel="noopener noreferrer"&gt;presentation&lt;/a&gt; on slide 5) explains the content of the vtable. Let's apply this knowledge to analyze the vtables, and match the dumped bytes to addresses in the symbol tables.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;Base&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dump&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00000000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000000000&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ptrdiff_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a83d0000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000003da8&lt;/td&gt;
&lt;td&gt;pointer to struct&lt;/td&gt;
&lt;td&gt;typeinfo for &lt;code&gt;Base&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6a110000 00000000&lt;/td&gt;
&lt;td&gt;0x000000000000116a&lt;/td&gt;
&lt;td&gt;function pointer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Base::foo const&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80110000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000001180&lt;/td&gt;
&lt;td&gt;function pointer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Base::bar const&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For &lt;code&gt;Derived&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dump&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00000000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000000000&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ptrdiff_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;b83d0000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000003db8&lt;/td&gt;
&lt;td&gt;pointer to struct&lt;/td&gt;
&lt;td&gt;typeinfo for &lt;code&gt;Derived&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;96110000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000001196&lt;/td&gt;
&lt;td&gt;function pointer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Derived::foo() const&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ac110000 00000000&lt;/td&gt;
&lt;td&gt;0x00000000000011ac&lt;/td&gt;
&lt;td&gt;function pointer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Derived::bar() const&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you may have guessed, if there were more virtual functions, the vtables would contain more function pointers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typeinfo
&lt;/h3&gt;

&lt;p&gt;The vtables point to the typeinfo objects, let's have a closer look at their contents.&lt;/p&gt;

&lt;p&gt;From the symbol table, we know that:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;th&gt;Address&lt;/th&gt;
&lt;th&gt;Size (hexa)&lt;/th&gt;
&lt;th&gt;Size (dec)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;typeinfo for &lt;code&gt;Base&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0x0000000000003da8&lt;/td&gt;
&lt;td&gt;0x10&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;typeinfo for &lt;code&gt;Derived&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0x0000000000003db8&lt;/td&gt;
&lt;td&gt;0x18&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In the hexdump of the section, we can deduce that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Line 5 shows the typeinfo for &lt;code&gt;Base&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lines 6 and 7 show the typeinfo for &lt;code&gt;Derived&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once again, we can match the dumped bytes with the data from the symbol table.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;Base&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dump&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00000000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000000000&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42200000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000002042&lt;/td&gt;
&lt;td&gt;typeinfo name for &lt;code&gt;Base&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For &lt;code&gt;Derived&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dump&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00000000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000000000&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;48200000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000002048&lt;/td&gt;
&lt;td&gt;typeinfo name for &lt;code&gt;Derived&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a83d0000 00000000&lt;/td&gt;
&lt;td&gt;0x0000000000003da8&lt;/td&gt;
&lt;td&gt;typeinfo for &lt;code&gt;Base&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you have probably guessed, the objects are &lt;a href="https://en.cppreference.com/w/cpp/types/type_info" rel="noopener noreferrer"&gt;implementations of &lt;code&gt;std::type_info&lt;/code&gt;&lt;/a&gt;. The ABI's specification includes a dedicated section for RTTI. For in-depth details, you may explore (the somewhat esoteric) part about &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti-layout" rel="noopener noreferrer"&gt;RTTI layout&lt;/a&gt;. You will see that &lt;code&gt;std::type_info&lt;/code&gt; has several subtypes, and that &lt;code&gt;__si_class_type_info&lt;/code&gt; is (in all likelihood) used here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typeinfo Names
&lt;/h3&gt;

&lt;p&gt;The remaining data we haven't explored yet are the names residing in the &lt;code&gt;.rodata&lt;/code&gt; section. This section is dedicated to store the data from our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;readelf &lt;span class="nt"&gt;--hex-dump&lt;/span&gt; .rodata a.out

Hex dump of section &lt;span class="s1"&gt;'.rodata'&lt;/span&gt;:
  0x00002000 01000200 42617365 203d3e20 666f6f28 ....Base &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; foo&lt;span class="o"&gt;(&lt;/span&gt;
  0x00002010 29004261 7365203d 3e206261 72282900 &lt;span class="o"&gt;)&lt;/span&gt;.Base &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; bar&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
  0x00002020 44657269 76656420 3d3e2066 6f6f2829 Derived &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; foo&lt;span class="o"&gt;()&lt;/span&gt;
  0x00002030 00446572 69766564 203d3e20 62617228 .Derived &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; bar&lt;span class="o"&gt;(&lt;/span&gt;
  0x00002040 29003442 61736500 37446572 69766564 &lt;span class="o"&gt;)&lt;/span&gt;.4Base.7Derived
  0x00002050 00                                  &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the right side of the dump, we find the ASCII interpretation of the hexadecimal values.&lt;/p&gt;

&lt;p&gt;Here, we see the strings printed in each function and the &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti-name" rel="noopener noreferrer"&gt;mangled names&lt;/a&gt; of the classes. Why do the mangled names contain 4 and 7? This simply corresponds to the length of the &lt;a href="https://en.wikipedia.org/wiki/Name_mangling#Complex_example" rel="noopener noreferrer"&gt;subsequent identifiers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable RTTI
&lt;/h2&gt;

&lt;p&gt;As a bonus, we will disable RTTI and observe the impact on the vtables.&lt;/p&gt;

&lt;p&gt;Modify your &lt;code&gt;CMakeLists.txt&lt;/code&gt; to add the appropriate option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;a.out PRIVATE
        -O1
        -fno-rtti
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the project has been recompiled, we can examine the symbol table again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;objdump &lt;span class="nt"&gt;--syms&lt;/span&gt; &lt;span class="nt"&gt;--demangle&lt;/span&gt; a.out | &lt;span class="nb"&gt;sort&lt;/span&gt; | egrep &lt;span class="s2"&gt;"Base|Derived"&lt;/span&gt;
000000000000116a g     F .text  0000000000000015              Base::foo&lt;span class="o"&gt;()&lt;/span&gt; const
0000000000001180 g     F .text  0000000000000015              Base::bar&lt;span class="o"&gt;()&lt;/span&gt; const
0000000000001196 g     F .text  0000000000000015              Derived::foo&lt;span class="o"&gt;()&lt;/span&gt; const
00000000000011ac g     F .text  0000000000000015              Derived::bar&lt;span class="o"&gt;()&lt;/span&gt; const
00000000000011c1 g     F .text  000000000000000e              use&lt;span class="o"&gt;(&lt;/span&gt;Base const&amp;amp;&lt;span class="o"&gt;)&lt;/span&gt;
0000000000003da0  w    O .data.rel.ro   0000000000000020              vtable &lt;span class="k"&gt;for &lt;/span&gt;Base
0000000000003dc0  w    O .data.rel.ro   0000000000000020              vtable &lt;span class="k"&gt;for &lt;/span&gt;Derived
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The size of the vtables remains unchanged, but all symbols related to type information are now absent.&lt;/p&gt;

&lt;p&gt;We can also examine the hexdump of the &lt;code&gt;.data.rel.ro&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;readelf &lt;span class="nt"&gt;--hex-dump&lt;/span&gt; .data.rel.ro a.out

Hex dump of section &lt;span class="s1"&gt;'.data.rel.ro'&lt;/span&gt;:
  0x00003da0 00000000 00000000 00000000 00000000 ................
  0x00003db0 6a110000 00000000 80110000 00000000 j...............
  0x00003dc0 00000000 00000000 00000000 00000000 ................
  0x00003dd0 96110000 00000000 ac110000 00000000 ................
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second double word in each vtables is now zero, to represent a null pointer, since there is no RTTI to point to.&lt;/p&gt;

&lt;p&gt;If you dump the &lt;code&gt;.rodata&lt;/code&gt; section, you will see that the type names are absent as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this episode, we delved into the bytes stored in the ELF file for the vtables. Their content is mostly dictated by the Itanium ABI followed by GCC. Vtables hold a pointer to RTTI (if enabled) along with pointers to all virtual functions. This was a basic case, with a single level of simple inheritance. I may cover more advanced cases in a further episode. &lt;/p&gt;

&lt;p&gt;In the next episode, we will explore how vtables are used at assembly level.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will publish the episodes as I write them. Subscribe to be notified! 🥳&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>cpp</category>
      <category>computerscience</category>
      <category>todayilearned</category>
      <category>todayisearched</category>
    </item>
    <item>
      <title>vtables under the surface | Episode 1 - Concepts</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Fri, 05 Jan 2024 09:04:49 +0000</pubDate>
      <link>https://dev.to/pgradot/vtables-under-the-surface-3foa</link>
      <guid>https://dev.to/pgradot/vtables-under-the-surface-3foa</guid>
      <description>&lt;p&gt;If you've been around C++ for a while, you've likely come across the terms "vtable", "virtual table" or "&lt;a href="https://en.wikipedia.org/wiki/Virtual_method_table" rel="noopener noreferrer"&gt;virtual method table&lt;/a&gt;". Vtables are not part of the C++ standard, even though this concept pops up almost immediately when you try to understand how virtual functions actually work in C++. Indeed, vtables are the most common implementation of polymorphism in C++.&lt;/p&gt;

&lt;p&gt;You may also have already encountered a cryptic compilation error like "undefined reference to &lt;code&gt;vtable for MyClass&lt;/code&gt;". This may have left you perplexed because you didn't explicitly create anything named "vtable" in your code. This error signals that, under the hood, the compiler generates vtables to handle virtual functions. If you're curious about this error, here is a &lt;a href="https://stackoverflow.com/questions/3065154/undefined-reference-to-vtable" rel="noopener noreferrer"&gt;good discussion&lt;/a&gt; on stackoverflow (the &lt;a href="https://stackoverflow.com/a/57504289" rel="noopener noreferrer"&gt;second answer&lt;/a&gt; is particularly enlightening).&lt;/p&gt;

&lt;p&gt;In this series, we're going to the lion's den and explore how a vtable works at the byte and assembly levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;As mentioned in the introduction, we'll be discussing implementation details. By definition, these details may vary from one compiler to another or from one OS to another. They may even change in the next version of the same compiler for the same OS.&lt;/p&gt;

&lt;p&gt;However, most major compilers (except MSVC) follow the &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/" rel="noopener noreferrer"&gt;Itanium C++ ABI&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Itanium C++ ABI is an ABI for C++. As an ABI, it gives precise rules for implementing the language, ensuring that separately-compiled parts of a program can successfully interoperate. Although it was initially developed for the Itanium architecture, it is not platform-specific and can be layered portably on top of an arbitrary C ABI. Accordingly, it is used as the standard C++ ABI for many major operating systems on all major architectures, and is implemented in many major C++ compilers, including GCC and Clang.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The ABI has a &lt;a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable" rel="noopener noreferrer"&gt;section about vtables&lt;/a&gt;, so using any compiler following this ABI should yield similar implementation details.&lt;/p&gt;

&lt;p&gt;In this series, I will use GCC 12.2.0 on Debian BookWorm (unless stated otherwise).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Here is a code that will serve as the foundation for the discussion in the series (at least for the first episodes). It is split into 3 different files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;code.hpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma once
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;dummy_base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;dummy_derived&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;code.cpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"code.hpp"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Base =&amp;gt; foo()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Base =&amp;gt; bar()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Derived =&amp;gt; foo()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Derived =&amp;gt; bar()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;main.cpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"code.hpp"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is a typical example of polymorphism using virtual functions. &lt;code&gt;use()&lt;/code&gt; receives a reference to a &lt;code&gt;Base&lt;/code&gt; object. At runtime, dynamic dispatch selects and calls &lt;code&gt;Derived::foo()&lt;/code&gt; and the program prints &lt;code&gt;Derived =&amp;gt; foo()&lt;/code&gt;. Looking at this code, you don't see any vtables. We will analyze the generated binary and find them later in the series. &lt;/p&gt;

&lt;h2&gt;
  
  
  Build and Run
&lt;/h2&gt;

&lt;p&gt;You can easily build the program with CMake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;cmake_minimum_required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;VERSION 3.25&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;vtables&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;add_executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;a.out
        main.cpp
        code.cpp
        code.hpp
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;a.out PRIVATE
        -O1
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the root directory of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cmake &lt;span class="nt"&gt;-B&lt;/span&gt; build &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build
&lt;span class="nv"&gt;$ &lt;/span&gt;./build/a.out 
Derived &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; foo&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separated source files avoid possible compiler optimizations.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-O1&lt;/code&gt; generates an assembly code that is much easier to read and understand than &lt;code&gt;-O0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  We're Ready
&lt;/h2&gt;

&lt;p&gt;We are now ready. Let's dive into vtables!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will publish the episodes as I write them. Subscribe to be notified! 🎉&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>cpp</category>
      <category>computerscience</category>
      <category>todayisearched</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Just in case: Debian Bookworm comes with a buggy GCC</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Fri, 15 Dec 2023 11:27:09 +0000</pubDate>
      <link>https://dev.to/pgradot/just-in-case-debian-bookworm-comes-with-a-buggy-gcc-2e9b</link>
      <guid>https://dev.to/pgradot/just-in-case-debian-bookworm-comes-with-a-buggy-gcc-2e9b</guid>
      <description>&lt;p&gt;Last month, I embarked on a new project. I set up a new computer with the latest Debian version, installed my favorites tools, and was all set to code. My first task was to migrate all the repositories from C++14 to C++20. While it might seem as straightforward as updating all the &lt;code&gt;CMakeLists.txt&lt;/code&gt; to replace &lt;code&gt;set (CMAKE_CXX_STANDARD 14)&lt;/code&gt; with &lt;code&gt;set (CMAKE_CXX_STANDARD 20)&lt;/code&gt; reality proved otherwise (and I knew it would).&lt;/p&gt;

&lt;p&gt;Among the funny things I encountered (&lt;a href="https://en.cppreference.com/w/cpp/experimental/basic_string_view" rel="noopener noreferrer"&gt;such as &lt;code&gt;std::experimental::basic_string_view::to_string()&lt;/code&gt;&lt;/a&gt; being &lt;a href="https://en.cppreference.com/w/cpp/string/basic_string_view" rel="noopener noreferrer"&gt;missing in &lt;code&gt;std::basic_string_view&lt;/code&gt;&lt;/a&gt;), the most cryptic error was something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/include/c++/12/bits/char_traits.h:431:56: warning: ‘void* __builtin_memcpy(void*, const void*, long unsigned int)’ accessing 9223372036854775810 or more bytes at offsets -4611686018427387902 and [-4611686018427387903, 4611686018427387904] may overlap up to 9223372036854775813 bytes at offset -3 [-Wrestrict]

  431 |         return static_cast&amp;lt;char_type*&amp;gt;(__builtin_memcpy(__s1, __s2, __n));

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a known bug in GCC and it affects only the 12.x branch. It's (&lt;a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329" rel="noopener noreferrer"&gt;Bug 105329 - [12/13/14 Regression] Bogus restrict warning when assigning 1-char string literal to std::string since r12-3347-g8af8abfbbace49e6&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Encountering this bug might not be an everyday occurrence, but it's quite easy to trigger it. Unfortunately, as you have guessed, Debian Bookworm ships with this problematic version of GCC. Bookworm is the &lt;a href="https://www.debian.org/releases/bookworm/" rel="noopener noreferrer"&gt;latest stable version&lt;/a&gt; of Debian, released in June this year. Previous stable versions, Buster and Bulleye, came with &lt;a href="https://packages.debian.org/buster/gcc" rel="noopener noreferrer"&gt;GCC 8&lt;/a&gt; and &lt;a href="https://packages.debian.org/bullseye/gcc" rel="noopener noreferrer"&gt;GCC 10&lt;/a&gt; respectively. Since Debian releases a new stable version every two years, if you are using Debian like me, we may have to deal with this bug for an extended period.&lt;/p&gt;

&lt;p&gt;In this article, I will explain how you can trigger this bug and how you can avoid it. It's also an opportunity to revisit various techniques for circumventing spurious warnings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conditions to Trigger the Bug
&lt;/h2&gt;

&lt;p&gt;Beyond from the source code itself, specific build conditions are necessary to trigger the bug.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You must use GCC 12, obviously. GCC 11 wasn't affected and the bug is fixed in GCC 13.&lt;/li&gt;
&lt;li&gt;Optimizations must be enabled. You must use either &lt;code&gt;-O2&lt;/code&gt; or &lt;code&gt;-O3&lt;/code&gt;. &lt;code&gt;-O0&lt;/code&gt;, &lt;code&gt;-O1&lt;/code&gt; and &lt;code&gt;-Os&lt;/code&gt; don't seem to concerned. If you set &lt;code&gt;CMAKE_BUILD_TYPE&lt;/code&gt; to &lt;code&gt;Release&lt;/code&gt;, CMake will add &lt;code&gt;-O3&lt;/code&gt;. Your release builds will then be susceptible, unlike debug builds.&lt;/li&gt;
&lt;li&gt;You must use C++20 and C++23. C++17 is unaffected.&lt;/li&gt;
&lt;li&gt;You must pass the &lt;code&gt;-Wrestrict&lt;/code&gt; flag since it causes the warning. It is included in &lt;code&gt;-Wall&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means your build may break simply by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updating GCC (it happened to &lt;a href="https://github.com/google/googletest/issues/4108" rel="noopener noreferrer"&gt;GoogleTest&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Changing from debug to release mode (but I guess your CI always builds in release mode, right?).&lt;/li&gt;
&lt;li&gt;Switching for C++17 or below to C++20 or above (and I encourage you to regularly upgrade to the new standard version).&lt;/li&gt;
&lt;li&gt;Enabling warnings (no, I can't believe you had lived without &lt;code&gt;-Wall&lt;/code&gt; so far).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use the word "break" because most release builds also use &lt;code&gt;-Werror&lt;/code&gt; to turn warnings into errors, ensuring they are absolutely noticeable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code Itself
&lt;/h2&gt;

&lt;p&gt;Oh, poor boyz and girlz... The code is so simple.&lt;/p&gt;

&lt;p&gt;Here is a CMake &lt;code&gt;CMakeLists.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;cmake_minimum_required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;VERSION 3.27&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;buggy&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;add_executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;buggy main.cpp&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;buggy PRIVATE -Wall&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_compile_features&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;buggy PRIVATE cxx_std_20&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here a &lt;code&gt;main.cpp&lt;/code&gt; that will raise the dreaded warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// oopsi...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is another case that emits the warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// oopsi...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The string literal must be single byte and must be the left-hand-side operand. The following lines are fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ab"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ab"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Circumvention Measures
&lt;/h2&gt;

&lt;p&gt;The discussion for &lt;a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329" rel="noopener noreferrer"&gt;bug 105329&lt;/a&gt; clearly indicates, in comments 26 and 27, than the 12 branch won't be fixed. The solution is hence to move to GCC 13. Alas! Debian will probably not change the major version of GCC in Bookworm. The next release, Trixie, is currently in testing mode and &lt;a href="https://packages.debian.org/testing/devel/gcc" rel="noopener noreferrer"&gt;comes with GCC 13&lt;/a&gt;, so perhaps one day it will be available in the &lt;a href="https://backports.debian.org/" rel="noopener noreferrer"&gt;backports&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fortunately, there are easy workarounds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disable &lt;code&gt;-Wrestrict&lt;/code&gt; globally
&lt;/h3&gt;

&lt;p&gt;As a temporary solution, you may add &lt;code&gt;-Wno-restrict&lt;/code&gt; to your build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;buggy PRIVATE -Wall -Wno-restrict&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is extreme and I highly discourage pushing such a change to a &lt;code&gt;develop&lt;/code&gt; or a &lt;code&gt;master&lt;/code&gt;/&lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disable &lt;code&gt;-Wrestrict&lt;/code&gt; for some files
&lt;/h3&gt;

&lt;p&gt;Another solution I also consider temporary is to disable the warning but only for a particular set of files.&lt;/p&gt;

&lt;p&gt;You can use CMake for this, &lt;a href="https://dev.to/younup/cmake-on-stm32-episode-3-handle-warnings-in-3rd-party-files-4gg4"&gt;especially if you can't change these sources files&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;set_source_files_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        main.cpp
        PROPERTIES
        COMPILE_FLAGS -Wno-restrict&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can use a pragma at the beginning of each file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma GCC diagnostic ignored "-Wrestrict"
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Disable &lt;code&gt;-Wrestrict&lt;/code&gt; locally
&lt;/h3&gt;

&lt;p&gt;Disabling the warning only for a couple of lines is a more acceptable solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wrestrict"
&lt;/span&gt;    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#pragma GCC diagnostic pop
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had to use this technique around a &lt;code&gt;#include &amp;lt;boost/test/data/test_case.hpp&amp;gt;&lt;/code&gt; because &lt;code&gt;BOOST_DATA_TEST_CASE&lt;/code&gt; triggered the bug. This solution is very verbose and reduce your code's readability. Think twice before choosing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Note about Clang
&lt;/h3&gt;

&lt;p&gt;Clang does support &lt;code&gt;#pragma GCC&lt;/code&gt; but it doesn't support &lt;code&gt;-Wrestrict&lt;/code&gt;... It means that the previous codes will raise a warning or error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;clang++ main.cpp &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Werror&lt;/span&gt;
main.cpp:7:32: error: unknown warning group &lt;span class="s1"&gt;'-Wrestrict'&lt;/span&gt;, ignored &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Werror&lt;/span&gt;,-Wunknown-warning-option]
&lt;span class="c"&gt;#pragma GCC diagnostic ignored "-Wrestrict"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want your code to compile both with GCC and Clang, you will need some extra preprocessor tricks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifndef __clang__
#pragma GCC diagnostic ignored "-Wrestrict"
#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros" rel="noopener noreferrer"&gt;Clang's builtin-macros&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The preferred solution: change the code
&lt;/h2&gt;

&lt;p&gt;The solution with &lt;code&gt;set_source_files_properties()&lt;/code&gt; may be acceptable if you plan to switch to GCC 13 soon. Otherwise, if you plan to use GCC 12 for a long time, just change your code.&lt;/p&gt;

&lt;p&gt;Remember the two faulty lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply change them to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simply makes implicit conversions explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;At the end of the day, the warning message is quite scary, but the code can easily be changed to avoid the bug. Apart from changing the code to avoid this particular issue with GCC 12, we also discussed several techniques you may use to mitigate spurious warnings in your code.&lt;/p&gt;

&lt;p&gt;This is not the first time I run into a compiler's bug. It's always so much fun (sarcasm indented) 😆&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cpp</category>
      <category>linux</category>
      <category>todayisearched</category>
    </item>
    <item>
      <title>Des enumérations encore plus puissantes avec Python 3.11</title>
      <dc:creator>Pierre Gradot</dc:creator>
      <pubDate>Thu, 08 Jun 2023 14:27:10 +0000</pubDate>
      <link>https://dev.to/younup/des-enumerations-encore-plus-puissantes-avec-python-311-569f</link>
      <guid>https://dev.to/younup/des-enumerations-encore-plus-puissantes-avec-python-311-569f</guid>
      <description>&lt;p&gt;Python 3.11 est sorti à la fin de l'année dernière. Comme souvent, il y a &lt;a href="https://docs.python.org/3/whatsnew/3.11.html" rel="noopener noreferrer"&gt;beaucoup de nouveautés&lt;/a&gt;. Une section a plus attiré mon œil que les autres : il y a eu &lt;a href="https://docs.python.org/3/whatsnew/3.11.html#enum" rel="noopener noreferrer"&gt;beaucoup de changements et d'ajouts sur les enums&lt;/a&gt; ! Bon, la vérité, c'est que je cherchais comment faire quelque chose d'assez spécifique et j'ai vu que Python 3.11 apportait justement cette fonctionnalité... J'ai bien sûr immédiatement mis à jour mon interpréteur pour tester ça !&lt;/p&gt;

&lt;p&gt;Dans cet article, je vous présente les nouveautés qui me semblent les plus prometteuses.&lt;/p&gt;

&lt;h2&gt;
  
  
  3.11 : une version importante pour le module &lt;code&gt;enum&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Le module &lt;a href="https://docs.python.org/3/library/enum.html" rel="noopener noreferrer"&gt;&lt;code&gt;enum&lt;/code&gt;&lt;/a&gt; est très stable depuis son apparition en &lt;a href="https://www.python.org/downloads/release/python-340/" rel="noopener noreferrer"&gt;version 3.4&lt;/a&gt; et l'implémentation de la &lt;a href="https://peps.python.org/pep-0435/" rel="noopener noreferrer"&gt;PEP 435&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Au début de la documentation, on voit :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;New in version 3.6: &lt;code&gt;Flag&lt;/code&gt;, &lt;code&gt;IntFlag&lt;/code&gt;, &lt;code&gt;auto&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;New in version 3.11: &lt;code&gt;StrEnum&lt;/code&gt;, &lt;code&gt;EnumCheck&lt;/code&gt;, &lt;code&gt;ReprEnum&lt;/code&gt;, &lt;code&gt;FlagBoundary&lt;/code&gt;, &lt;code&gt;property&lt;/code&gt;, &lt;code&gt;member&lt;/code&gt;, &lt;code&gt;nonmember&lt;/code&gt;, &lt;code&gt;global_enum&lt;/code&gt;, &lt;code&gt;show_flag_values&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La version 3.11 est donc une version qui apporte beaucoup de nouveautés. 9 sont listées au début de la documentation, mais il y en a une 10ᵉ qu'on trouve plus bas : &lt;code&gt;verify()&lt;/code&gt;. En vrai, &lt;a href="https://github.com/python/cpython/issues/98298" rel="noopener noreferrer"&gt;la documentation est loin d'être parfaite&lt;/a&gt;, mais on s'en sort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streets of Rage
&lt;/h2&gt;

&lt;p&gt;Pour le fun, j'ai décidé d'utiliser des exemples basés sur Streets of Rage. Quoi ?! Tu connais pas Streets of Rage ?! Mais fonce vite &lt;a href="https://en.wikipedia.org/wiki/Streets_of_Rage_2" rel="noopener noreferrer"&gt;agrandir&lt;/a&gt; ta culture pop !&lt;/p&gt;

&lt;p&gt;Mon épisode préféré est clairement le &lt;a href="https://streetsofrage.fandom.com/wiki/Streets_of_Rage_2" rel="noopener noreferrer"&gt;2&lt;/a&gt;, mais j'utiliserai un peu le &lt;a href="https://streetsofrage.fandom.com/wiki/Streets_of_Rage" rel="noopener noreferrer"&gt;1&lt;/a&gt; aussi !&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce qu'on pouvait déjà faire avant Python 3.11
&lt;/h2&gt;

&lt;p&gt;Si on souhaite lister les niveaux de Streets of Rage 2, il est possible de faire une énumération comme celle-ci depuis Python 3.4 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DOWNTOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;BRIDGE_CONSTRUCTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;AMUSEMENT_PARK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;STADIUM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="c1"&gt;# ... et plusieurs autres encore !
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Elles sont très permissives et on peut par exemple faire quelque chose comme :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DOWNTOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;BRIDGE_CONSTRUCTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;AMUSEMENT_PARK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;three&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;STADIUM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Il est donc possible d'avoir des valeurs de types différents. Ça peut être pratique dans certains cas, mais on souhaite en général imposer le type des valeurs, comme dans notre exemple dans lequel chaque niveau correspond à un numéro. C'est pour cette raison que &lt;code&gt;IntEnum&lt;/code&gt; a été introduite en Python 3.6 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IntEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DOWNTOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;BRIDGE_CONSTRUCTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;AMUSEMENT_PARK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;STADIUM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;four&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On obtient une exception à l'exécution : &lt;code&gt;ValueError: invalid literal for int() with base 10: 'four'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Notez que si on a &lt;code&gt;STADIUM = '4'&lt;/code&gt; (notez les &lt;em&gt;simple quotes&lt;/em&gt; autour du 4), le code fonctionne. En effet, comme l'indique l'exception, &lt;code&gt;IntEnum&lt;/code&gt; utilise &lt;code&gt;int()&lt;/code&gt; pour obtenir la valeur et il s'avère que &lt;code&gt;int('4') == 4&lt;/code&gt;. On peut ainsi utiliser comme &lt;em&gt;initializer&lt;/em&gt; une instance d'une classe qui fournit une méthode &lt;code&gt;def __int__(self) -&amp;gt; int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IntEnum&lt;/code&gt; est en fait une "&lt;em&gt;mixed enum&lt;/em&gt;". Le principe des &lt;em&gt;mixed enums&lt;/em&gt; est de faire un héritage (multiple) d'un type souhaité &lt;code&gt;T&lt;/code&gt; et d'&lt;code&gt;enum&lt;/code&gt;. Ce n'est pas très bien documenté à mon goût, mais on trouve des explications dans le &lt;a href="https://docs.python.org/3/howto/enum.html" rel="noopener noreferrer"&gt;"Enum HOWTO"&lt;/a&gt; (&lt;a href="https://docs.python.org/3/howto/enum.html#others" rel="noopener noreferrer"&gt;ici&lt;/a&gt; et un peu &lt;a href="https://docs.python.org/3/howto/enum.html#restricted-enum-subclassing" rel="noopener noreferrer"&gt;là&lt;/a&gt;). On obtient ainsi une énumération dont les valeurs sont obligatoirement du même type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Après ces rappels, on va s'attarder dans la suite aux changements apportés par la version 3.11.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;ReprEnum&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Si on hérite &lt;code&gt;ReprEnum&lt;/code&gt; plutôt que &lt;code&gt;Enum&lt;/code&gt;, on créé une énumération pour laquelle la conversion en &lt;em&gt;string&lt;/em&gt; de ses valeurs sera alors la même que la conversion du &lt;em&gt;mixed-in type&lt;/em&gt;. La &lt;a href="https://docs.python.org/3.11/library/enum.html#enum.ReprEnum" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; précise :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ReprEnum&lt;/code&gt; uses the &lt;code&gt;repr()&lt;/code&gt; of &lt;code&gt;Enum&lt;/code&gt;, but the &lt;code&gt;str()&lt;/code&gt; of the mixed-in data type.&lt;/p&gt;

&lt;p&gt;(...)&lt;/p&gt;

&lt;p&gt;Inherit from &lt;code&gt;ReprEnum&lt;/code&gt; to keep the &lt;code&gt;str()&lt;/code&gt; / &lt;code&gt;format()&lt;/code&gt; of the mixed-in data type instead of using the &lt;code&gt;Enum&lt;/code&gt;-default &lt;code&gt;str()&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  L'affichage des &lt;code&gt;IntEnum&lt;/code&gt;s change à cause de &lt;code&gt;ReprEnum&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.python.org/3/whatsnew/3.11.html" rel="noopener noreferrer"&gt;What’s New In Python 3.11&lt;/a&gt; nous dit :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Changed &lt;code&gt;IntEnum&lt;/code&gt; (...) to now inherit from ReprEnum, so their &lt;code&gt;str()&lt;/code&gt; output now matches &lt;code&gt;format()&lt;/code&gt; (both &lt;code&gt;str(AnIntEnum.ONE)&lt;/code&gt; and &lt;code&gt;format(AnIntEnum.ONE)&lt;/code&gt; return &lt;code&gt;'1'&lt;/code&gt;, whereas before &lt;code&gt;str(AnIntEnum.ONE)&lt;/code&gt; returned &lt;code&gt;'AnIntEnum.ONE'&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Regardons ce que ça donne avec notre énumération &lt;code&gt;Stages(IntEnum)&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;member&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWNTOWN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWNTOWN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWNTOWN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;str()&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWNTOWN&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;repr()&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWNTOWN&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;f-str&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWNTOWN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En 3.10 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;member   Stages.DOWNTOWN
name     DOWNTOWN
value    1
str()    Stages.DOWNTOWN
repr()   &amp;lt;Stages.DOWNTOWN: 1&amp;gt;
f-str    1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Affichage modifié en 3.11 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;member   1
name     DOWNTOWN
value    1
str()    1
repr()   &amp;lt;Stages.DOWNTOWN: 1&amp;gt;
f-str    1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personnellement, je trouve ça plus logique, mais ce changement peut avoir des conséquences sur un code existant !&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;StrEnum&lt;/code&gt;, pour faire comme &lt;code&gt;IntEnum&lt;/code&gt; mais avec des &lt;em&gt;strings&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;On a souvent besoin de faire une énumération qui ne contient que des &lt;em&gt;strings&lt;/em&gt;, par exemple pour lister les personnages du jeu :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Characters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StrEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;AXEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Axel Stone&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;BLAZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Blaze Fielding&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Max Thunder&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;SKATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Eddie &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Hunter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;StrEnum&lt;/code&gt; hérite de &lt;code&gt;ReprEnum&lt;/code&gt;, ce qui implique que &lt;code&gt;print(str(Characters.BLAZE))&lt;/code&gt; et &lt;code&gt;print(f'{Characters.BLAZE}')&lt;/code&gt; affichent &lt;code&gt;Blaze Fielding&lt;/code&gt;. Si on avait fait &lt;code&gt;Characters(Enum)&lt;/code&gt;, l'affichage aurait donné &lt;code&gt;Characters.BLAZE&lt;/code&gt;. Comme pour &lt;code&gt;IntEnum&lt;/code&gt;, je trouve cet affichage logique.&lt;/p&gt;

&lt;p&gt;On peut utiliser &lt;code&gt;auto()&lt;/code&gt; avec &lt;code&gt;StrEnum&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Characters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StrEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="n"&gt;SKATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;str(Characters.SKATE))&lt;/code&gt; sera alors &lt;code&gt;skate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Il était déjà possible de faire un équivalent de &lt;code&gt;StrEnum&lt;/code&gt; avant Python 3.11, avec une simple &lt;em&gt;enum&lt;/em&gt; mais le typage était moins fort. On pouvait par exemple faire :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Characters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;AXEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Axel Stone&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;BLAZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Blaze Fielding&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Max Thunder&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;SKATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et ça passait crème. En effet, il est possible de construire une &lt;em&gt;string&lt;/em&gt; à partir de 8 avec &lt;code&gt;str(8)&lt;/code&gt;. Ce n'est pas dit dans la doc, mais on peut regarder l'implémentation de &lt;code&gt;StrEnum&lt;/code&gt; dans &lt;code&gt;enum.py&lt;/code&gt; et on voit que le constructeur est redéfini et vérifie explicitement le typage avec des &lt;code&gt;isinstance(..., str)&lt;/code&gt;. Ce n'est pas le cas de &lt;code&gt;IntEnum&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plus de vérifications avec le décorateur &lt;code&gt;@verify&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@unique&lt;/code&gt; est présent depuis le début du module &lt;code&gt;enum&lt;/code&gt; et permet de s'assurer que chaque membre a une valeur... unique ! 😂&lt;/p&gt;

&lt;p&gt;C'est très bien pour définir les niveaux du jeu et s'assurer qu'ils ont tous un numéro différent. Exemple :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@unique&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IntEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DOWNTOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;BRIDGE_CONSTRUCTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;AMUSEMENT_PARK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;STADIUM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce code génère une exception : &lt;code&gt;ValueError: duplicate values found in &amp;lt;enum 'Stages'&amp;gt;: STADIUM -&amp;gt; AMUSEMENT_PARK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Un nouveau décorateur, &lt;a href="https://docs.python.org/3/library/enum.html#enum.verify" rel="noopener noreferrer"&gt;&lt;code&gt;@verify&lt;/code&gt;&lt;/a&gt;, est apparu en 3.11 :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;code&gt;class&lt;/code&gt; decorator specifically for enumerations. Members from &lt;code&gt;EnumCheck&lt;/code&gt; are used to specify which constraints should be checked on the decorated enumeration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Il prend donc en paramètres des &lt;a href="https://docs.python.org/3/library/enum.html#enum.EnumCheck" rel="noopener noreferrer"&gt;&lt;code&gt;EnumCheck&lt;/code&gt;s&lt;/a&gt; :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;EnumCheck&lt;/em&gt; contains the options used by the &lt;code&gt;verify()&lt;/code&gt; decorator to ensure various constraints; failed constraints result in a &lt;code&gt;ValueError&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seuls &lt;a href="https://docs.python.org/3/library/enum.html#enum.EnumCheck.UNIQUE" rel="noopener noreferrer"&gt;&lt;code&gt;UNIQUE&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.python.org/3/library/enum.html#enum.EnumCheck.CONTINUOUS" rel="noopener noreferrer"&gt;&lt;code&gt;CONTINUOUS&lt;/code&gt;&lt;/a&gt; et &lt;a href="https://docs.python.org/3/library/enum.html#enum.EnumCheck.NAMED_FLAGS" rel="noopener noreferrer"&gt;&lt;code&gt;NAMED_FLAGS&lt;/code&gt;&lt;/a&gt; sont disponibles pour le moment. &lt;code&gt;@verify(UNIQUE)&lt;/code&gt; est équivalent à &lt;code&gt;@unique&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On peut passer plusieurs flags en paramètres, ce qui est parfait pour notre exemple :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CONTINUOUS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IntEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DOWNTOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;BRIDGE_CONSTRUCTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;AMUSEMENT_PARK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;STADIUM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Une exception nous prévient qu'il manque une valeur : &lt;code&gt;ValueError: invalid enum 'Stages': missing values 4&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendre les membres accessibles dans le namespace global
&lt;/h2&gt;

&lt;p&gt;Pour accéder à un membre, il faut normalement y accéder via la classe : &lt;code&gt;Stages.STADIUM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dans certains cas (et avec les éventuels risques de &lt;em&gt;name clashes&lt;/em&gt; qui vont avec), vous pourriez souhaitez utiliser directement &lt;code&gt;STADIUM&lt;/code&gt;. C'est possible à partir de Python 3.11, en annotant votre classe avec &lt;code&gt;@global_enum&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contrôler ce qui est membre et ce qui n'est pas membre
&lt;/h2&gt;

&lt;p&gt;Deux &lt;a href="https://docs.python.org/3.11/library/enum.html#enum.member" rel="noopener noreferrer"&gt;nouveaux décorateurs&lt;/a&gt; permettent de contrôler explicitement ce qui est membre de l'énumération et ce qui ne l'est pas :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;@enum.member&lt;/code&gt;&lt;br&gt;
A decorator for use in enums: its target will become a member.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@enum.nonmember&lt;/code&gt;&lt;br&gt;
A decorator for use in enums: its target will not become a member.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quand on parle de membres d'une énumération, on parle de ses différentes valeurs possibles.&lt;/p&gt;

&lt;p&gt;Ce décorateur &lt;code&gt;@member&lt;/code&gt; est très pratique pour définir une énumération dont les valeurs sont des fonctions.&lt;/p&gt;

&lt;p&gt;Pour Streets of Rage 2, il nous faut par exemple une énumération des 3 actions de base que peut faire un personnage. Une fonction est un bon type pour représenter une action. Par défaut, une fonction définie dans une classe dérivant de &lt;code&gt;Enum&lt;/code&gt; est une &lt;em&gt;static method&lt;/em&gt;. Ainsi, le code suivant ne fait pas ce qu'on souhaiterait, car il crée une énumération sans valeur :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;special_move&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Special move, massive damage!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Attack? OK! Punch!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;jump&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The floor is lava! Jump!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce code affiche :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[]
Attack? OK! Punch!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour corriger ça, il suffit d'annoter les fonctions :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@member&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;special_move&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Special move, massive damage!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@member&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Attack? OK! Punch!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@member&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;jump&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The floor is lava! Jump!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On obtient cette fois :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[&amp;lt;Controls.special_move: &amp;lt;function Controls.special_move at 0x0000015B0080AD40&amp;gt;&amp;gt;,
        &amp;lt;Controls.attack: &amp;lt;function Controls.attack at 0x0000015B00778680&amp;gt;&amp;gt;,
        &amp;lt;Controls.jump: &amp;lt;function Controls.jump at 0x0000015B00822200&amp;gt;&amp;gt;]
Attack? OK! Punch!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parfait ! Notez bien que &lt;code&gt;Controls.attack&lt;/code&gt; n'est pas &lt;em&gt;callable&lt;/em&gt; (car c'est le membre de l'énumération) et qu'il faut utiliser &lt;code&gt;.value&lt;/code&gt; pour accéder réellement à la fonction.&lt;/p&gt;

&lt;p&gt;À l'inverse, si vous voulez qu'une donnée soit statique à la classe, il faut utiliser &lt;code&gt;@nonmember()&lt;/code&gt;. La syntaxe est un peu surprenante (je trouve) et la documentation officielle n'en donne aucun exemple. En voici donc un petit pour la route :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Characters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StrEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;playable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;nonmember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;AXEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Axel Stone&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;BLAZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Blaze Fielding&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Max Thunder&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;SKATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Eddie &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Hunter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;playable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comme toujours en Python, un champ de la classe est accessible via ses membres, donc on peut utiliser &lt;code&gt;Characters.SKATE.playable&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Il y a beaucoup de nouveautés intéressantes dans cette version de Python 3.11 ! Quand ton langage principal est C++, où les &lt;a href="https://en.cppreference.com/w/cpp/language/enum" rel="noopener noreferrer"&gt;enumérations&lt;/a&gt; sont vraiment très basiques, tu es comme un enfant dans un magasin de bonbons ! Je regrette quand même une documentation pas ouf (certaines features sont très mal, voire pas documentées) et des trucs trop bizarres (comme &lt;a href="https://docs.python.org/3/library/enum.html#enum.show_flag_values" rel="noopener noreferrer"&gt;show_flag_values()&lt;/a&gt; qui n'est pas ajouté à &lt;code&gt;__all__&lt;/code&gt; et dont l'utilisabilité est vraiment mauvaise). Gageons que ça s'améliorera dans les prochaines versions et profitons dès maintenant de cette puissance supplémentaire dans le package &lt;code&gt;enum&lt;/code&gt; !&lt;/p&gt;

</description>
      <category>programming</category>
      <category>todayilearned</category>
      <category>python</category>
    </item>
  </channel>
</rss>
