<?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: Mr. VyM</title>
    <description>The latest articles on DEV Community by Mr. VyM (@mrvym).</description>
    <link>https://dev.to/mrvym</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%2F1338506%2F2561be98-ab3e-4a8b-b0d8-08bea7fe29b5.png</url>
      <title>DEV Community: Mr. VyM</title>
      <link>https://dev.to/mrvym</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrvym"/>
    <language>en</language>
    <item>
      <title>Tester c'est tricher, compiler c'est douter</title>
      <dc:creator>Mr. VyM</dc:creator>
      <pubDate>Fri, 10 Jan 2025 13:42:59 +0000</pubDate>
      <link>https://dev.to/mrvym/tester-cest-tricher-compiler-cest-douter-h59</link>
      <guid>https://dev.to/mrvym/tester-cest-tricher-compiler-cest-douter-h59</guid>
      <description>&lt;p&gt;Dans cet article, nous allons voir le concept de Continuous Integration (CI), son intérêt et ses inconvénients et une démonstration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Histoire
&lt;/h2&gt;

&lt;p&gt;Mais d'abord, comme à mon habitude, un petit point histoire.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En 1999, Kent Beck a approfondi le sujet dans son premier livre sur l'Extreme Programming. En 2001, CruiseControl, l'un des premiers outils open-source de CI, a vu le jour.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Mais why ?
&lt;/h2&gt;

&lt;p&gt;Le but d'une CI est de faire des tests automatisés à chaque commit. Cela garantit que le code reste fonctionnel en permanence. On appelle cela une Continuous Integration car, à chaque modification, le code est vérifié pour s'assurer qu'il n'y a pas de régressions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Détection précoce des erreurs&lt;/strong&gt; : Les problèmes sont identifiés rapidement, ce qui permet de réagir sans attendre.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amélioration de la qualité&lt;/strong&gt; : En testant systématiquement, on garantit un code plus robuste.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gain de temps&lt;/strong&gt; : Les pipelines automatisés réduisent la nécessité de tests manuels répétitifs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coût initial&lt;/strong&gt; : Mettre en place une CI peut demander des efforts et des compétences initiales importantes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temps d’exécution&lt;/strong&gt; : Les pipelines complexes peuvent rallonger le temps avant qu'un développeur puisse valider son code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fonctionnement
&lt;/h2&gt;

&lt;p&gt;Avant de voir le fonctionnement, un petit lexique :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jobs&lt;/strong&gt; : Une instance d'un conteneur (souvent Docker) qui exécute un script. Cela peut inclure des commandes, des tests ou des actions simples comme un &lt;code&gt;echo&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline&lt;/strong&gt; : Une série de jobs organisés de manière séquentielle ou parallèle. Chaque commit déclenche cette série pour valider les changements.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le principe est simple : chaque job retourne un code de statut (succès ou échec). Si un job échoue, la pipeline s’arrête ou ignore les étapes suivantes selon la configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trêve de blabla
&lt;/h2&gt;

&lt;p&gt;Nous allons utiliser un exemple basé sur GitLab CI. On la configure via un fichier &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basique, simple, simple, basique
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bookworm-slim:latest&lt;/span&gt;

&lt;span class="na"&gt;myjobname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Les flags
&lt;/h3&gt;

&lt;p&gt;Pour ajouter des flags de compilation, deux approches sont possibles :  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Via une règle dans le Makefile.
&lt;/li&gt;
&lt;li&gt;En passant les flags directement dans la commande CI.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;myjobname_hard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CFLAGS="-Wall -Werror" make&lt;/span&gt;
    &lt;span class="c1"&gt;# ou&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make compile_flags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tests avec Criterion et flags
&lt;/h3&gt;

&lt;p&gt;Criterion est une bibliothèque de tests unitaires en C.&lt;/p&gt;

&lt;h4&gt;
  
  
  Où est passé Criterion ?
&lt;/h4&gt;

&lt;p&gt;Avant d’exécuter des tests avec Criterion, il est souvent nécessaire d'installer Criterion, eh oui !&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;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y libcriterion-dev&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./configure&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Multistaging
&lt;/h4&gt;

&lt;p&gt;Diviser les tests unitaires et fonctionnels en plusieurs stages garantit :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;une bonne organisation
&lt;/li&gt;
&lt;li&gt;une meilleure visibilité des résultats
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make all&lt;/span&gt;

&lt;span class="na"&gt;test-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make unit-test&lt;/span&gt;

&lt;span class="na"&gt;test-functional&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make functional-test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tu t'es fait clang ?
&lt;/h3&gt;

&lt;p&gt;Le formatage du code est super important pour maintenir une base de code propre.&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;clang_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;format&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get -qq update &amp;amp;&amp;amp; apt-get -qq install -y clang-format autotools-dev autoconf-archive gcovr libcriterion-dev&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;clang-format -i $(find src/ -type f -name "*.c") --dry-run --Werror&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cache
&lt;/h3&gt;

&lt;p&gt;Dans certains cas, c'est utile de mettre en cache des fichiers ou dossiers pour éviter de les recharger à chaque pipeline.&lt;br&gt;&lt;br&gt;
Un exemple courant est le dossier &lt;code&gt;node_modules/&lt;/code&gt; en JavaScript.&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;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/&lt;/span&gt;

&lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bien entendu, vous pouvez nettoyer le cache au besoin avec une option supplémentaire dans la configuration de pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Artefacts
&lt;/h3&gt;

&lt;p&gt;Les artefacts sont les fichiers générés par la CI qui peuvent être partagés entre jobs ou téléchargés.&lt;br&gt;&lt;br&gt;
Par exemple, les rapports de tests ou de couverture.&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;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;reports/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Coverage de tests
&lt;/h3&gt;

&lt;p&gt;On peut mesurer la couverture de tests en intégrant des outils comme gcovr ou Cobertura dans votre pipeline CI.&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;test-coverage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gcovr --html --html-details -o coverage.html&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;coverage.html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Rapporteur
&lt;/h4&gt;

&lt;p&gt;Ce bloc vous permet d'intégrer le coverage report dans votre Merge Request, vous pourrez ainsi voir le code qui n'est pas couvert mais aussi votre pourcentage de coverage.&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;coverage-report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# do coverage&lt;/span&gt;
  &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/^TOTAL.*\s+(\d+\%)$/&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage.xml&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2 days&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;coverage_report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;coverage_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cobertura&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage.xml&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Environnement custom
&lt;/h3&gt;

&lt;p&gt;Vous pouvez préciser l’environnement de base pour votre CI en sélectionnant une image Docker spécifique.&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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcc:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En utilisant un peu ce que l'on vient de voir, ça donnerait quelque chose comme ça :&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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcc&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;format&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;clean&lt;/span&gt;

&lt;span class="na"&gt;clang-format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;format&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;clang-format -i $(find src/ -type f -name "*.c") --dry-run --Werror&lt;/span&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;autoreconf --install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./configure&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make all&lt;/span&gt;

&lt;span class="na"&gt;test-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;autoreconf --install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./configure&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make unit-test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Attention aux &lt;code&gt;.h&lt;/code&gt; et il manque des &lt;code&gt;before_script&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Petit Bonus
&lt;/h3&gt;

&lt;p&gt;On peut aussi vérifier les trash-files pour s’assurer que le &lt;code&gt;make clean&lt;/code&gt; fait bien son travail.&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;trash-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clean&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get -qq update &amp;amp;&amp;amp; apt-get -qq install -y tree&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tree &amp;gt; /tmp/REF&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;make &amp;amp;&amp;amp; make clean&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tree &amp;gt; /tmp/TEST&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;diff /tmp/REF /tmp/TEST&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;La Continuous Integration est un outil extrêmement puissant. Il peut parfois être difficile à mettre en place, mais les gains sont immenses.&lt;/p&gt;

