A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 7 месеца
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Make (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://www.arthurperret.fr/cours/make.html">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>Make</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://www.arthurperret.fr/cours/make.html" title="Lien vers le contenu original">Source originale</a>
  70. <br>
  71. Mis en cache le 2024-03-28
  72. </p>
  73. </nav>
  74. <hr>
  75. <h1 data-number="1"> Qu’est-ce que Make ?</h1>
  76. <p><a href="https://www.gnu.org/software/make/">Make</a> fait partie des logiciels d’automatisation des tâches : il sert à créer des processus dans lesquels des actions s’enchaînent automatiquement.</p>
  77. <p>À l’origine, Make est un outil conçu pour le développement de logiciels : il sert à automatiser la fabrication de programmes exécutables à partir de fichiers contenant du code.</p>
  78. <p>Mais en réalité, Make peut être utilisé pour gérer toutes sortes de projets. En tant que langage, il permet de définir des processus de manière très simple (encore plus simple que les <a href="ligne-de-commande.html#scripts-shell">scripts shell</a>). Et en tant qu’outil, il permet de gagner du temps, avec une gestion efficace des états des fichiers qui fait économiser du travail aussi bien à l’humain qu’à la machine.</p>
  79. <section id="origine-gerer-la-fabrication-de-programmes-informatiques" class="level2" data-number="1.1">
  80. <h2 data-number="1.1"> Origine : gérer la fabrication de programmes informatiques</h2>
  81. <p>Make a été inventé pour automatiser la fabrication de programmes exécutables. Un programme exécutable est un fichier qui se fabrique en deux temps : d’abord, on écrit du code dans des fichiers texte ; puis on exécute un programme appelé compilateur qui transforme le code en un fichier exécutable – cette deuxième étape, c’est la compilation.</p>
  82. <p>Make a été conçu en particulier pour déterminer quels fichiers doivent être recompilés lors de la fabrication d’un programme. Lorsqu’un fichier est modifié, il déclenche automatiquement les commandes appropriées. L’objectif était de ne pas tout recompiler si on ne modifiait qu’une petite partie du code d’un programme complexe, afin d’économiser des ressources et gagner du temps.</p>
  83. <p>Pour faire cela, Make s’appuie sur deux choses : la date de dernière modification des fichiers ; et un arbre de dépendances, c’est-à-dire une représentation des relations entre des fichiers cible, qu’on veut fabriquer, et des fichiers source (les « dépendances »), qui sont nécessaires à la fabrication des fichiers cible. Évidemment, un fichier cible peut à son tour être fichier source pour fabriquer un autre fichier cible, et ainsi de suite.</p>
  84. <p>Voici un exemple d’arbre de dépendances :</p>
  85. <figure>
  86. <img src="../img/make-arbre-dependances.svg" alt="Le programme « main.cpp » dépend de quatre fichiers, dont deux dépendent eux-mêmes d’autres fichiers. Diagramme inspiré de makefiletutorial.com">
  87. <figcaption aria-hidden="true">Le programme « main.cpp » dépend de quatre fichiers, dont deux dépendent eux-mêmes d’autres fichiers. Diagramme inspiré de <a href="https://makefiletutorial.com/">makefiletutorial.com</a></figcaption>
  88. </figure>
  89. <p>Si l’une des dépendances change, Make recompile le ou les fichiers cible correspondants. Dans l’exemple ci-dessus, si <code>one.h</code> est modifié, Make recompile <code>one.cpp</code> puis <code>main.cpp</code>, mais pas <code>two.cpp</code>.</p>
  90. </section>
  91. <section id="fonctionnement-les-makefiles" class="level2" data-number="1.2">
  92. <h2 data-number="1.2"> Fonctionnement : les Makefiles</h2>
  93. <p>Le fonctionnement de Make repose sur des fichiers texte appelés <em>Makefiles</em>. Dans un Makefile, on rédige des instructions appelées <strong>règles</strong> (<em>rules</em>) ; chaque règle définit une <strong>recette</strong> (<em>recipe</em>) pour fabriquer une ou plusieurs <strong>cibles</strong> (<em>targets</em>) suivant des <strong>prérequis</strong> (<em>prerequisites</em>).</p>
  94. <p>Les règles s’écrivent de la manière suivante :</p>
  95. <div class="sourceCode" id="cb1"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dv">cibles :</span><span class="dt"> prérequis</span></span>
  96. <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> recette</span></code></pre></div>
  97. <p>Ce sont les relations entre cibles et prérequis qui constituent l’arbre de dépendances modélisé par Make.</p>
  98. <p>Une recette est constituée d’une ou plusieurs <strong>commandes</strong> : des instructions textuelles qu’on exécuterait habituellement dans un terminal.</p>
  99. <div class="sourceCode" id="cb2"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dv">cibles :</span><span class="dt"> prérequis</span></span>
  100. <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> commande</span>
  101. <span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> commande</span>
  102. <span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> commande</span>
  103. <span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> …</span></code></pre></div>
  104. <p>Comme dans de nombreux langages informatiques, la syntaxe des Makefiles inclut la possibilité de créer des variables, de laisser des commentaires, de définir des fonctions qui incluent des étapes logiques, etc.</p>
  105. <p>Pour exécuter les instructions contenues dans un Makefile, il faut ouvrir un terminal, se déplacer à l’emplacement du Makefile, puis exécuter la commande <code>make</code> (ce qui déclenche les instructions qui sont contenues dans le Makefile).</p>
  106. <p>Si vous souhaitez découvrir comment utiliser un terminal, consultez ma page <a href="ligne-de-commande.html" class="cours">Ligne de commande</a>.</p>
  107. </section>
  108. <section id="utilisation-en-dehors-du-developpement-logiciel" class="level2" data-number="1.3">
  109. <h2 data-number="1.3"> Utilisation en dehors du développement logiciel</h2>
  110. <p>Progressivement, d’autres usages de Make ont émergé. En effet, son fonctionnement a une portée plus générale que la seule fabrication de programmes, car il ne pose aucune restriction sur la nature de la cible, des prérequis ou de la recette. On peut utiliser Make pour automatiser le déclenchement de n’importe quel programme qui s’utilise habituellement à la ligne de commande.</p>
  111. <p>Donc si Make est souvent présenté comme un outil d’automatisation pour la <em>compilation de programmes</em>, il serait en fait plus juste de le décrire comme un outil d’automatisation pour la <em>ligne de commande</em>. C’est un outil qui permet de définir des enchaînements de commandes textuelles ; dit de façon plus abstraite, Make permet de créer des processus, des séquences d’actions, où chaque action est une instruction envoyée à un ou plusieurs programmes à interface textuelle. Bref : Make permet de fabriquer des fabriques. (Clin d’œil à Antoine Fauchié qui a beaucoup travaillé sur ce concept de fabrique, voir <a href="https://www.quaternum.net/2023/06/02/fabrique-concept/">son blog</a> et <a href="https://these.quaternum.net/concepts/#fabrique">sa thèse</a>.)</p>
  112. <div class="exemple">
  113. <p>J’ai partagé un modèle de Makefile qui automatise l’utilisation de <a href="pandoc.html">Pandoc</a> pour générer différents exports à partir d’une même source : <a href="https://github.com/infologie/pandoc-ssp">Pandoc-SSP</a>. Make a complètement remplacé mon usage des scripts shell pour automatiser le déclenchement de commandes Pandoc. J’utiliserai Pandoc comme exemple à plusieurs reprises sur cette page.</p>
  114. <p>Make me sert donc à rédiger des recettes dans lesquelles je passe d’ingrédients de base (des fichiers) à un résultat final (d’autres fichiers). Mais comme me l’a fait remarquer David Larlet, on peut aussi l’utiliser pour des processus qui n’ont pas forcément de fichiers en entrée ou en sortie, comme la mise en place d’un serveur ou bien l’installation d’un logiciel. Make est un outil versatile.</p>
  115. </div>
  116. </section>
  117. <section id="outils-requis-pour-utiliser-make" class="level2" data-number="1.4">
  118. <h2 data-number="1.4"> Outils requis pour utiliser Make</h2>
  119. <p>Pour utiliser Make, vous avez besoin des choses suivantes :</p>
  120. <dl>
  121. <dt>Un terminal</dt>
  122. <dd>
  123. Si vous n’êtes pas familier de ce type d’environnement, consultez ma page <a href="ligne-de-commande.html" class="cours">Ligne de commande</a>.
  124. </dd>
  125. <dt>Le programme Make</dt>
  126. <dd>
  127. Make existe dans plusieurs versions. Cette page est écrite en référence à <a href="https://www.gnu.org/software/make/manual/">GNU Make</a>, la version la plus répandue. Sur Linux et macOS, Make est pré-installé ; pour vérifier de quelle version vous disposez, exécutez <code>make --version</code> dans un terminal. Sur Windows, vous pouvez installer Make par exemple en installant le gestionnaire de programmes <a href="https://chocolatey.org/install">Chocolatey</a>, puis en utilisant Chocolatey pour installer Make en ouvrant un terminal (je recommande PowerShell) et en exécutant la commande <code>choco install make</code>.
  128. </dd>
  129. <dt>Un éditeur de texte</dt>
  130. <dd>
  131. Pour rédiger des Makefiles. Je recommande souvent <a href="https://notepad-plus-plus.org">Notepad++</a> (Windows), <a href="http://www.barebones.com/products/bbedit/index.html">BBEdit</a> (macOS) et <a href="https://doc.ubuntu-fr.org/gedit">gedit</a> (Linux), mais n’importe quel éditeur de texte fera l’affaire.
  132. </dd>
  133. </dl>
  134. </section>
  135. </section>
  136. <section id="prise-en-main-ecrire-un-makefile-et-executer-make" class="level1" data-number="2">
  137. <h1 data-number="2"> Prise en main : écrire un Makefile et exécuter Make</h1>
  138. <p>Make s’utilise en écrivant des Makefiles et en utilisant la commande <code>make</code> dans un terminal. Par défaut, <code>make</code> cherche un fichier appelé <code>makefile</code> ou <code>Makefile</code> situé dans le répertoire courant. On peut aussi nommer un Makefile par n’importe quel <code>nom</code> et utiliser <code>make</code> avec l’option <code>--file=nom</code> ou <code>-f nom</code>.</p>
  139. <section id="regles-cibles-prerequis-recettes" class="level2" data-number="2.1">
  140. <h2 data-number="2.1"> Règles : cibles, prérequis, recettes</h2>
  141. <p>Un Makefile contient une ou plusieurs règles.</p>
  142. <p>La syntaxe générale d’une règle est la suivante :</p>
  143. <div class="sourceCode" id="cb3"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dv">cibles :</span><span class="dt"> prérequis</span></span>
  144. <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> recette</span></code></pre></div>
  145. <div class="important">
  146. <p>Notez l’espacement avant le mot « recette » : dans une règle, <strong>la recette doit être indentée avec une tabulation</strong> (une seule tabulation, pas d’espaces).</p>
  147. <p>(Si comme moi vous utilisez régulièrement YAML, un langage qui requiert d’indenter les lignes avec des espaces, préparez-vous à vous mélanger les pinceaux pendant quelques temps !)</p>
  148. </div>
  149. <p>Les <strong>cibles</strong> et les <strong>prérequis</strong> sont des noms de fichiers, séparés par des espaces. En pratique, il n’y a souvent qu’une cible par règle.</p>
  150. <p>La <strong>recette</strong> est constituée d’une ou plusieurs <strong>commandes</strong>, qui sont une série d’étapes utilisées pour créer la cible. Make applique la recette :</p>
  151. <ul>
  152. <li>si les cibles n’existent pas ;</li>
  153. <li>si les cibles existent mais que les prérequis ont une date de dernière modification plus récente que les cibles.</li>
  154. </ul>
  155. <div class="exemple">
  156. <p>Dans le Makefile suivant, la cible est un fichier PDF, <code>doc.pdf</code>. Elle a un prérequis qui est un fichier texte rédigé en Markdown, <code>doc.md</code>. La recette est constituée par une commande qui exécute le programme Pandoc.</p>
  157. <div class="sourceCode" id="cb4"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dv">doc.pdf :</span><span class="dt"> doc.md</span></span>
  158. <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> pandoc doc.md -o doc.pdf</span></code></pre></div>
  159. <p>Si j’exécute <code>make</code> :</p>
  160. <ul>
  161. <li>Si <code>doc.pdf</code> n’existe pas, ou qu’il existe mais que <code>doc.md</code> est plus récent (donc qu’il a été modifié depuis la dernière fabrication de <code>doc.pdf</code>), Make lance la commande Pandoc qui convertit le fichier Markdown en PDF.</li>
  162. <li>Si <code>doc.pdf</code> existe et que <code>doc.md</code> n’est pas plus récent, rien ne se passe.</li>
  163. </ul>
  164. </div>
  165. </section>
  166. <section id="cibles-factices" class="level2" data-number="2.2">
  167. <h2 data-number="2.2"> Cibles factices</h2>
  168. <p>Les cibles peuvent être des cibles « factices » (en anglais <em>phony</em>). Une cible factice ne correspond pas à un fichier réel : c’est une sorte de nom de code pour une série d’opérations qu’on veut exécuter. Les cibles factices doivent être déclarées comme prérequis de la cible spéciale <code>.PHONY</code>.</p>
  169. <div class="exemple">
  170. <p>Je reprends l’exemple précédent, avec cette fois deux fichiers Markdown, <code>doc-fr.md</code> et <code>doc-en.md</code>. Je définis une cible <code>all</code> qui a deux prérequis, les cibles <code>doc-fr.pdf</code> et <code>doc-en.pdf</code>.</p>
  171. <div class="sourceCode" id="cb5"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">.PHONY:</span><span class="dt"> all</span></span>
  172. <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
  173. <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="dv">doc-fr.pdf :</span><span class="dt"> doc-fr.md</span></span>
  174. <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> pandoc doc-fr.md -o doc-fr.pdf</span>
  175. <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
  176. <span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="dv">doc-en.pdf :</span><span class="dt"> doc-en.md</span></span>
  177. <span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> pandoc doc-en.md -o doc-en.pdf</span>
  178. <span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
  179. <span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="dv">all :</span><span class="dt"> doc-fr.pdf doc-en.pdf</span></span></code></pre></div>
  180. <p>Si j’exécute <code>make all</code>, Make déclenchera la fabrication des deux cibles correspondantes, à moins que les cibles existent déjà et qu’elles soient plus récentes que les prérequis.</p>
  181. </div>
  182. </section>
  183. <section id="ordre-dexecution-des-regles" class="level2" data-number="2.4">
  184. <h2 data-number="2.4"> Ordre d’exécution des règles</h2>
  185. <p>Si un Makefile contient plusieurs règles, par défaut <code>make</code> fabrique la première cible qu’il trouve dans le fichier. Il est possible de définir manuellement la cible à exécuter par défaut grâce à la variable spéciale <code>.DEFAULT_GOAL</code> (voir la section <a href="#variables-speciales">Variables spéciales</a> plus bas).</p>
  186. </section>
  187. <section id="options-dexecution" class="level2" data-number="2.5">
  188. <h2 data-number="2.5"> Options d’exécution</h2>
  189. <p>La commande <code>make</code> dispose de nombreuses options qui modifient son comportement. Utilisez <code>make --option</code> pour appliquer l’option correspondante lors de l’utilisation de Make. Plusieurs options peuvent être utilisées simultanément. La plupart des options sont disponibles sous plusieurs noms (notamment pour des questions de compatibilité), dont des formes raccourcies avec un seul tiret et une seule lettre, pour aller plus vite lorsqu’on saisit les commandes manuellement.</p>
  190. <p>Quelques exemples :</p>
  191. <ul>
  192. <li><code>-n</code> (ou <code>--just-print</code>, <code>--dry-run</code>, <code>--recon</code>) : affiche les commandes qui seraient exécutées, sans les exécuter. Ceci permet de vérifier ce que ferait un Makefile sans l’appliquer réellement.</li>
  193. <li><code>-j [jobs]</code> (ou <code>--jobs[=jobs]</code>) : autorise Make à exécuter simultanément un certain nombre de commandes (<code>jobs</code>). Si votre machine dispose d’un processeurs avec plusieurs cœurs, ceci permet de réduire considérablement le temps d’exécution du Makefile. Par exemple, avec un processeur à huit cœurs, vous pouvez utiliser l’option <code>-j 8</code> pour que Make lance jusqu’à huit commandes en parallèle (une par cœur).</li>
  194. </ul>
  195. <p>Dans un terminal, utilisez <code>man make</code> pour afficher le manuel et découvrir les options. Appuyez sur la touche <kbd>q</kbd> pour quitter le manuel.</p>
  196. </section>
  197. <section id="supprimer-lecho" class="level2" data-number="2.6">
  198. <h2 data-number="2.6"> Supprimer l’écho</h2>
  199. <p>Par défaut, Make affiche dans le terminal chaque ligne d’une recette exécutée. On appelle cela « l’écho », par analogie avec la commande <code>echo</code> qu’on utilise dans un terminal pour afficher des messages.</p>
  200. <p>Il y a plusieurs manières de supprimer l’écho :</p>
  201. <ul>
  202. <li>On peut préfixer une ligne par une arobase <code>@</code> pour supprimer l’écho pour cette ligne.</li>
  203. </ul>
  204. <div class="exemple">
  205. <div class="sourceCode" id="cb7"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">.PHONY:</span><span class="dt"> all</span></span>
  206. <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
  207. <span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="dv">doc-fr.pdf :</span><span class="dt"> doc-fr.md</span></span>
  208. <span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="ch">@</span><span class="fu">pandoc doc-fr.md -o doc-fr.pdf</span></span>
  209. <span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
  210. <span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="dv">doc-en.pdf :</span><span class="dt"> doc-en.md</span></span>
  211. <span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="ch">@</span><span class="fu">pandoc doc-en.md -o doc-en.pdf</span></span>
  212. <span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
  213. <span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="dv">all :</span><span class="dt"> doc-fr.pdf doc-en.pdf</span></span></code></pre></div>
  214. </div>
  215. <p>Remarque : il existe d’autres préfixes qu’on peut ajouter à une ligne pour modifier le comportement de Make. Par exemple, préfixer une ligne par <code>-</code> indique à Make qu’il ne doit pas s’interrompre en cas d’erreur, ce qui est pratique lorsqu’on dépanne un processus.</p>
  216. <ul>
  217. <li>On peut utiliser la cible spéciale <code>.SILENT</code> en indiquant des prérequis, ce qui supprimera l’écho pour la fabrication des prérequis correspondants.</li>
  218. </ul>
  219. <div class="exemple">
  220. <div class="sourceCode" id="cb8"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">.PHONY:</span><span class="dt"> all</span></span>
  221. <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">.SILENT:</span><span class="dt"> doc-fr.pdf doc-en.pdf</span></span>
  222. <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
  223. <span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="dv">doc-fr.pdf :</span><span class="dt"> doc-fr.md</span></span>
  224. <span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> pandoc doc-fr.md -o doc-fr.pdf</span>
  225. <span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
  226. <span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="dv">doc-en.pdf :</span><span class="dt"> doc-en.md</span></span>
  227. <span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> pandoc doc-en.md -o doc-en.pdf</span>
  228. <span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a></span>
  229. <span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="dv">all :</span><span class="dt"> doc-fr.pdf doc-en.pdf</span></span>
  230. <span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="co"># "make all" sera silencieux aussi !</span></span></code></pre></div>
  231. </div>
  232. <p>Remarque : <code>.PHONY</code> et <code>.SILENT</code> sont deux exemples de cibles spéciales. Voir <a href="https://www.gnu.org/software/make/manual/make.html#Special-Targets">Special Targets</a> dans le manuel GNU Make pour la liste complète.</p>
  233. <ul>
  234. <li>On peut utiliser l’option <code>-s</code> (ou <code>--silent</code>, <code>--quiet</code>) au moment d’exécuter la commande <code>make</code>. Toutes les recettes s’exécuteront alors silencieusement.</li>
  235. </ul>
  236. </section>
  237. </section>
  238. <section id="variables" class="level1" data-number="3">
  239. <h1 data-number="3"> Variables</h1>
  240. <p>Make permet de créer des variables, c’est-à-dire d’affecter une valeur à un nom pour pouvoir ensuite utiliser le nom à la place de la valeur. L’intérêt premier des variables, c’est d’éviter d’écrire plusieurs fois la même chose, pour économiser du travail et réduire le risque de faire des erreurs.</p>
  241. <p>Pour définir une variable :</p>
  242. <p>Pour utiliser la valeur de cette variable :</p>
  243. <div class="exemple">
  244. <p>Dans le Makefile ci-dessous, une longue liste de fichiers apparaît plusieurs fois :</p>
  245. <div class="sourceCode" id="cb11"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="dv">edit :</span><span class="dt"> main.o kbd.o command.o display.o insert.o search.o files.o utils.o</span></span>
  246. <span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o</span>
  247. <span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
  248. <span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="dv">clean :</span></span>
  249. <span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o</span></code></pre></div>
  250. <p>On peut définir une variable dont la valeur est cette liste de fichiers, puis utiliser le nom de la variable partout où cette liste doit être utilisée :</p>
  251. <div class="sourceCode" id="cb12"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">objects</span> <span class="ch">=</span><span class="st"> main.o kbd.o command.o display.o insert.o search.o files.o utils.o</span></span>
  252. <span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
  253. <span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="dv">edit :</span><span class="dt"> </span><span class="ch">$(</span><span class="dt">objects</span><span class="ch">)</span></span>
  254. <span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> cc -o edit <span class="ch">$(</span><span class="dt">objects</span><span class="ch">)</span></span>
  255. <span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
  256. <span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="dv">clean :</span></span>
  257. <span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a> rm edit <span class="ch">$(</span><span class="dt">objects</span><span class="ch">)</span></span></code></pre></div>
  258. </div>
  259. <p>Une variable peut être redéfinie, c’est-à-dire qu’on peut la définir à nouveau dans le même Makefile. La nouvelle valeur remplace alors la précédente.</p>
  260. <div class="exemple">
  261. <div class="sourceCode" id="cb13"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="dt">message</span> <span class="ch">=</span><span class="st"> Bonjour !</span></span>
  262. <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="dt">message</span> <span class="ch">=</span><span class="st"> Bonsoir !</span></span></code></pre></div>
  263. </div>
  264. <p>La valeur d’une variable peut elle-même contenir une ou plusieurs variables.</p>
  265. <div class="exemple">
  266. <div class="sourceCode" id="cb14"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">txt</span> <span class="ch">=</span><span class="st"> doc1.txt doc2.txt</span></span>
  267. <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="dt">img</span> <span class="ch">=</span><span class="st"> soleil.svg lune.svg</span></span>
  268. <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="dt">fichiers</span><span class="ch"> =</span><span class="st"> </span><span class="ch">$(</span><span class="dt">txt</span><span class="ch">)</span><span class="st"> </span><span class="ch">$(</span><span class="dt">img</span><span class="ch">)</span></span>
  269. <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="co"># la valeur de "fichiers" est "doc1.txt doc2.txt soleil.svg lune.svg"</span></span></code></pre></div>
  270. </div>
  271. <div class="important">
  272. <p>La plupart des langages informatiques reconnaissent plusieurs types de données, soit de manière implicite, soit de manière explicite grâce à l’ajout de caractères spéciaux. Exemple en JavaScript :</p>
  273. <div class="sourceCode" id="cb15"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> <span class="op">=</span> <span class="kw">true</span> <span class="co">// booléen (boolean)</span></span>
  274. <span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> <span class="op">=</span> <span class="dv">28</span> <span class="co">// nombre entier (integer)</span></span>
  275. <span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> <span class="op">=</span> <span class="st">"Bonjour !"</span> <span class="co">// chaîne de caractères (string)</span></span></code></pre></div>
  276. <p><strong>Make ne reconnaît qu’un type de données : la chaîne de caractères</strong> (en anglais : <em>string</em>). Par conséquent, il interprète les guillemets littéralement. Il est donc conseillé de n’utiliser les guillemets que lorsque la chaîne va être interprétée dans un autre environnement, par exemple lorsqu’on passe une variable au shell pour exécuter une commande.</p>
  277. <p>Ainsi, plutôt que :</p>
  278. <div class="sourceCode" id="cb16"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="dt">message</span> <span class="ch">=</span><span class="st"> "Bonjour !"</span></span>
  279. <span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="dv">test :</span></span>
  280. <span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> echo <span class="ch">$(</span><span class="dt">message</span><span class="ch">)</span></span></code></pre></div>
  281. <p>On écrira :</p>
  282. <div class="sourceCode" id="cb17"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="dt">message</span> <span class="ch">=</span><span class="st"> Bonjour !</span></span>
  283. <span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="dv">test :</span></span>
  284. <span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> echo <span class="st">"</span><span class="ch">$(</span><span class="dt">message</span><span class="ch">)</span><span class="st">"</span></span></code></pre></div>
  285. </div>
  286. <section id="expansion-et-operateurs-de-definition" class="level2" data-number="3.1">
  287. <h2 data-number="3.1"> Expansion et opérateurs de définition</h2>
  288. <p>On parle d’expansion pour désigner le fait de remplacer une expression de la forme <code>$(nom)</code> par la valeur de la variable correspondante.</p>
  289. <p>Ce concept devient important lorsqu’on définit des variables qui contiennent d’autres variables, et plus encore lorsque des variables sont redéfinies.</p>
  290. <p>En effet, Make permet de gérer de manière très fine l’ordre dans lequel se passe l’expansion. Ceci repose sur l’utilisation de différents opérateurs de définition (voir la section <a href="https://www.gnu.org/software/make/manual/make.html#Reading-Makefiles">How Make reads a Makefile</a> du manuel de GNU Make pour la liste des opérateurs et leurs effets). Or les différences de comportement entre ces opérateurs sont souvent source de confusion.</p>
  291. <p>Les deux opérateurs qu’on rencontre le plus fréquemment sont <code>=</code> et <code>:=</code>.</p>
  292. <ul>
  293. <li>Quand on utilise <code>=</code> pour définir une variable, l’expansion des variables contenues dans la valeur se fait au moment où la variable est <strong>utilisée</strong>. Ceci permet de changer la valeur en cours de route, si on redéfinit les variables utilisées dans la valeur.</li>
  294. </ul>
  295. <div class="exemple">
  296. <div class="sourceCode" id="cb18"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="dt">mot</span> <span class="ch">=</span><span class="st"> bonjour</span></span>
  297. <span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="dt">hello</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="dt">mot</span><span class="ch">)</span><span class="st"> à vous !</span></span>
  298. <span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="co"># la valeur de "hello" est "bonjour à vous !"</span></span>
  299. <span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span>
  300. <span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="co"># on redéfinit "mot" en changeant sa valeur</span></span>
  301. <span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="dt">mot</span> <span class="ch">=</span><span class="st"> bonsoir</span></span>
  302. <span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="co"># la valeur de "hello" est maintenant "bonsoir à vous !"</span></span></code></pre></div>
  303. </div>
  304. <ul>
  305. <li>Quand on utilise <code>:=</code> pour définir une variable, l’expansion des variables contenues dans la valeur se fait au moment où la variable est <strong>définie</strong>. Ceci permet de fixer la valeur une fois pour toutes. Exemple :</li>
  306. </ul>
  307. <div class="exemple">
  308. <div class="sourceCode" id="cb19"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="dt">mot</span> <span class="ch">=</span><span class="st"> bonjour</span></span>
  309. <span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="dt">hello</span><span class="ch"> :=</span><span class="st"> </span><span class="ch">$(</span><span class="dt">mot</span><span class="ch">)</span><span class="st"> à vous !</span></span>
  310. <span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="co"># la valeur de "hello" est "bonjour à vous !"</span></span>
  311. <span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span>
  312. <span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="co"># on redéfinit "mot"</span></span>
  313. <span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a><span class="dt">mot</span> <span class="ch">=</span><span class="st"> bonsoir</span></span>
  314. <span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="co"># la valeur de "hello" reste "bonjour à vous !"</span></span>
  315. <span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a></span>
  316. <span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="co"># on redéfinit cette fois "hello", on répète la première définition</span></span>
  317. <span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="dt">hello</span><span class="ch"> :=</span><span class="st"> </span><span class="ch">$(</span><span class="dt">mot</span><span class="ch">)</span><span class="st"> à vous !</span></span>
  318. <span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a><span class="co"># la valeur de "hello" est maintenant "bonsoir à vous !"</span></span></code></pre></div>
  319. </div>
  320. <p>En résumé :</p>
  321. <ul>
  322. <li>Si on définit des variables qui contiennent des variables, et qu’on modifie ces définitions en cours de route, alors on peut alterner entre <code>=</code> et <code>:=</code> suivant les besoins.</li>
  323. <li>En revanche, lorsqu’une variable contient une valeur simple (on parle aussi de valeur littérale), c’est-à-dire qu’elle ne contient pas elle-même de variable, alors utiliser <code>=</code> ou <code>:=</code> ne fait <strong>aucune différence</strong>, puisqu’il n’y a rien dans la valeur de la variable définie qui nécessite une expansion.</li>
  324. <li>Et lorsque le Makefile ne contient que des variables définies une seule fois, alors utiliser <code>=</code> ou <code>:=</code> ne fait <strong>aucune différence non plus</strong>, puisqu’il n’y a aucune redéfinition qui vient affecter l’expansion.</li>
  325. </ul>
  326. </section>
  327. <section id="variables-speciales" class="level2" data-number="3.2">
  328. <h2 data-number="3.2"> Variables spéciales</h2>
  329. <p>Make inclut quelques variables <em>spéciales</em>, dont le nom est réservé pour un comportement prédéfini.</p>
  330. <p>Par exemple, lorsqu’on exécute <code>make</code> sans argument, c’est la première règle contenue dans le Makefile qui est appliquée. On peut utiliser la variable spéciale <code>.DEFAULT_GOAL</code> pour définir la règle à appliquer par défaut.</p>
  331. <div class="exemple">
  332. <p>Avec le Makefile ci-dessous, exécuter <code>make</code> fabriquera <code>doc.html</code> au lieu de <code>all</code> :</p>
  333. <div class="sourceCode" id="cb20"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">.PHONY:</span><span class="dt"> all</span></span>
  334. <span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="dt">.DEFAULT_GOAL</span><span class="ch"> :=</span><span class="st"> doc.html</span></span>
  335. <span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a></span>
  336. <span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="dv">all :</span><span class="dt"> doc.pdf doc.html</span></span>
  337. <span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a></span>
  338. <span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="dv">doc.pdf :</span><span class="dt"> doc.md</span></span>
  339. <span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a> pandoc doc.md -o doc.pdf</span>
  340. <span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a></span>
  341. <span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a><span class="dv">doc.html :</span><span class="dt"> doc.md</span></span>
  342. <span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a> pandoc doc.md -o doc.html</span></code></pre></div>
  343. </div>
  344. <p>Voir <a href="https://www.gnu.org/software/make/manual/make.html#Special-Variables">Special Variables</a> dans le manuel GNU Make pour la liste complète.</p>
  345. </section>
  346. </section>
  347. <section id="fonctions" class="level1" data-number="5">
  348. <h1 data-number="5"> Fonctions</h1>
  349. <p>Make inclut la possibilité d’utiliser des fonctions pour manipuler du texte. Il y a des fonctions prédéfinies qui correspondent aux opérations les plus courantes : trier, chercher, filtrer, tronquer, etc. Il est également possible de définir ses propres fonctions.</p>
  350. <p>Une fonction s’utilise en faisant appel à son nom et en lui passant du texte en argument :</p>
  351. <div class="exemple">
  352. <ul>
  353. <li>La fonction <code>$(wildcard pattern)</code> cherche les noms de fichiers qui correspondent au motif <code>pattern</code>.</li>
  354. <li>La fonction de référence avec substitution <code>$(var:a=b)</code> remplace la chaîne de caractères <code>a</code> par <code>b</code> dans la variable <code>var</code>.</li>
  355. </ul>
  356. <p>Dans l’exemple ci-dessous, on combine ces deux fonctions pour créer une variable <code>input</code> qui contient les noms de fichiers Markdown présents dans le répertoire où se situe le Makefile, puis une variable <code>output</code> qui contient les mêmes noms en remplaçant l’extension <code>.md</code> par <code>.html</code>.</p>
  357. <div class="sourceCode" id="cb23"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="dt">input</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="kw">wildcard</span><span class="st"> *.md</span><span class="ch">)</span></span>
  358. <span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="dt">input</span><span class="kw">:</span><span class="ss">.md</span><span class="kw">=</span><span class="ss">.html</span><span class="ch">)</span></span>
  359. <span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="co"># si input a pour valeur par exemple "doc.md 2024-03-25.md"</span></span>
  360. <span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="co"># output aura pour valeur "doc.html 2024-03-25.html"</span></span></code></pre></div>
  361. </div>
  362. <p>Une fonction peut avoir pour argument une valeur littérale, une variable ou une fonction. Plusieurs fonctions peuvent ainsi être imbriquées les unes dans les autres, comme des poupées russes :</p>
  363. <div class="sourceCode" id="cb24"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ch">$(</span><span class="dt">fonction</span><span class="er"> </span><span class="ch">$(</span><span class="dt">fonction</span><span class="er"> </span><span class="ch">$(</span><span class="dt">fonction</span><span class="er"> </span><span class="dt">…</span><span class="er"> </span><span class="ch">)))</span></span></code></pre></div>
  364. <p>L’ordre d’exécution est simple à déterminer : c’est la fonction qui ne contient pas elle-même une autre fonction (la plus petite poupée russe) qui s’exécute en premier ; puis elle passe son résultat à la fonction qui la contient, et ainsi de suite jusqu’à la dernière fonction (la plus grande poupée russe), celle qui n’est pas elle-même contenue dans une autre fonction.</p>
  365. <p>La fonction <code>shell</code> est particulièrement utile. Comme son nom l’indique, elle permet de passer des commandes au shell, comme si on les exécutait dans un terminal.</p>
  366. <p>Voir <a href="https://www.gnu.org/software/make/manual/make.html#Functions">Fonctions</a> dans le manuel GNU Make pour la liste complète des fonctions.</p>
  367. </section>
  368. <section id="regles-implicites" class="level1" data-number="6">
  369. <h1 data-number="6"> Règles implicites</h1>
  370. <p>Contrairement aux règles de base (aussi appelées règles explicites), les règles implicites ne définissent pas comment fabriquer une cible précise à partir de prérequis définis, mais comment fabriquer des <em>types de cibles</em> à partir de <em>types de prérequis</em>.</p>
  371. <div class="important">
  372. <p>Une règle implicite ne définit pas de cibles. Lorsqu’on utilise une règle implicite, il faut donc par ailleurs définir explicitement les cibles à fabriquer.</p>
  373. </div>
  374. <section id="modeles-pattern-rules" class="level2" data-number="6.1">
  375. <h2 data-number="6.1"> Modèles <em>(pattern rules)</em></h2>
  376. <p>Dans une règle implicite, au lieu d’indiquer explicitement le nom de cibles et de prérequis, on indique le <strong>modèle</strong> (en anglais <em>pattern</em>) que doivent suivre ces noms. Un modèle de nom contient le symbole pourcentage <code>%</code>, qui constitue la part variable du modèle, avec éventuellement un préfixe et/ou un suffixe, qui constituent la part fixe du modèle.</p>
  377. <p>Exemples :</p>
  378. <ul>
  379. <li><code>%.txt</code> désigne tous les fichiers dont le nom finit par <code>.txt</code></li>
  380. <li><code>_%</code> désigne tous les fichiers dont le nom commence par <code>_</code></li>
  381. <li><code>_%.txt</code> désigne tous les fichiers dont le nom commence par <code>_</code> et finit par <code>.txt</code></li>
  382. </ul>
  383. <div class="exemple">
  384. <p>Dans le Makefile ci-dessous, on génère automatiquement les noms des cibles en utilisant la fonction <code>wildcard</code> et la fonction de référence avec substitution, et on crée une règle implicite qui définit comment fabriquer des fichiers HTML à partir de fichiers Markdown, quel que soit leur nom.</p>
  385. <div class="sourceCode" id="cb25"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="ot">.PHONY:</span><span class="dt"> html</span></span>
  386. <span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a></span>
  387. <span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="co"># liste des noms de fichiers Markdown présents</span></span>
  388. <span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="dt">input</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="kw">wildcard</span><span class="st"> *.md</span><span class="ch">)</span></span>
  389. <span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a></span>
  390. <span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a><span class="co"># liste des noms de fichiers HTML à fabriquer</span></span>
  391. <span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="dt">input</span><span class="kw">:</span><span class="ss">.md</span><span class="kw">=</span><span class="ss">.html</span><span class="ch">)</span></span>
  392. <span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a></span>
  393. <span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a><span class="co"># cible à fabriquer</span></span>
  394. <span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="dv">html :</span><span class="dt"> </span><span class="ch">$(</span><span class="dt">output</span><span class="ch">)</span></span>
  395. <span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a></span>
  396. <span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a><span class="co"># règle implicite pour la fabrication</span></span>
  397. <span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a><span class="dv">%.html :</span><span class="dt"> %.md</span></span>
  398. <span id="cb25-14"><a href="#cb25-14" aria-hidden="true" tabindex="-1"></a> recette …</span></code></pre></div>
  399. </div>
  400. </section>
  401. <section id="variables-automatiques" class="level2" data-number="6.2">
  402. <h2 data-number="6.2"> Variables automatiques</h2>
  403. <p>Comme pour les variables spéciales, les variables automatiques sont des variables dont le nom est réservé. En revanche, leur valeur n’est pas définie manuellement mais calculée automatiquement (d’où leur nom) en fonction du contexte.</p>
  404. <table>
  405. <caption>Exemples de variables automatiques</caption>
  406. <thead>
  407. </thead>
  408. <tbody>
  409. <tr class="odd">
  410. <td><code>$@</code></td>
  411. <td>nom de la cible</td>
  412. </tr>
  413. <tr class="even">
  414. <td><code>$&lt;</code></td>
  415. <td>nom du premier prérequis</td>
  416. </tr>
  417. <tr class="odd">
  418. <td><code>$^</code></td>
  419. <td>noms de tous les prérequis (séparés par des espaces)</td>
  420. </tr>
  421. </tbody>
  422. </table>
  423. <div class="important">
  424. <p>Les variables automatiques ne peuvent être utilisées que dans les recettes.</p>
  425. </div>
  426. <p>Les variables automatiques sont pensées pour être utilisées dans des règles implicites. Combiner les deux permet de réaliser facilement des traitements de fichiers par lots. À mes yeux, c’est l’une des fonctionnalités les plus utiles de Make.</p>
  427. <div class="exemple">
  428. <p>On reprend l’exemple précédent de la règle qui définit comment fabriquer des fichiers HTML à partir de fichiers Markdown et on ajoute une recette qui consiste à exécuter Pandoc en lui donnant le nom des prérequis <code>$^</code> comme entrée et le nom des cibles <code>$@</code> comme sortie.</p>
  429. <div class="sourceCode" id="cb26"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">.PHONY:</span><span class="dt"> html</span></span>
  430. <span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="dt">input</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="kw">wildcard</span><span class="st"> *.md</span><span class="ch">)</span></span>
  431. <span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="dt">output</span> <span class="ch">=</span><span class="st"> </span><span class="ch">$(</span><span class="dt">input</span><span class="kw">:</span><span class="ss">.md</span><span class="kw">=</span><span class="ss">.html</span><span class="ch">)</span></span>
  432. <span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a><span class="dv">html :</span><span class="dt"> </span><span class="ch">$(</span><span class="dt">output</span><span class="ch">)</span></span>
  433. <span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="dv">%.html :</span><span class="dt"> %.md</span></span>
  434. <span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> pandoc <span class="ch">$^</span> --output=<span class="ch">$@</span></span></code></pre></div>
  435. <p>Et voici une légère variation de la recette : on ajoute un prérequis, du coup on remplace <code>$^</code> par <code>$&lt;</code> pour ne plus passer en entrée tous les prérequis mais uniquement le nom du fichier Markdown.</p>
  436. <div class="sourceCode" id="cb27"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="dv">%.html :</span><span class="dt"> %.md styles.css</span></span>
  437. <span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a> pandoc <span class="ch">$&lt;</span> --css=styles.css --output=<span class="ch">$@</span></span></code></pre></div>
  438. </div>
  439. <p>Voir <a href="https://www.gnu.org/software/make/manual/make.html#Automatic-Variables">Automatic variables</a> dans le manuel GNU Make pour la liste complète des variables automatiques.</p>
  440. </section>
  441. </section>
  442. </article>
  443. <hr>
  444. <footer>
  445. <p>
  446. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  447. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  448. </svg> Accueil</a> •
  449. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  450. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  451. </svg> Suivre</a> •
  452. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  453. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  454. </svg> Pro</a> •
  455. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  456. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  457. </svg> Email</a> •
  458. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  459. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  460. </svg> Légal</abbr>
  461. </p>
  462. <template id="theme-selector">
  463. <form>
  464. <fieldset>
  465. <legend><svg class="icon icon-brightness-contrast">
  466. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  467. </svg> Thème</legend>
  468. <label>
  469. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  470. </label>
  471. <label>
  472. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  473. </label>
  474. <label>
  475. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  476. </label>
  477. </fieldset>
  478. </form>
  479. </template>
  480. </footer>
  481. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  482. <script>
  483. function loadThemeForm(templateName) {
  484. const themeSelectorTemplate = document.querySelector(templateName)
  485. const form = themeSelectorTemplate.content.firstElementChild
  486. themeSelectorTemplate.replaceWith(form)
  487. form.addEventListener('change', (e) => {
  488. const chosenColorScheme = e.target.value
  489. localStorage.setItem('theme', chosenColorScheme)
  490. toggleTheme(chosenColorScheme)
  491. })
  492. const selectedTheme = localStorage.getItem('theme')
  493. if (selectedTheme && selectedTheme !== 'undefined') {
  494. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  495. }
  496. }
  497. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  498. window.addEventListener('load', () => {
  499. let hasDarkRules = false
  500. for (const styleSheet of Array.from(document.styleSheets)) {
  501. let mediaRules = []
  502. for (const cssRule of styleSheet.cssRules) {
  503. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  504. continue
  505. }
  506. // WARNING: Safari does not have/supports `conditionText`.
  507. if (cssRule.conditionText) {
  508. if (cssRule.conditionText !== prefersColorSchemeDark) {
  509. continue
  510. }
  511. } else {
  512. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  513. continue
  514. }
  515. }
  516. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  517. }
  518. // WARNING: do not try to insert a Rule to a styleSheet you are
  519. // currently iterating on, otherwise the browser will be stuck
  520. // in a infinite loop…
  521. for (const mediaRule of mediaRules) {
  522. styleSheet.insertRule(mediaRule.cssText)
  523. hasDarkRules = true
  524. }
  525. }
  526. if (hasDarkRules) {
  527. loadThemeForm('#theme-selector')
  528. }
  529. })
  530. </script>
  531. </body>
  532. </html>