</description>
      <category>ci</category>
      <category>clang</category>
      <category>c</category>
      <category>criterion</category>
    </item>
    <item>
      <title>Introduction à Terraform avec Proxmox</title>
      <dc:creator>Mr. VyM</dc:creator>
      <pubDate>Mon, 02 Dec 2024 10:35:20 +0000</pubDate>
      <link>https://dev.to/mrvym/introduction-a-terraform-avec-proxmox-83a</link>
      <guid>https://dev.to/mrvym/introduction-a-terraform-avec-proxmox-83a</guid>
      <description>&lt;p&gt;Le but de Terraform est de déployer une infrastructure ou une entité de manière &lt;strong&gt;idempotente&lt;/strong&gt;. Cela signifie que l’on doit pouvoir relancer le script 100 fois et obtenir le même résultat à chaque exécution.&lt;br&gt;&lt;br&gt;
Pour cela, nous utilisons un &lt;strong&gt;provider&lt;/strong&gt;, qui est essentiellement une bibliothèque permettant de se connecter à notre serveur.&lt;/p&gt;

&lt;p&gt;Dans ce cas pratique, nous allons utiliser &lt;strong&gt;Proxmox&lt;/strong&gt;. Il existe deux principaux providers pour Proxmox :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://registry.terraform.io/providers/Telmate/proxmox/latest/docs" rel="noopener noreferrer"&gt;Telmate&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
C’est une bibliothèque qui permet de déployer très simplement des VMs et des LXCs.&lt;br&gt;&lt;br&gt;
Inconvénient : elle n’implémente pas de fonctionnalités avancées. Cependant, elle est fréquemment mise à jour.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://registry.terraform.io/providers/bpg/proxmox/latest/docs" rel="noopener noreferrer"&gt;Bpg&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Cette bibliothèque est légèrement plus complexe à prendre en main, mais elle est bien plus puissante.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Organisation et Structure d'un Projet Terraform
&lt;/h2&gt;

&lt;p&gt;Afin que vous puissiez mieux comprendre le projet, voici son architecture :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── main.tf
├── provider.tf
├── variable.tf
└── terraform.auto.tfvars
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vous pouvez ajouter ou segmenter le projet en autant de fichiers &lt;code&gt;.tf&lt;/code&gt; que nécessaire. Par exemple, nous aurions pu avoir un fichier pour les VMs et un autre pour les LXCs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Les fichiers se terminant par &lt;code&gt;.tfvars&lt;/code&gt; servent à définir des variables. Lorsqu’ils commencent par &lt;code&gt;auto&lt;/code&gt;, ils sont automatiquement chargés par Terraform.
&lt;/li&gt;
&lt;li&gt;Le fichier &lt;code&gt;variable.tf&lt;/code&gt; permet de créer des variables sans les instancier.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Petit point Vocabulaire
&lt;/h3&gt;

&lt;p&gt;Dans cette article, nous allons utiliser le terme de LXC et de VM. Je vais faire un petit point dessus.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;LXC&lt;/code&gt;&lt;/strong&gt; ou &lt;strong&gt;&lt;code&gt;LinuX Container&lt;/code&gt;&lt;/strong&gt; : ce sont des environnements virtualisés qui tourne sur le &lt;code&gt;kernel&lt;/code&gt; de l'hôte mais qui ne peuvent pas discuter ensemble. Cela permet de segmenter nos services sans trop perde en performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;VM&lt;/code&gt;&lt;/strong&gt; ou &lt;strong&gt;&lt;code&gt;Virtual Machine&lt;/code&gt;&lt;/strong&gt; : comme son nom l'indique, on simule l'intégralité d'une machine. On perd en performance mais on gagne en sécurité et en fonctionnalité car un LXC n'a pas tout les privilèges.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choisir et Configurer un Provider Proxmox
&lt;/h2&gt;

&lt;p&gt;Avant tout, nous devons installer le &lt;strong&gt;provider&lt;/strong&gt; (la bibliothèque). Bien entendu, nous fixons une version minimale :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;proxmox&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bpg/proxmox"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 0.3.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;required_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 0.14"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Une fois la bibliothèque ajoutée, nous déclarons un provider nommé "proxmox", en fournissant les informations nécessaires :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"proxmox"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://${var.proxmox_endpoint}:8006"&lt;/span&gt;
  &lt;span class="nx"&gt;api_token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api_token_secret&lt;/span&gt;

  &lt;span class="nx"&gt;insecure&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# car un certificat TLS auto-signé est utilisé&lt;/span&gt;
  &lt;span class="nx"&gt;ssh&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;terraform&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;h2&gt;
  
  
  Les Variables dans Terraform
&lt;/h2&gt;

&lt;p&gt;Si vous êtes attentif, vous avez remarqué que nous utilisons l’objet &lt;code&gt;var.api_token_secret&lt;/code&gt; dans le bloc du provider. Cette chaîne de caractères est définie dans le fichier &lt;code&gt;terraform.auto.tfvars&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;À la manière d’un fichier &lt;code&gt;.env&lt;/code&gt;, ce fichier contient des valeurs sensibles et &lt;strong&gt;ne doit pas être poussé sur le dépôt git&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# terraform.auto.tfvars&lt;/span&gt;
&lt;span class="nx"&gt;api_token_secret&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-prov@pve!terraform=TOKEN"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dans le fichier &lt;code&gt;variable.tf&lt;/code&gt;, nous définissons les variables et leur type.&lt;br&gt;&lt;br&gt;
Voici les principaux types disponibles :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;number&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;string&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;list()&lt;/strong&gt; (ex. : &lt;code&gt;list(string)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;object&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;map&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# variable.tf&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"api_token_secret"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Secret token to connect Proxmox API"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_endpoint"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The domain name of the Proxmox instance"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"proxmox.mysite.fr"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Les Images et les Templates
&lt;/h2&gt;

&lt;p&gt;Pour démarrer nos entités, nous devons leur fournir un système d’exploitation.&lt;br&gt;&lt;br&gt;
Nous téléchargeons automatiquement un fichier de template pour le LXC et un ISO avec &lt;strong&gt;cloud-init&lt;/strong&gt; pour la VM.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si vous ne connaissez pas &lt;strong&gt;cloud-init&lt;/strong&gt;, c’est une méthode permettant d’instancier des machines sans passer par l’installateur de l’OS.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_download_file"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu_22-04_lxc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vztmpl"&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"local"&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target_node&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://download.proxmox.com/images/system/ubuntu-22.04-standard_22.04-1_amd64.tar.zst"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_download_file"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu_22-04_img"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"iso"&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"local"&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target_node&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  On crée un Réseau Virtuel
&lt;/h2&gt;

&lt;p&gt;Si nous avons envie que nos ressources discutent entre elles, il nous faut un réseau.&lt;/p&gt;

&lt;p&gt;Pour créer un adaptateur virtuel, il suffit d’appeler la ressource &lt;code&gt;proxmox_virtual_environment_network_linux_bridge&lt;/code&gt; et de lui donner un nom :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_network_linux_bridge"&lt;/span&gt; &lt;span class="s2"&gt;"internal_network"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target_node&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vmbr5"&lt;/span&gt;
  &lt;span class="nx"&gt;comment&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Internal Network"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Votre premier Container
&lt;/h2&gt;

&lt;p&gt;Passons aux choses concrètes en instanciant un &lt;strong&gt;LXC&lt;/strong&gt;. Pour cela, nous créons une ressource &lt;code&gt;proxmox_virtual_environment_container&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Avec l’IaC, tout peut être configuré : le disque, la RAM, le serveur DNS, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_container"&lt;/span&gt; &lt;span class="s2"&gt;"first_lxc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Managed by Terraform - Mr.VyM"&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target_node&lt;/span&gt;
  &lt;span class="nx"&gt;start_on_boot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;started&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;vm_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;

  &lt;span class="nx"&gt;cpu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;architecture&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"amd64"&lt;/span&gt;
    &lt;span class="nx"&gt;cores&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core_nb&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"storage"&lt;/span&gt;
    &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disk_size&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;memory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dedicated&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory_size&lt;/span&gt;
    &lt;span class="nx"&gt;swap&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="nx"&gt;operating_system&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;template_file_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxmox_virtual_environment_download_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ubuntu_22-04_lxc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;initialization&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;hostname&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mycontainer"&lt;/span&gt;

    &lt;span class="nx"&gt;dns&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;servers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"1.1.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"1.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;ip_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ipv4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"192.168.10.2/24"&lt;/span&gt;
        &lt;span class="nx"&gt;gateway&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"192.168.10.1"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;user_account&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;keys&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"keys 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"keys 2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lxc_password&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;network_interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bridge&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxmox_virtual_environment_network_linux_bridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internal_network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eth0"&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;h2&gt;
  
  
  Et maintenant une VM
&lt;/h2&gt;

&lt;p&gt;Créer une VM suit le même pattern que pour un LXC, avec quelques différences :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_vm"&lt;/span&gt; &lt;span class="s2"&gt;"vm_template"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Managed by Terraform - Mr.VyM"&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target_node&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"MyDummyVM"&lt;/span&gt;
  &lt;span class="nx"&gt;vm_id&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;102&lt;/span&gt;

  &lt;span class="nx"&gt;cpu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cores&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core_nb&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"x86-64-v2-AES"&lt;/span&gt;  &lt;span class="c1"&gt;# recommandé pour les CPU modernes&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;memory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dedicated&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory_size&lt;/span&gt;
    &lt;span class="nx"&gt;floating&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory_size&lt;/span&gt; &lt;span class="c1"&gt;# active le ballooning&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"local"&lt;/span&gt;
    &lt;span class="nx"&gt;file_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxmox_virtual_environment_download_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ubuntu_22-04_img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi0"&lt;/span&gt;
    &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disk_size&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;initialization&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ip_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ipv4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.base_subnet}.3/24"&lt;/span&gt;
        &lt;span class="nx"&gt;gateway&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.base_subnet}.1"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;user_account&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;keys&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"keys 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"keys 2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_password&lt;/span&gt; 
      &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mrvym"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"local"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;network_device&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bridge&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxmox_virtual_environment_network_linux_bridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internal_network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;operating_system&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"l26"&lt;/span&gt; &lt;span class="c1"&gt;# Linux Kernel&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;h2&gt;
  
  
  On check et ca part en Prod
&lt;/h2&gt;

&lt;p&gt;Enfin, nous déployons le tout avec les commandes suivantes :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;terraform init&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Initialise Terraform, télécharge les providers et crée les fichiers &lt;code&gt;terraform.state&lt;/code&gt; et &lt;code&gt;terraform.lock&lt;/code&gt;. Ces fichiers stockent l’état des entités sur le serveur.&lt;br&gt;&lt;br&gt;
Si ces fichiers sont absents, Terraform recrée les ressources, ce qui pourrait entraîner leur suppression et recréation.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;terraform fmt&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Formate le code pour garantir sa propreté.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;terraform plan&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Vérifie les actions que Terraform s’apprête à exécuter.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;terraform apply&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Applique les modifications.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Ecrit pour l'&lt;strong&gt;&lt;code&gt;Avent of Tech&lt;/code&gt;&lt;/strong&gt; de la &lt;a href="https://dev.to/ject"&gt;JECT&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>terraform</category>
      <category>infrastructureascode</category>
      <category>devops</category>
      <category>proxmox</category>
    </item>
    <item>
      <title>Disque dur : SAS, SATA, SCSI ou IDE ?</title>
      <dc:creator>Mr. VyM</dc:creator>
      <pubDate>Thu, 07 Nov 2024 01:11:30 +0000</pubDate>
      <link>https://dev.to/mrvym/disque-dur-sas-sata-scsi-ou-ide-59h6</link>
      <guid>https://dev.to/mrvym/disque-dur-sas-sata-scsi-ou-ide-59h6</guid>
      <description>&lt;p&gt;Notre but dans cet article est de mieux comprendre le concept des interfaces matérielles / programmation, des couches physiques et des jeux de commandes, et plus simplement des systèmes de stockage qui nous entourent.&lt;/p&gt;

&lt;p&gt;Mais d'abord, un "rapide" récapitulatif de l'état actuel de nos périphériques de stockage :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Norme de stockage&lt;/th&gt;
&lt;th&gt;Interface matérielle&lt;/th&gt;
&lt;th&gt;Couche physique&lt;/th&gt;
&lt;th&gt;Jeux de commandes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PATA&lt;/td&gt;
&lt;td&gt;IDE (Integrated Drive Electronics)&lt;/td&gt;
&lt;td&gt;Connecteur 40/44 broches, câble parallèle&lt;/td&gt;
&lt;td&gt;ACS (ATA Command Set)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SATA&lt;/td&gt;
&lt;td&gt;SATA (Serial ATA)&lt;/td&gt;
&lt;td&gt;Connecteur SATA, câble série&lt;/td&gt;
&lt;td&gt;ACS (ATA Command Set)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SAS (Serial Attached SCSI)&lt;/td&gt;
&lt;td&gt;SCSI (Small Computer System Interface)&lt;/td&gt;
&lt;td&gt;Connecteur SAS, câble série&lt;/td&gt;
&lt;td&gt;SCSI (Small Computer System Interface)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVMe (Non-Volatile Memory Express)&lt;/td&gt;
&lt;td&gt;PCIe (Peripheral Component Interconnect Express)&lt;/td&gt;
&lt;td&gt;Bus PCIe&lt;/td&gt;
&lt;td&gt;AHCI (Advanced Host Controller Interface)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Si vous vous demandez, oui, les constructeurs ont pris un malin plaisir à utiliser le même nom entre l'interface et la norme.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Avant de commencer, un point vocabulaire&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Couche Physique : C'est le cable et le connecteur.&lt;/p&gt;

&lt;p&gt;Interface Materielle : C'est la maniere de communiquer, attention ne pas confondre avec le "language". &lt;/p&gt;

&lt;p&gt;Jeu de commandes : C'est le language utilisé.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pour faire une analogie, si vous etes un humain (j'espere 🤔), la couche physique c'est vos cordes vocales, l'interface materielle, c'est la maniere de faire vibrer vos cordes et le jeu de commandes, c'est le language utilisé. &lt;/p&gt;

&lt;h2&gt;
  
  
  Norme de stockage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ATA
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Date : 1986&lt;br&gt;&lt;br&gt;
Qui : Western Digital  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ATA signifie &lt;strong&gt;Advanced Technology Attachment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;C'est le véritable concurrent du protocole SCSI. C'est aussi un ensemble de normes avec l'interface matérielle (IDE), la couche physique (PATA ou bien SATA) et les jeux de commandes (ACS).&lt;/p&gt;

&lt;p&gt;C'est une version plus low-cost de SCSI, qui avait pour but de réutiliser des éléments de ce dernier mais en simplifiant le connecteur (la couche physique) et le jeu d'instruction.&lt;/p&gt;

&lt;p&gt;Contrairement au SAS, cette norme est en semi-duplex, ce qui signifie qu'elle ne peut exécuter qu'une seule action simultanément : soit lire, soit écrire.&lt;/p&gt;

&lt;h3&gt;
  
  
  SAS
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Date : 1980&lt;br&gt;&lt;br&gt;
Qui : Shugart / NCR Corporation  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;C'est un ensemble de normes qui s'applique sur les couches physiques et les jeux de commandes. &lt;/p&gt;

&lt;p&gt;Nous devons revenir dans les années 80, à cette époque, il n'y a pas des milliers de façons de communiquer avec un périphérique de stockage. L'un d'entre eux est le protocole &lt;strong&gt;SCSI&lt;/strong&gt; (Small Computer System Interface).&lt;/p&gt;

&lt;p&gt;C'est un protocole propriétaire mais très performant pour son temps. Son grand avantage est le fait de déporter la logique dans le périphérique, contrairement à ses concurrents qui utilisent allègrement la puissance de l'ordinateur. Et dans les années 80, on n'avait pas encore la puissance de calcul, ce protocole a donc été particulièrement apprécié par l'industrie.&lt;/p&gt;

&lt;p&gt;De plus, la norme a l'avantage de pouvoir écrire en duplex, c'est-à-dire lire et écrire des données simultanément.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface matérielle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  IDE
&lt;/h3&gt;

&lt;p&gt;IDE est une norme qui intègre le contrôleur de disque directement sur le disque dur lui-même. Avant IDE, les contrôleurs de disque étaient séparés, ce qui compliquait la configuration et limitait la compatibilité.&lt;br&gt;&lt;br&gt;
Cela signifie qu'un disque dur est dit compatible IDE s'il possède une puce IDE.&lt;/p&gt;

&lt;h3&gt;
  
  
  SATA
&lt;/h3&gt;

&lt;p&gt;C'est une ré-implémentation de l'interface matérielle parallèle en série (Serial ATA).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Qu'est-ce qu'un port parallèle ?&lt;br&gt;&lt;br&gt;
Contrairement au port série, un port parallèle peut transférer un ensemble de 8 bits à la fois sur huit fils différents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pour vous donner une idée de l'interface matérielle / couche physique.&lt;br&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%2Fsi132dwg6anuqybjfeal.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%2Fsi132dwg6anuqybjfeal.png" alt="PATA Pin-out" width="506" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  PCIe
&lt;/h3&gt;

&lt;p&gt;L'interface matérielle PCIe (Peripheral Component Interconnect Express) est une interface de communication utilisée principalement pour connecter des périphériques internes tels que des cartes graphiques, des cartes réseau et d'autres cartes d'extension.&lt;/p&gt;

&lt;p&gt;Elle utilise un bus série, ce qui signifie que les données sont transmises bit par bit sur une seule ligne, contrairement aux anciennes interfaces parallèles.&lt;/p&gt;

&lt;p&gt;PCIe fonctionne avec des connecteurs spécifiques et des voies de transmission (lanes) qui permettent des transferts de données très rapides. &lt;/p&gt;

&lt;p&gt;Les cartes PCIe sont insérées dans des slots PCIe sur la carte mère, et l'interface est disponible en différentes versions (x1, x4, x8, x16) en fonction du nombre de voies utilisées, offrant ainsi une bande passante ajustée aux besoins des périphériques.&lt;/p&gt;

&lt;p&gt;PCIe est largement utilisé dans les systèmes modernes en raison de sa vitesse de transmission élevée, de sa flexibilité et de sa capacité à évoluer pour prendre en charge des dispositifs nécessitant des débits importants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Couche physique
&lt;/h2&gt;

&lt;p&gt;Globalement, c'est la partie la plus simple de l'article.&lt;br&gt;&lt;br&gt;
(Enfin, en électronique, ce n'est jamais simple).&lt;/p&gt;

&lt;p&gt;Une couche physique, cela signifie que c'est la norme qui régit la façon de réaliser le câble et le connecteur (cf Illustration du Pin-out)&lt;/p&gt;

&lt;p&gt;Une nappe IDE&lt;br&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%2Ffu04kfy2js7vjn27lbpg.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%2Ffu04kfy2js7vjn27lbpg.jpg" alt="Nappe IDE" width="330" height="226"&gt;&lt;/a&gt;&lt;br&gt;
Dans notre cas, c'est un câble dit "IDE".&lt;br&gt;&lt;br&gt;
Ce genre de câble est la version parallèle, il contient 80 fils, ce qui permet de connecter deux appareils à la carte mère. Le premier sera appelé "master" et le deuxième "slave".&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%2F10bq0ctd4sh4ettg1514.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%2F10bq0ctd4sh4ettg1514.png" alt="Master Slave PATA" width="672" height="144"&gt;&lt;/a&gt;&lt;br&gt;
Mais je ne vais pas détailler les différents câbles qui existent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jeux de commandes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ACS (Commandes)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Date : années 80&lt;br&gt;&lt;br&gt;
Qui : Shugart / NCR Corporation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Le &lt;strong&gt;ATA Command Set&lt;/strong&gt; (ACS) est la liste des commandes que le système peut envoyer au périphérique.&lt;br&gt;&lt;br&gt;
On pourrait citer comme exemples :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WRITE_SECTOR
&lt;/li&gt;
&lt;li&gt;SLEEP
&lt;/li&gt;
&lt;li&gt;PACKET
&lt;/li&gt;
&lt;li&gt;IDENTIFY PACKET DEVICE&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SCSI
&lt;/h3&gt;

&lt;p&gt;ACS étant un détournement du jeu de SCSI, on retrouve de grandes similitudes entre les deux jeux. Cependant, on peut les différencier en creusant un peu, notamment en ce qui concerne les rapports d'erreurs.&lt;/p&gt;

&lt;h3&gt;
  
  
  AHCI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AHCI&lt;/strong&gt; (Advanced Host Controller Interface) permet une communication optimisée entre le système d'exploitation et les périphériques de stockage, en offrant des fonctionnalités avancées comme le contrôle de file d'attente (pour améliorer les lectures/écritures simultanées) et le mode &lt;strong&gt;NCQ&lt;/strong&gt; (Native Command Queuing), qui permet au disque de réorganiser les commandes d'entrée/sortie pour une performance maximale.&lt;/p&gt;

&lt;p&gt;Ce jeu de commandes facilite également des fonctionnalités telles que la gestion de l'alimentation et le &lt;strong&gt;hot-plug&lt;/strong&gt; (permettre l'ajout et le retrait de périphériques sans éteindre le système).&lt;/p&gt;

&lt;p&gt;AHCI a été conçu pour améliorer les performances et la gestion des périphériques de stockage SATA en optimisant l'utilisation des ressources et la vitesse des transferts.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion / Performance
&lt;/h1&gt;

&lt;p&gt;Nous n'avons toujours pas parlé de la partie performance de ces différences, donc voici le mot de la fin.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Interface&lt;/th&gt;
&lt;th&gt;Vitesse max (Gb/s)&lt;/th&gt;
&lt;th&gt;Type de connexion&lt;/th&gt;
&lt;th&gt;Utilisation principale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SATA III&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6 Gb/s&lt;/td&gt;
&lt;td&gt;Série&lt;/td&gt;
&lt;td&gt;SSD et HDD domestiques&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SAS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22,5 Gb/s&lt;/td&gt;
&lt;td&gt;Série&lt;/td&gt;
&lt;td&gt;Disques professionnels et serveurs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PCIe 5.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;32 Gb/s par ligne&lt;/td&gt;
&lt;td&gt;Série&lt;/td&gt;
&lt;td&gt;SSD NVMe internes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NVMe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dépend de PCIe&lt;/td&gt;
&lt;td&gt;PCIe&lt;/td&gt;
&lt;td&gt;SSD haute performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;U.2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Selon PCIe (16-32 Gb/s)&lt;/td&gt;
&lt;td&gt;PCIe et NVMe&lt;/td&gt;
&lt;td&gt;Serveurs et stations de travail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;M.2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Selon PCIe (16-32 Gb/s)&lt;/td&gt;
&lt;td&gt;PCIe ou SATA&lt;/td&gt;
&lt;td&gt;Ordinateurs portables et de bureau&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Thunderbolt 3/4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;40 Gb/s&lt;/td&gt;
&lt;td&gt;Série (USB-C)&lt;/td&gt;
&lt;td&gt;Stockage externe rapide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;USB 4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;40 Gb/s&lt;/td&gt;
&lt;td&gt;Série (USB-C)&lt;/td&gt;
&lt;td&gt;Stockage externe polyvalent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>storage</category>
      <category>comparative</category>
      <category>embedsystem</category>
      <category>sata</category>
    </item>
    <item>
      <title>#define INC(a) INC(a+1)</title>
      <dc:creator>Mr. VyM</dc:creator>
      <pubDate>Thu, 17 Oct 2024 22:05:58 +0000</pubDate>
      <link>https://dev.to/mrvym/define-inca-inca-20pn</link>
      <guid>https://dev.to/mrvym/define-inca-inca-20pn</guid>
      <description>&lt;p&gt;Cette macro fait-elle planter GCC ? Lisez et vous aurez la réponse&lt;/p&gt;

&lt;p&gt;Le but de cet article est de vous faire découvrir le magnifique univers des macros en C.&lt;/p&gt;

&lt;h1&gt;
  
  
  Une directive préprocesseur
&lt;/h1&gt;

&lt;p&gt;En C, les lignes qui commencent par un # sont interprétées par le compilateur avant la compilation des fichiers sources. &lt;br&gt;
On les appelle des directives du préprocesseur. Les macros en font partie.&lt;/p&gt;

&lt;p&gt;Petit point historique : &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Les macros en langage C ont été introduites avec la première norme du langage C, appelée ANSI C (ou C89), &lt;br&gt;
qui a été standardisée par l'&lt;a href="https://www.ansi.org" rel="noopener noreferrer"&gt;American National Standards Institute&lt;/a&gt; (ANSI) en 1989.&lt;/p&gt;

&lt;p&gt;Cependant, avant cette standardisation, les macros faisaient déjà partie du langage C classique (ou K&amp;amp;R C) utilisé dans les années 1970. &lt;br&gt;
Le compilateur C original, développé par Dennis Ritchie pour le système d'exploitation UNIX, incluait déjà une forme rudimentaire de macros via le préprocesseur, permettant des définitions avec #define.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Define
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define SENS_DE_LA_VIE 3.14
&lt;/span&gt;
&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%f&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;SENS_DE_LA_VIE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Le &lt;code&gt;define&lt;/code&gt; a un fonctionnement assez simple à comprendre : le compilateur remplace toutes les occurrences dans le code par la valeur définie. Il fonctionne avec la syntaxe suivante &lt;code&gt;#define &amp;lt;MACRO_NAME&amp;gt; &amp;lt;value&amp;gt;&lt;/code&gt;. On a pour convention de mettre le nom en majuscule, la valeur quant à elle est optionnelle.&lt;/p&gt;

&lt;p&gt;Un peu comme un "Ctrl-f et remplacer".&lt;/p&gt;
&lt;h2&gt;
  
  
  Mama, la macro
&lt;/h2&gt;

&lt;p&gt;On peut utiliser les &lt;code&gt;define&lt;/code&gt; pour définir des fonctions que l'on pourra utiliser dans notre code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 
&lt;/span&gt;

&lt;span class="n"&gt;INC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_variable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="n"&gt;MULTI_LINE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_variable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne &lt;/span&gt;

&lt;span class="c1"&gt;// Cela donnera  &lt;/span&gt;
&lt;span class="n"&gt;my_variable&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;my_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;foobar&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  If or not if
&lt;/h2&gt;

&lt;p&gt;Nous pouvons déclarer des macros de manière conditionnelle. &lt;br&gt;
Si un nom est déjà défini alors on exécute le bout de code suivant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifdef DEBUG
&lt;/span&gt;&lt;span class="c1"&gt;// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug&lt;/span&gt;
&lt;span class="c1"&gt;// et que nous avons brisé la règle du nom des macros en MAJ.&lt;/span&gt;
&lt;span class="cp"&gt;#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* ! DEBUG */&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="kt"&gt;void&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="mi"&gt;1&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;Dans ce cas, j'utilise un &lt;code&gt;#ifndef&lt;/code&gt;, mais il existe aussi :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#ifdef&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#if&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#else&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#elif&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if (X == 1)
#define Y 2
#elif (X == 2)
#define Y "Ami de la bonne blague, bonjour !"
#else
#define Y NULL
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* ! X */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cm"&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="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cp"&gt;#if (X == 1)
&lt;/span&gt;    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d&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;Y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="cp"&gt;#elif (X == 2)
&lt;/span&gt;    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s&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;Y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="cp"&gt;#else
&lt;/span&gt;    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%p&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;Y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="cp"&gt;#endif &lt;/span&gt;&lt;span class="cm"&gt;/* ! X */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On aime bien signaler avec un commentaire en bloc la fin des &lt;code&gt;#if&lt;/code&gt;. C'est une convention qui permet de mieux se repérer dans le code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Macros prédéfinies
&lt;/h2&gt;

&lt;p&gt;Vous avez pu voir dans l'exemple précédent que j'utilisais les mots-clés &lt;code&gt;__FUNCTION__&lt;/code&gt; et &lt;code&gt;__LINE__&lt;/code&gt;. &lt;br&gt;
Comme vous pouvez vous en douter, ce sont des macros que le compilateur va remplacer par la bonne valeur.&lt;/p&gt;

&lt;p&gt;Il existe une liste de macros prédéfinies &lt;a href="https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html" rel="noopener noreferrer"&gt;Common Predifined&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;À noter qu'il existe des macros dites &lt;a href="https://gcc.gnu.org/onlinedocs/cpp/System-specific-Predefined-Macros.html" rel="noopener noreferrer"&gt;System specific&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Petite liste non exhaustive : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;__DATE__&lt;/code&gt; : Jan 14 2012&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__GNUC__&lt;/code&gt; : Version majeure de GCC&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__TIME__&lt;/code&gt; : 15:12:18&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__INCLUDE_LEVEL__&lt;/code&gt; : La profondeur des includes en commençant par 0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__BASE_FILE__&lt;/code&gt; : Le nom du fichier actuel&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Vers l'infini et au-delà des arguments
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ici, l'opérateur ## est l'opérateur de concaténation&lt;/span&gt;
&lt;span class="cp"&gt;#define DEBUG_PRNTF(fmt, ...) printf("LOG" ## fmt, __VA_ARGS__);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ici, on peut voir que l'on génère des macros variadiques, surtout utiles lors de la création de logs. &lt;br&gt;
(Même si ce n'est pas une bonne idée de faire des logs avec des &lt;code&gt;printf&lt;/code&gt;.)&lt;/p&gt;
&lt;h2&gt;
  
  
  X-Macro
&lt;/h2&gt;

&lt;p&gt;Pour cela, nous allons devoir créer un fichier externe, souvent nommé en &lt;code&gt;*.def&lt;/code&gt; bien qu'il n'existe pas de convention.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// color.def&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"No Color"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BLACK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;30m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Black"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;30m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Gray"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x808080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;31m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xFF0000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LIGHT_RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;31m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Light Red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xFF8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GREEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;32m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Green"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x00FF00&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LIGHT_GREEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;32m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Light Green"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x80FF80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BROWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;33m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Brown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xA52A2A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YELLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;33m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Yellow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xFFFF00&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BLUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;34m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Blue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0000FF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LIGHT_BLUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;34m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Light Blue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xADD8E6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PURPLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;35m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Purple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x800080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LIGHT_PURPLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;35m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Light Purple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xEE82EE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CYAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;36m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cyan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x00FFFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LIGHT_CYAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;36m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Light Cyan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xE0FFFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LIGHT_GRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[0;37m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Light Gray"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xD3D3D3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WHITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\e[1;37m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"White"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xFFFFFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&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="n"&gt;name&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="n"&gt;ansi_code&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="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define X(NAME, ANSI, DESC, RGB) { #NAME, ANSI, DESC, RGB },
&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"color.def"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cp"&gt;#undef X
&lt;/span&gt;
&lt;span class="cp"&gt;#define X(NAME, ANSI, DESC, RGB) printf("%s (%s) = %s\n", #NAME, DESC, #RGB);
&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print_colors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Bien entendu, on pourrait itérer sur la structure créée mais c'est une illustration&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"color.def"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#undef X
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce genre de macro est extrêmement utile. Je dois reconnaître qu'on la retrouve rarement dans un code source, mais elle permet de modifier le fonctionnement du programme sans pour autant devoir modifier le code source. Fun fact, elle est souvent utilisée dans la création de kernels. Elle permet de générer les structures globales comme l'IDT et la GDT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Les problèmes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Attention&lt;/strong&gt;&lt;/strong&gt; : Petite mise au point d'abord, les macros sont des outils formidables mais il faut faire attention. Vous ne devez surtout pas utiliser ce genre de macro :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MIN(a,b) (a &amp;lt; b ? a : b)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prenons un exemple : &lt;code&gt;MIN(2 + 5, fibo(25))&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Problème n°1
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MIN(2 + 5, fibo(25))&lt;/code&gt; =&amp;gt; &lt;code&gt;(2 + 5 &amp;lt; fibo(25) ? 2 + 5 : fibo(25))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ici le problème est la priorité de calcul. Le compilateur va d'abord effectuer la comparaison puis l'addition, donc 2 + (1). On corrige cela par l'ajout de parenthèses en utilisant les arguments des macros.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MIN(a,b) ((a) &amp;lt; (b) ? (a) : (b))
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comme vous ne savez jamais ce que vos utilisateurs vont passer en paramètre, mettez toujours des parenthèses sur les arguments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problème n°2
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MIN(2 + 5, fibo(25))&lt;/code&gt; =&amp;gt; &lt;code&gt;(2 + 5 &amp;lt; fibo(25) ? 2 + 5 : fibo(25))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On remarque que le compilateur fait un remplacement bête et méchant, ce qui veut dire que l'on va calculer deux fois &lt;code&gt;fibo(25)&lt;/code&gt;. Je vous laisse imaginer si c'est une implémentation récursive.&lt;/p&gt;

&lt;p&gt;Pour fixer ce problème, nous déclarons une variable intermédiaire avant le &lt;code&gt;if&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Macros utiles
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MIN(a, b)                                                              \
    ({                                                                         \
        __typeof__(a) _a = a;                                                  \
        __typeof__(b) _b = b;                                                  \
        (_a) &amp;gt; (_b) ? (_b) : (_a);                                             \
    })
&lt;/span&gt;
&lt;span class="cp"&gt;#define ABS(a)                                                                 \
    ({                                                                         \
        __typeof__(a) _a = a;                                                  \
        0 &amp;lt; (_a) ? (_a) : -(_a);                                               \
    })
&lt;/span&gt;
&lt;span class="cp"&gt;#define MAX(a, b)                                                              \
    ({                                                                         \
        __typeof__(a) _a = a;                                                  \
        __typeof__(b) _b = b;                                                  \
        (_a) &amp;lt; (_b) ? (_b) : (_a);                                             \
    })
&lt;/span&gt;
&lt;span class="cp"&gt;#define CLAMP(a, x, b) MAX(a, MIN(x, b))
&lt;/span&gt;&lt;span class="c1"&gt;// Pour les tableaux uniquement&lt;/span&gt;
&lt;span class="cp"&gt;#define COUNT_OF(arr) sizeof(arr) / sizeof(arr[0])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Là, on s'amuse
&lt;/h2&gt;

&lt;p&gt;Ici, c'est du code purement overkill juste pour le fun. Je ne vous conseille pas forcément d'utiliser ces macros dans votre code.&lt;br&gt;
Je me fais juste plaisir (faut bien dans la vie).&lt;/p&gt;
&lt;h3&gt;
  
  
  Un auto free
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define DEFER(free_call) __attribute__((cleanup(free_call)))
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;auto_free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&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="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;ptr&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&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="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;DEFER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_free&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&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;Je vous laisse tester avec un petit &lt;code&gt;-fsanitize=address&lt;/code&gt;. C'est vraiment une dinguerie. On pourrait même voir une amélioration de la fonction auto_free qui prend en paramètre une chaîne de caractères du nom de notre structure pour faire un switch.&lt;/p&gt;
&lt;h3&gt;
  
  
  Get time
&lt;/h3&gt;

&lt;p&gt;Fonction plus chill où l'on calcule juste le temps d'exécution de notre fonction. Très utile pour faire du benchmark.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MEASURE_TIME(block) {                                \
    clock_t start_time = clock();                            \
    block                                                    \
    clock_t end_time = clock();                              \
    double elapsed = ((double)(end_time - start_time)) / CLOCKS_PER_SEC * 1000.0; \
    printf("Execution time: %.3f ms\n", elapsed);            \
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define Error
&lt;/h3&gt;

&lt;p&gt;Petite X-macro qui prend une macro en argument et qui l'expand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define ERROR_LIST(X)          \
    X(ERROR_FILE_NOT_FOUND, "File not found")    \
    X(ERROR_INVALID_INPUT, "Invalid input")      \
    X(ERROR_OUT_OF_MEMORY, "Out of memory")      \
    X(ERROR_UNKNOWN, "Unknown error")
&lt;/span&gt;
&lt;span class="cp"&gt;#define DEFINE_ERROR_ENUM(code, message) code,
&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ErrorCode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ERROR_LIST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEFINE_ERROR_ENUM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cp"&gt;#define DEFINE_ERROR_STRING(code, message) case code: return message;
&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="nf"&gt;get_error_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ErrorCode&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ERROR_LIST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEFINE_ERROR_STRING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nl"&gt;default:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Unrecognized error"&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="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ErrorCode&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ERROR_OUT_OF_MEMORY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error: %s&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;get_error_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Génération de tests automatisés
&lt;/h3&gt;

&lt;p&gt;Ici, on génère carrément des fonctions entières avec une macro, parce que le C n'a aucune limite. Moi aussi 👀&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define GENERATE_TEST_FUNC(func, test_value, wanted_value) \
    void test_##func(void) { \
        printf("Test de " #func " avec valeur %d : ", test_value); \
        if (func(test_value)) { \
            printf("Succès\n"); \
        } else { \
            printf("Échec\n"); \
        } \
    }
&lt;/span&gt;
&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="n"&gt;GENERATE_TEST_FUNC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;test_fibo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  RTFM
&lt;/h2&gt;

&lt;p&gt;Il est maintenant l'heure de conclure. Nous avons vu plein de choses très cool. Et si jamais vous êtes tentés, libre à vous de découvrir les macros par vous-même. Il reste encore plein de choses à voir. &lt;br&gt;
Donc, conclusion : &lt;strong&gt;RTFM&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PS : Pour ce qui est du titre, les macros ne sont pas récursives, elles ne s'expandent qu'avec une profondeur de 1 et dans notre cas présent, GCC va faire une implicit_declaration sur INC et crash.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>c</category>
      <category>macro</category>
      <category>define</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Le merveilleux monde de Make</title>
      <dc:creator>Mr. VyM</dc:creator>
      <pubDate>Thu, 14 Mar 2024 20:48:14 +0000</pubDate>
      <link>https://dev.to/mrvym/le-merveilleux-monde-de-make-59e5</link>
      <guid>https://dev.to/mrvym/le-merveilleux-monde-de-make-59e5</guid>
      <description>&lt;h1&gt;
  
  
  Le merveilleux monde de Make
&lt;/h1&gt;

&lt;p&gt;Les Makefiles constituent un outil essentiel dans le développement de logiciels que ce soit en C/C++ ou autre. Ils permettent une gestion efficace des projets en automatisant le processus de compilation, de nettoyage et de tests. &lt;/p&gt;

&lt;p&gt;Dans cet article, nous explorerons les bonnes pratiques pour la création et l'utilisation de Makefiles dans des projets C quelque soit leurs complexites.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make, ca sert a quoi ?
&lt;/h3&gt;

&lt;p&gt;Make est un programme qui a pour but de générer des fichier. Il permet de générer des pdfs, des exécutables et bien plus.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dans les années 1970, la compilation des programmes devient de plus en plus longue et complexe, nécessitant de nombreuses étapes interdépendantes. La plupart des systèmes alors utilisés reposent sur des script shell, nécessitant de répéter toutes les étapes lors de la moindre correction. C'est dans ce contexte que Make fut développé par le docteur Stuart Feldman en 1977. En gérant les dépendances entre fichiers sources et fichiers compilés, Make permet de ne compiler que ce qui est nécessaire à la suite de la modification d'un fichier source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Il existe un makefile par défaut, qui définit un grand nombre de règles afin de générer la plupart des fichiers avec lesquels, vous serez amené a travailler.&lt;/p&gt;

&lt;p&gt;Pour voir ce makefile, par défaut : &lt;code&gt;make -p&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hello World
&lt;/h3&gt;

&lt;p&gt;Pour débuter, nous allons prendre un cas très simple celui d'un fichier source unique, dans le même dossier que notre makefile.&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;.&lt;/span&gt;
└── main.c 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dans ce cas, il existe 2 facons de faire.&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;make main &lt;span class="c"&gt;# Je souligne l'absence du .c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dans cette commande, nous demandons a make de créer le fichier &lt;code&gt;main&lt;/code&gt;. Mais comment sait-il qu'il doit utiliser le fichier main.c pour faire notre binaire ? Cela est défini dans les règles par défaut.&lt;/p&gt;

&lt;p&gt;Nous pouvons aussi creer un fichier &lt;code&gt;Makefile&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;# Makefile
my_compilation_rule: 
    gcc main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Une fois, le fichier crée, il suffit d'exécuter la commande &lt;code&gt;make&lt;/code&gt; (qui, par défaut, exécute la première règle du fichier).&lt;br&gt;
Nous pouvons aussi mettre en argument le nom de la règle que nous voulons exécuter &lt;code&gt;make my_compilation_rule&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Plus on est de fou, plus on rit
&lt;/h3&gt;

&lt;p&gt;Notre projet grossit, nous avons maintenant un deuxième fichier source.&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;.&lt;/span&gt;
├── foo.c
├── foo.h
└── main.c 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dans l'objectif de faire un makefile propre, nous allons déclarer une variable OBJ qui contiendra nos différents fichiers. On en profite pour déclarer un variable CC pour notre compilateur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# makefile
&lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; gcc
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main.o foo.o


&lt;span class="c"&gt;# Cette variable sera utilisée dans la règle implicite qui compile les .o  
&lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c"&gt;# My C Flags for the compiler&lt;/span&gt;
&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c"&gt;# My linker flags&lt;/span&gt;
&lt;span class="nv"&gt;TARGET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; a.out

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(OBJ)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;TARGET&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDFLAGS&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cette fois-ci, nous avons ajouter des dépendances à notre règle &lt;code&gt;all&lt;/code&gt;. Maintenant, make sait qu'il faut d'abord faire les fichiers .o avant de pouvoir faire le linkage de tous les fichiers en un binaire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# makefile
&lt;/span&gt;&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# main.c foo.c&lt;/span&gt;
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC:.c&lt;span class="o"&gt;=&lt;/span&gt;.o&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# main.o foo.o&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dans ce makefile, nous avons choisi de ne pas récupérer, à la main, les différents fichiers source. Nous récupérons automatiquement les fichiers source via la fonction &lt;code&gt;wildcard&lt;/code&gt;. Cette fonction agit comme le globbing d'un shell. Dans cette example, elle récupère tous les fichiers terminant par &lt;code&gt;.c&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Nous les convertissons en &lt;code&gt;.o&lt;/code&gt; via cette syntax &lt;code&gt;$(NAME:old=new)&lt;/code&gt; qui n'est rien de moins qu'un replace. La suite de notre makefile reste néanmoins la même chose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean
&lt;/h3&gt;

&lt;p&gt;Comme vous avez pu le remarquer, un makefile peut facilement générer un grand nombre de fichiers. C'est pour cela que nous allons créer une nouvelle règle dans notre makefile qui a pour but de supprimer tous les fichiers issus de la compilation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;
&lt;span class="c"&gt;# ...
&lt;/span&gt;
&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; 
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;TARGET&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour les petits curieux qui se demandent ce que signifie la variable RM. C'est un simple alias avec la commande &lt;code&gt;rm -f&lt;/code&gt;. Il faut savoir que cette variable peut très bien override. On peut très bien voir &lt;code&gt;RM = echo&lt;/code&gt; ou bien &lt;code&gt;RM = mv to/path/&lt;/code&gt; (à la place du remove), cela peut être très utile dans certains projets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Phony
&lt;/h4&gt;

&lt;p&gt;Nous l'avons dit au début de cet article, mais make est un utilitaire qui permet de générer des fichiers. Mais que se passe-t-il, si l'on appelle la règle clean et qui existe un fichier &lt;code&gt;clean&lt;/code&gt; dans notre dossier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make: &lt;span class="s1"&gt;'clean'&lt;/span&gt; is up to date.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour éviter ce genre de problème, il faut spécifier dans notre makefile que notre règle n'a pas pour but de générer un fichier. Pour cela, nous utilisons le mot clé &lt;code&gt;phony&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Il suffit d'écrire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;my_rule1 my_rule12 &lt;/span&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; ... &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  On range le repo
&lt;/h3&gt;

&lt;p&gt;Maintenant, que nous avons réussi à faire un makefile propre, nous allons pouvoir faire évoluer notre projet en mettant nos fichiers dans un dossier &lt;code&gt;src&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;.
├── Makefile
└── src/
    ├── foo.c
    ├── foo.h
    └── main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour cela, il nous suffit de rechercher la liste de nos .c dans le dossier src/ puis de les transformer en .o. On peut modifier le code que nous avons fait ci-dessus.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SRCDIR = src
SRC = $(wildcard $(SRCDIR)/*.c)
OBJ = $(SRC:$(SRCDIR)/%.c=$(SRCDIR)/%.o)
# qui est équivalent à
# OBJ = src/main.o \
#       src/main.o

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where GDB ?
&lt;/h3&gt;

&lt;p&gt;Il peut être utile d'avoir un règle debug, afin de ne pas avoir à mettre un &lt;code&gt;-g&lt;/code&gt; dans nos CFLAGS par défaut.&lt;/p&gt;

&lt;p&gt;Pour cela, il suffit de :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;CFLAGS += -g&lt;/span&gt;
&lt;span class="nl"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On remarque que la règle debug n'a pas de corps. Elle se contente d'ajouter un flag et d'appeler notre règle &lt;code&gt;all&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tester, c'est tricher
&lt;/h3&gt;

&lt;p&gt;Pour cet article, nous allons voir comment faire un Makefile pour une test suite criterion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Makefile
├── src/
...
└── tests/
    └── foo_test.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour pouvoir lancer, nos tests, il va falloir que l'on trouve les fichiers source du dossier &lt;code&gt;tests&lt;/code&gt;, puis linker tous nos fichiers en excluant le fichier main.o.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;TEST_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; tests
&lt;span class="nv"&gt;SRC_TEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;TEST_DIR&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;OBJ_TEST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC:&lt;span class="p"&gt;$(&lt;/span&gt;TEST_DIR&lt;span class="p"&gt;)&lt;/span&gt;/%.c&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;TEST_DIR&lt;span class="p"&gt;)&lt;/span&gt;/%.o&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# ... 
&lt;/span&gt;
&lt;span class="nl"&gt;check&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(filter-out $(SRC_DIR)/main.o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $(OBJ)) $(OBJ_TEST)&lt;/span&gt;
&lt;span class="err"&gt;$(CC)&lt;/span&gt; &lt;span class="err"&gt;$^&lt;/span&gt; &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="err"&gt;$(TARGET)&lt;/span&gt; &lt;span class="err"&gt;$(LDFLAGS)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On remarque que le fichier main.o est exclus en utilisant la fonction &lt;code&gt;filter-out&lt;/code&gt;. On voit aussi l'appel d'une variable pour le moment inconnu. Il en existe un grand nombre.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$^&lt;/code&gt;  : La liste des dépendances de la règle&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$&amp;lt;&lt;/code&gt; : Le nom de la première dépendance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$@&lt;/code&gt; : Le nom de la règle&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  On teste les tests
&lt;/h3&gt;

&lt;p&gt;Si l'on parle de test, nous devons forcément parler de coverage. Pour cela rien de plus simple, nous ajoutons les flags a nos variables puis exécutons &lt;code&gt;GCOVR&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;coverage: CFLAGS += -fPIC --coverage
coverage: LDFLAGS += -lgcov -lcriterion
coverage: check
gcovr --print-summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Like a pro
&lt;/h3&gt;

&lt;p&gt;La création d'un dossier build est la cerise sur le gâteau. Elle permet au développeur de faire &lt;code&gt;rm -rf build/&lt;/code&gt; pour faire un clean.&lt;/p&gt;

&lt;p&gt;Pour cela, nous allons devoir modifier notre variable &lt;code&gt;OBJ&lt;/code&gt; et nous allons devoir créer un règle pour la compilation des .o. Nous ne pouvons plus utiliser les règles implicite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;BUILD_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; build
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC:&lt;span class="p"&gt;$(&lt;/span&gt;SRC_DIR&lt;span class="p"&gt;)&lt;/span&gt;/%.c&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="p"&gt;)&lt;/span&gt;/%.o&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Compilation des fichiers source
&lt;/span&gt;&lt;span class="nl"&gt;$(BUILD_DIR)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC_DIR)/%.c | $(BUILD_DIR)&lt;/span&gt;
&lt;span class="err"&gt;$(CC)&lt;/span&gt; &lt;span class="err"&gt;$(CFLAGS)&lt;/span&gt; &lt;span class="err"&gt;-c&lt;/span&gt; &lt;span class="err"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="err"&gt;$@&lt;/span&gt;

&lt;span class="c"&gt;# Creer le repertoire de build
&lt;/span&gt;&lt;span class="nl"&gt;$(BUILD_DIR)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;mkdir&lt;/span&gt; &lt;span class="err"&gt;-p&lt;/span&gt; &lt;span class="err"&gt;$(BUILD_DIR)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alors on remarque que cette fois-ci, nous n'avons pas défini une règle, mais avec une variable. Nous avons même utilisé une sorte de regex pour la définir. &lt;/p&gt;

&lt;p&gt;Nous avons aussi dû mettre un prérequis en plus, la règle $(build_dir). Le fait de mettre un &lt;code&gt;|&lt;/code&gt; signifie qu'il doit d'abord vérifier qu'il est nécessaire de faire cette règle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bibliothèque statique
&lt;/h3&gt;

&lt;p&gt;Pour créer une bibliothèque statique à partir des fichiers source, vous pouvez ajouter des règles au Makefile :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;LIB_TARGET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; libmylib.a
&lt;span class="nv"&gt;LIB_OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;filter-out &lt;span class="p"&gt;$(&lt;/span&gt;BUILD_DIR&lt;span class="p"&gt;)&lt;/span&gt;/main.o, &lt;span class="p"&gt;$(&lt;/span&gt;OBJS&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nl"&gt;$(LIB_TARGET)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(LIB_OBJS)&lt;/span&gt;
&lt;span class="err"&gt;ar&lt;/span&gt; &lt;span class="err"&gt;rcs&lt;/span&gt; &lt;span class="err"&gt;$@&lt;/span&gt; &lt;span class="err"&gt;$^&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Une fois, la librairie crée, vous pourrez simplement la link avec votre binaire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Makefile récursif
&lt;/h3&gt;

&lt;p&gt;Si votre projet comporte des sous-modules, vous pouvez utiliser un Makefile récursif. Imaginons un projet avec la structure suivante.&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;.&lt;/span&gt;
├── Makefile
└── src/
    ├── features1/
        ...
        └── Makefile
    ├── features2/
        ...
        └── Makefile
    ├── features3/
        ...
        └── Makefile
    ├── features4/
        ...
        └── Makefile
    ├── main.c
    └── Makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour cela, il y a deux approches possibles. La première serait de faire un seul makefile à la racine de notre projet et faire un find de nos fichiers .c. Nous verrons comment faire par la suite.&lt;/p&gt;

&lt;p&gt;La deuxième, c'est de faire une structure récursif via le Makefile suivant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# src/makefile 
&lt;/span&gt;&lt;span class="nv"&gt;SUBDIRS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="k"&gt;*&lt;/span&gt;/.&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;subdirs $(SUBDIRS)&lt;/span&gt;

&lt;span class="nl"&gt;subdirs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SUBDIRS)&lt;/span&gt;

&lt;span class="nl"&gt;$(SUBDIRS)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;MAKE&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avec ce fichier, nous allons pouvoir mettre un makefile dans chaque dossier features et lui et lui seul gérera la compilation de la features. Ils seront appelés par le &lt;code&gt;src/Makefile&lt;/code&gt; via la règles subdirs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# Makefile
&lt;/span&gt;
&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Werror&lt;/span&gt; &lt;span class="nt"&gt;-pedantic&lt;/span&gt;

&lt;span class="c"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;N'oubliez pas d'export vos variables dans votre Makefile afin qu´elle s'applique sur les Makefiles suivants.&lt;/p&gt;

&lt;p&gt;Ce genre d'architecture nécessite, la plupart du temps, de la combiner avec la création de librairie statique.&lt;/p&gt;

&lt;h3&gt;
  
  
  Répertoires infinis
&lt;/h3&gt;

&lt;p&gt;Nous avons vu comment utiliser la fonction &lt;code&gt;wildcard&lt;/code&gt; mais comment faire pour recuperer l'intégralité de nos fichiers sources ?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── Makefile
└── src/
    └── foo/
        └── bar/
            ...
                └── foobar/
                    └── barfoo/
                        └── here.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La prise en charge des répertoires "infinis" peut se faire via des règles génériques ou bien par l'intermédiaire d'un sub-shell.&lt;/p&gt;

&lt;p&gt;Par exemple :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# Attention, il faut que votre systeme possede la command find
&lt;/span&gt;
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;shell find &lt;span class="p"&gt;$(&lt;/span&gt;SRC_DIR&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.c"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ou bien&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# Je laisse les plus aventureux d'entre vous dechiffrer ce code
&lt;/span&gt;
&lt;span class="nv"&gt;rwildcard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;foreach d, &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;1:&lt;span class="o"&gt;=&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;, &lt;span class="p"&gt;$(&lt;/span&gt;call rwildcard,&lt;span class="nv"&gt;$d&lt;/span&gt;,&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;filter &lt;span class="p"&gt;$(&lt;/span&gt;subst &lt;span class="k"&gt;*&lt;/span&gt;,%,&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,&lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;rwildcard src,&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ou encore&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard src/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="p"&gt;$(&lt;/span&gt;wildcard src/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="c"&gt;# ... # &lt;/span&gt;
      &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;wildcard&lt;/span&gt; src/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# S'il vous plait, ne faites pas ca 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  $ make conclusion
&lt;/h2&gt;

&lt;p&gt;En conclusion, l'utilisation judicieuse des Makefiles est cruciale pour la gestion efficace de projets. Il permet d'économiser énormément de temps lors du processus de développement. Ce n'est pas pour rien que la quasi-intégralité de l'industrie utilise cet outil. &lt;/p&gt;

&lt;p&gt;Cette article n'étant bien entendu, pas exhaustif, je vous invite à vous renseigner par vous meme afin de découvrir les autres fonctionnalités de cet outil.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>make</category>
      <category>cpp</category>
    </item>
  </channel>
</rss>
