<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cross-Platform on kenji.blog</title><link>http://kenji.blog/fr/categories/cross-platform/</link><description>Recent content in Cross-Platform on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 08:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/categories/cross-platform/index.xml" rel="self" type="application/rss+xml"/><item><title>Les points essentiels du développement multiplateforme Mac et Windows</title><link>http://kenji.blog/fr/p/cross-platform-development-mac-windows/</link><pubDate>Sun, 13 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/cross-platform-development-mac-windows/</guid><description>&lt;img src="http://kenji.blog/p/cross-platform-development-mac-windows/img/eyecatch.jpg" alt="Featured image of post Les points essentiels du développement multiplateforme Mac et Windows" />&lt;p>Le développement multiplateforme à travers plusieurs systèmes d&amp;rsquo;exploitation (OS) tels que Mac (macOS), Windows, et même Linux (y compris WSL), est une étape incontournable de l&amp;rsquo;ingénierie logicielle moderne. Que ce soit pour le développement web, le backend d&amp;rsquo;applications mobiles, ou la création d&amp;rsquo;applications de bureau multiplateformes (Electron, Tauri, Qt, etc.), l&amp;rsquo;utilisation d&amp;rsquo;OS différents au sein d&amp;rsquo;une même équipe vous expose à de nombreux &amp;ldquo;bugs liés aux différences d&amp;rsquo;OS&amp;rdquo;.&lt;/p>
&lt;p>Chaque OS possède un contexte historique et une philosophie de conception qui lui sont propres. Alors que Windows dispose d&amp;rsquo;une architecture unique dérivée de MS-DOS (API Win32, noyau NT), macOS est basé sur UNIX (Darwin, basé sur FreeBSD), et Linux est conforme à la norme POSIX. Cette différence fondamentale crée des &amp;ldquo;pièges&amp;rdquo; qui tourmentent les développeurs dans tous les domaines, notamment les systèmes de fichiers, le réseau et la gestion des processus.&lt;/p>
&lt;p>Dans cet article, nous expliquerons de manière très détaillée et pratique les différences techniques et les meilleures pratiques que vous devez absolument connaître, que ce soit pour les équipes de développement mixtes Mac et Windows ou pour le développement d&amp;rsquo;applications ciblant les deux OS.&lt;/p>
&lt;hr>
&lt;h2 id="1-le-piège-des-caractères-de-fin-de-ligne-crlf-vs-lf-et-la-configuration-stricte-de-git">1. Le piège des caractères de fin de ligne (CRLF vs LF) et la configuration stricte de Git
&lt;/h2>&lt;p>L&amp;rsquo;une des causes les plus fréquentes de confusion dans le développement en équipe est le problème des &amp;ldquo;caractères de fin de ligne (Line Endings)&amp;rdquo;. Il s&amp;rsquo;agit d&amp;rsquo;un problème historique remontant à l&amp;rsquo;époque des machines à écrire.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Windows&lt;/strong> : Utilise &lt;strong>CRLF&lt;/strong>, une combinaison de retour chariot (CR, &lt;code>\r&lt;/code>, &lt;code>0x0D&lt;/code>) et de saut de ligne (LF, &lt;code>\n&lt;/code>, &lt;code>0x0A&lt;/code>), comme caractère de fin de ligne standard.&lt;/li>
&lt;li>&lt;strong>macOS / Linux&lt;/strong> : Utilise &lt;strong>LF&lt;/strong> (saut de ligne) seul comme caractère de fin de ligne standard. (Note : jusqu&amp;rsquo;à Mac OS 9, seul CR était utilisé, mais depuis Mac OS X, basé sur UNIX, c&amp;rsquo;est LF).&lt;/li>
&lt;/ul>
&lt;p>En raison de cette différence, lors du partage de code source dans un dépôt Git, les différences (diffs) peuvent s&amp;rsquo;étendre à l&amp;rsquo;ensemble du fichier. De même, si un script shell (&lt;code>.sh&lt;/code>) censé s&amp;rsquo;exécuter sous Linux est édité sous Windows et passe en CRLF, le &lt;code>\r&lt;/code> sera interprété comme un caractère non valide à l&amp;rsquo;exécution, provoquant des erreurs telles que &lt;code>\r: command not found&lt;/code>.&lt;/p>
&lt;h3 id="la-solution-dans-git--gérer-avec-gitattributes">La solution dans Git : Gérer avec &lt;code>.gitattributes&lt;/code>
&lt;/h3>&lt;p>Bien que Git dispose du paramètre &lt;code>core.autocrlf&lt;/code>, il est dangereux de s&amp;rsquo;y fier. Comme cela dépend de la configuration globale de la machine locale de chaque développeur, des problèmes surviennent souvent lorsqu&amp;rsquo;un nouveau membre rejoint l&amp;rsquo;équipe avec des paramètres manquants.&lt;/p>
&lt;p>La meilleure pratique consiste à placer un fichier &lt;code>.gitattributes&lt;/code> dans le répertoire racine du dépôt et à définir explicitement la gestion des caractères de fin de ligne au niveau du dépôt. Cela garantit un comportement cohérent, quel que soit l&amp;rsquo;environnement dans lequel il est cloné.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"># Par défaut, traite comme des fichiers texte et normalise en LF dans le dépôt (base de données Git)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Converti dans le caractère de fin de ligne standard du système d&amp;#39;exploitation lors du checkout
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">* text=auto
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Cependant, pour certaines extensions comme le code source, LF est toujours forcé quel que soit l&amp;#39;OS
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.sh text eol=lf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.py text eol=lf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.cpp text eol=lf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.hpp text eol=lf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.js text eol=lf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.json text eol=lf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Pour les fichiers batch exclusifs à Windows, CRLF est forcé
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.cmd text eol=crlf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.bat text eol=crlf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Ne pas convertir les caractères de fin de ligne pour les images ou les binaires (pour éviter la corruption)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.png binary
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.jpg binary
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">*.pdf binary
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="2-sensibilité-à-la-casse-du-système-de-fichiers-case-sensitivity">2. Sensibilité à la casse du système de fichiers (Case Sensitivity)
&lt;/h2>&lt;p>La sensibilité à la casse (Case Sensitivity) des systèmes de fichiers est également l&amp;rsquo;un des plus grands défis du développement multiplateforme.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>macOS (APFS / HFS+)&lt;/strong> : Par défaut, &lt;strong>ne distingue pas les majuscules et minuscules (Case-Insensitive)&lt;/strong>, mais &lt;strong>préserve la casse (Case-Preserving)&lt;/strong>. En d&amp;rsquo;autres termes, si vous l&amp;rsquo;enregistrez sous &lt;code>File.txt&lt;/code>, il s&amp;rsquo;affichera comme &lt;code>File.txt&lt;/code>, mais vous pourrez toujours le lire depuis un programme en y accédant avec &lt;code>file.txt&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Windows (NTFS)&lt;/strong> : Comme macOS, il &lt;strong>ne distingue pas les majuscules et minuscules (Case-Insensitive)&lt;/strong> par défaut, mais il &lt;strong>préserve la casse (Case-Preserving)&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Linux / WSL (ext4, etc.)&lt;/strong> : &lt;strong>Sensible à la casse (Case-Sensitive)&lt;/strong>. &lt;code>File.txt&lt;/code> et &lt;code>file.txt&lt;/code> peuvent coexister dans le même répertoire comme deux fichiers totalement différents.&lt;/li>
&lt;/ul>
&lt;h3 id="bug-typique-rencontré">Bug typique rencontré
&lt;/h3>&lt;p>Lors du développement sur Mac ou Windows, si vous spécifiez &lt;code>#include &amp;quot;myclass.h&amp;quot;&lt;/code> (ou &lt;code>import &amp;quot;./myclass&amp;quot;&lt;/code>) en minuscules dans le code source alors que le fichier réel est &lt;code>MyClass.h&lt;/code>, la compilation réussira car l&amp;rsquo;OS de l&amp;rsquo;environnement local est Case-Insensitive.&lt;/p>
&lt;p>Cependant, lorsque vous commitez ce code et exécutez le build sur un serveur CI/CD (généralement Linux comme Ubuntu), le système de fichiers ext4 de Linux étant Case-Sensitive, cela provoquera une erreur de compilation &amp;ldquo;fichier introuvable&amp;rdquo;.&lt;/p>
&lt;h3 id="perspective-algorithmique--complexité-de-la-recherche-de-fichiers-et-normalisation">Perspective algorithmique : Complexité de la recherche de fichiers et normalisation
&lt;/h3>&lt;p>Voyons mathématiquement quel processus interne se produit lorsqu&amp;rsquo;un système de fichiers résout un chemin de fichier.&lt;/p>
&lt;p>Dans le cas de ext4, qui distingue les majuscules et minuscules, les entrées dans un répertoire sont gérées par des structures telles que des tables de hachage ou des arbres B (B-Tree). Si le nombre de fichiers dans un répertoire est $N$ et la longueur du nom de fichier est $L$, la complexité d&amp;rsquo;une simple recherche binaire ou d&amp;rsquo;une recherche dans l&amp;rsquo;arbre sera la suivante :&lt;/p>
$$ T_{search}(N) = O(L \log N) $$&lt;p>En revanche, pour les systèmes de fichiers comme NTFS et APFS qui ne font pas la distinction entre les majuscules et minuscules, il est nécessaire de normaliser (Case Folding) les deux chaînes dans la même casse (majuscule ou minuscule) avant de les comparer. La normalisation Unicode et la conversion de casse prenant en compte les paramètres régionaux (locale) ne se limitent pas à de simples opérations sur les bits ASCII, mais nécessitent des recherches dans des tables (table lookup).&lt;/p>
&lt;p>Si nous considérons le coût de calcul de la fonction de conversion comme une constante $C_{fold}$, une surcharge (overhead) supplémentaire s&amp;rsquo;ajoute à chaque comparaison de chaîne.&lt;/p>
$$ T_{insensitive\_search}(N) = O( (L \times C_{fold}) \log N ) $$&lt;p>Les systèmes d&amp;rsquo;exploitation récents mettent ces données en cache de manière avancée, mais les différences fondamentales de comportement ne peuvent être contraintes que par des règles au niveau du développement. L&amp;rsquo;approche la plus sûre consiste à établir une règle de projet stipulant que &lt;strong>&amp;ldquo;tous les noms de fichiers et de répertoires doivent être uniformisés en minuscules et avec des tirets (kebab-case) ou des tirets bas (snake_case)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="3-séparateurs-de-chemin-path-separators-et-abstraction-des-chemins-de-fichiers">3. Séparateurs de chemin (Path Separators) et abstraction des chemins de fichiers
&lt;/h2>&lt;p>La gestion des caractères de séparation indiquant la hiérarchie des répertoires reflète les différences fondamentales entre les OS.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Windows&lt;/strong> : Utilise l&amp;rsquo;antislash &lt;code>\&lt;/code> (parfois affiché comme le symbole Yen &lt;code>¥&lt;/code> selon les polices dans les environnements japonais) et possède également les concepts de lettre de lecteur (ex : &lt;code>C:\&lt;/code>) et de chemin UNC (ex : &lt;code>\\Server\Share&lt;/code>).&lt;/li>
&lt;li>&lt;strong>macOS / Linux&lt;/strong> : Utilise le slash &lt;code>/&lt;/code>, et tous les systèmes de fichiers ont une structure hiérarchique partant d&amp;rsquo;une racine unique &lt;code>/&lt;/code> (Single Root Hierarchy).&lt;/li>
&lt;/ul>
&lt;p>De nombreux langages de programmation interprètent intelligemment &lt;code>/&lt;/code> comme un séparateur de fichiers même sous Windows (l&amp;rsquo;API Win32 elle-même prenant en partie en charge &lt;code>/&lt;/code>). Cependant, cela provoque des erreurs fatales lors de la transmission de chemins en tant qu&amp;rsquo;arguments de ligne de commande, lors de l&amp;rsquo;appel direct d&amp;rsquo;appels système, ou lors de la comparaison ou de l&amp;rsquo;analyse de chemins sous forme de chaînes de caractères.&lt;/p>
&lt;h3 id="meilleures-pratiques-selon-les-langages-abstraction-de-los">Meilleures pratiques selon les langages (Abstraction de l&amp;rsquo;OS)
&lt;/h3>&lt;p>Évitez &lt;strong>absolument&lt;/strong> de construire des chemins de fichiers par concaténation de chaînes (ex : &lt;code>path + &amp;quot;\\&amp;quot; + filename&lt;/code>). Utilisez les bibliothèques standard de manipulation de chemins (OS Abstraction Layer) fournies par chaque langage.&lt;/p>
&lt;h4 id="exemple-en-c-stdfilesystem">Exemple en C++ (&lt;code>std::filesystem&lt;/code>)
&lt;/h4>&lt;p>Depuis C++17, &lt;code>&amp;lt;filesystem&amp;gt;&lt;/code> a été introduit pour abstraire les différences de chemins entre les plateformes.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;filesystem&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">namespace&lt;/span> &lt;span class="n">fs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">filesystem&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Construction de chemin indépendante de l&amp;#39;OS (abstraction par surcharge d&amp;#39;opérateur)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">fs&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">path&lt;/span> &lt;span class="n">dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;data&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fs&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">path&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;config.json&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fs&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">path&lt;/span> &lt;span class="n">full_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dir&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Devient &amp;#34;data\config.json&amp;#34; sous Windows et &amp;#34;data/config.json&amp;#34; sous Mac/Linux
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Full path: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">full_path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="exemple-en-python-pathlib">Exemple en Python (&lt;code>pathlib&lt;/code>)
&lt;/h4>&lt;p>Auparavant, &lt;code>os.path.join()&lt;/code> était utilisé, mais de nos jours, il est standard d&amp;rsquo;utiliser le module orienté objet &lt;code>pathlib&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pathlib&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># L&amp;#39;opérateur / est surchargé et génère un objet chemin adapté à l&amp;#39;OS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">base_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;user_data&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">config_file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">base_dir&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="s2">&amp;#34;settings&amp;#34;&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="s2">&amp;#34;app.ini&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># La résolution de chemin et la lecture de fichiers sont également possibles avec des méthodes cohérentes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">config_file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config_file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read_text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="exemple-en-nodejs-module-path">Exemple en Node.js (Module &lt;code>path&lt;/code>)
&lt;/h4>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// path.join prend des arguments et les combine avec le séparateur approprié pour l&amp;#39;OS actuel
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">configPath&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;config&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;default.json&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">configPath&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Windows: &amp;#34;config\default.json&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// macOS/Linux: &amp;#34;config/default.json&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="4-encodage-des-caractères-utf-8-vs-cp932shift-jis-et-la-barrière-de-unicode">4. Encodage des caractères (UTF-8 vs CP932/Shift-JIS) et la barrière de Unicode
&lt;/h2>&lt;p>L&amp;rsquo;encodage des caractères est la plus grande source de problèmes dans l&amp;rsquo;environnement Windows japonais.
Dans le développement moderne, macOS et Linux sont entièrement unifiés avec &lt;strong>UTF-8&lt;/strong>, du système global jusqu&amp;rsquo;aux terminaux et l&amp;rsquo;encodage de fichiers. Cependant, l&amp;rsquo;encodage standard sur la version japonaise de Windows (la &amp;ldquo;page de codes ANSI&amp;rdquo; basée sur les paramètres régionaux du système) utilise encore souvent &lt;strong>CP932 (une extension Microsoft de Shift-JIS)&lt;/strong> par défaut.&lt;/p>
&lt;ul>
&lt;li>Note : La représentation interne des chaînes dans l&amp;rsquo;API Win32 est UTF-16LE (&lt;code>wchar_t&lt;/code>).&lt;/li>
&lt;/ul>
&lt;p>Lors de la lecture ou de l&amp;rsquo;écriture de fichiers en Python ou autres sans spécifier d&amp;rsquo;encodage, Windows tentera de les interpréter selon le résultat de &lt;code>locale.getpreferredencoding()&lt;/code> (CP932). Cela peut entraîner une erreur &lt;code>UnicodeDecodeError&lt;/code> ou du texte corrompu (Mojibake) lors d&amp;rsquo;une tentative de lecture d&amp;rsquo;un fichier enregistré en UTF-8.&lt;/p>
&lt;h3 id="modèle-mathématique-de-conversion-des-codes-de-caractères-et-surcharge-overhead">Modèle mathématique de conversion des codes de caractères et surcharge (overhead)
&lt;/h3>&lt;p>Lors de la conversion d&amp;rsquo;une chaîne d&amp;rsquo;un encodage (UTF-8) à un autre (UTF-16 ou CP932), la complexité temporelle dans le pire des cas est proportionnelle à la longueur de la chaîne. Si la longueur en octets de la chaîne est $B$, la complexité de conversion est $O(B)$. Cependant, l&amp;rsquo;analyse syntaxique (parsing) de l&amp;rsquo;UTF-8 à longueur variable, le calcul des paires de substitution (surrogate pairs) et la recherche dans la table de conversion (Lookup) génèrent une surcharge non négligeable.&lt;/p>
&lt;p>Si la longueur de la chaîne est $N$, que la fonction mappant les caractères multioctets vers les points de code Unicode est $f_{decode}$, et que la fonction mappant les points de code vers l&amp;rsquo;encodage de destination est $f_{encode}$, alors le temps de conversion total $T_{conv}$ est approximé de la façon suivante :&lt;/p>
$$ T_{conv} = \sum_{i=1}^{N} \Big( C_{decode} \cdot f_{decode}(x_i) + C_{encode} \cdot f_{encode}(y_i) \Big) \approx O(N) $$&lt;p>Dans les applications multiplateformes, il est important de réaliser que ce coût de conversion se produit chaque fois qu&amp;rsquo;une API native de l&amp;rsquo;OS est appelée (traversée de la limite I/O). (En particulier lors du développement en C++ pour Windows, les conversions vers UTF-16 via des fonctions comme &lt;code>MultiByteToWideChar&lt;/code> surviennent fréquemment).&lt;/p>
&lt;h3 id="mesures-concernant-lencodage">Mesures concernant l&amp;rsquo;encodage
&lt;/h3>&lt;p>La mesure la plus sûre est de &lt;strong>&amp;ldquo;toujours spécifier explicitement UTF-8 en toutes circonstances&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Bon exemple en Python : Toujours spécifier encoding=&amp;#34;utf-8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;data.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Bonjour, le monde !&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>De plus, pour que la sortie UTF-8 s&amp;rsquo;affiche correctement dans le terminal Windows (Invite de commandes ou PowerShell), il peut être nécessaire de définir la variable d&amp;rsquo;environnement &lt;code>PYTHONUTF8=1&lt;/code> au démarrage de l&amp;rsquo;application, ou si vous utilisez Node.js, de modifier temporairement la page de codes de la console en UTF-8 à l&amp;rsquo;aide de la commande &lt;code>chcp 65001&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-différences-entre-les-variables-denvironnement-et-les-environnements-shell-bashzsh-vs-powershell">5. Différences entre les variables d&amp;rsquo;environnement et les environnements Shell (bash/zsh vs PowerShell)
&lt;/h2>&lt;p>Les différences entre les shells (interpréteurs de ligne de commande) lors de l&amp;rsquo;exécution de scripts de build ou d&amp;rsquo;outils de développement constituent également un obstacle majeur au multiplateforme.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>macOS / Linux&lt;/strong> : &lt;code>bash&lt;/code> ou &lt;code>zsh&lt;/code> sont les plus courants. Ils effectuent un traitement de pipeline basé sur le texte.&lt;/li>
&lt;li>&lt;strong>Windows&lt;/strong> : L&amp;rsquo;invite de commandes (&lt;code>cmd.exe&lt;/code>) ou &lt;code>PowerShell&lt;/code>. PowerShell est basé sur .NET et dispose d&amp;rsquo;un puissant pipeline orienté objet, mais sa syntaxe est totalement différente des shells POSIX.&lt;/li>
&lt;/ul>
&lt;p>Parce que les méthodes de référencement et de configuration des variables d&amp;rsquo;environnement diffèrent, l&amp;rsquo;utilisation de syntaxes dépendantes de l&amp;rsquo;OS, comme dans la section &lt;code>scripts&lt;/code> du &lt;code>package.json&lt;/code> de Node.js, fera que cela ne fonctionnera pas dans d&amp;rsquo;autres environnements.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ❌ Mauvais exemple : Sous Windows, &amp;#34;NODE_ENV&amp;#34; n&amp;#39;est pas reconnu comme une commande et provoque une erreur
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="s2">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;build&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;NODE_ENV=production webpack&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="solution--utilisation-doutils-dédiés-au-multiplateforme">Solution : Utilisation d&amp;rsquo;outils dédiés au multiplateforme
&lt;/h3>&lt;p>Dans un environnement Node.js, utilisez des paquets comme &lt;code>cross-env&lt;/code> pour abstraire la configuration des variables d&amp;rsquo;environnement.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ✅ Bon exemple : cross-env gère les différences d&amp;#39;OS, configure les variables d&amp;#39;environnement correctement et lance webpack
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="s2">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;build&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;cross-env NODE_ENV=production webpack&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;clean&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;rimraf dist/&amp;#34;&lt;/span> &lt;span class="c1">// Utiliser un outil de suppression multiplateforme au lieu de rm -rf
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Si des scripts shell complexes sont nécessaires dans des projets à grande échelle, la meilleure pratique actuelle consiste à standardiser l&amp;rsquo;utilisation de WSL (Windows Subsystem for Linux) ou de Git Bash pour les développeurs Windows, et à gérer de manière unifiée tous les traitements par lots (batch processing) sous forme de scripts &lt;code>.sh&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="6-systèmes-de-build-et-compilateurs-multiplateformes">6. Systèmes de build et compilateurs multiplateformes
&lt;/h2>&lt;p>Lors de la manipulation de code natif comme en C++ ou en Rust (langages compilés directement en code machine), il faut non seulement surmonter les différences d&amp;rsquo;API spécifiques à l&amp;rsquo;OS, mais aussi celles des systèmes de build et des compilateurs.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Compilateurs&lt;/strong> :
&lt;ul>
&lt;li>Windows: MSVC (Microsoft Visual C++), MinGW (GCC for Windows)&lt;/li>
&lt;li>macOS: Apple Clang&lt;/li>
&lt;li>Linux: GCC, Clang&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Formats binaires&lt;/strong> :
&lt;ul>
&lt;li>Windows: PE (Portable Executable) &lt;code>.exe&lt;/code> / &lt;code>.dll&lt;/code>&lt;/li>
&lt;li>macOS: Mach-O&lt;/li>
&lt;li>Linux: ELF (Executable and Linkable Format) &lt;code>.so&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="utilisation-du-système-de-méta-build-via-cmake">Utilisation du système de méta-build via CMake
&lt;/h3>&lt;p>Pour les projets C/C++, le standard mondial de facto pour réaliser le multiplateforme est &lt;strong>CMake&lt;/strong>. CMake ne compile pas le code source directement, mais fonctionne comme un &amp;ldquo;Générateur (Generator)&amp;rdquo; qui crée des fichiers de configuration de build natifs adaptés à chaque environnement (des fichiers de solution Visual Studio pour Windows, et des Makefile ou scripts de build Ninja pour Linux/Mac).&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;CMakeLists.txt (Indépendant de la plateforme)&amp;#34;] --&amp;gt; B(&amp;#34;Moteur CMake&amp;#34;)
B --&amp;gt; C{&amp;#34;Système d&amp;#39;exploitation cible&amp;#34;}
C --&amp;gt;|Windows| D[&amp;#34;Solution Visual Studio / MSBuild&amp;#34;]
C --&amp;gt;|macOS| E[&amp;#34;Projet Xcode / Apple Clang&amp;#34;]
C --&amp;gt;|Linux| F[&amp;#34;Makefile / Ninja / GCC&amp;#34;]
D --&amp;gt; G[&amp;#34;Exécutable Windows (.exe)&amp;#34;]
E --&amp;gt; H[&amp;#34;Exécutable macOS (Mach-O)&amp;#34;]
F --&amp;gt; I[&amp;#34;Exécutable Linux (ELF)&amp;#34;]
&lt;/pre>
&lt;p>L&amp;rsquo;utilisation de CMake permet d&amp;rsquo;absorber les différences entre environnements et de générer le binaire optimal pour chaque OS à partir d&amp;rsquo;un fichier de configuration unique (&lt;code>CMakeLists.txt&lt;/code>). La résolution des bibliothèques dépendantes (&lt;code>find_package&lt;/code>) ainsi que la liaison (link) à des bibliothèques spécifiques à chaque OS peuvent être facilement décrites grâce aux instructions conditionnelles.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Exemple partiel de CMakeLists.txt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">WIN32&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="c"># Lier des bibliothèques spécifiques à Windows (ex: WS2_32.lib)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">my_app&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">ws2_32&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">OS_WINDOWS&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">elseif&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">APPLE&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="c"># Lier des frameworks spécifiques à macOS
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">my_app&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s2">&amp;#34;-framework Foundation&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">OS_MACOS&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">elseif&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">UNIX&lt;/span> &lt;span class="s">AND&lt;/span> &lt;span class="s">NOT&lt;/span> &lt;span class="s">APPLE&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="c"># Liens pour Linux (ex: pthread)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">my_app&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">pthread&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">OS_LINUX&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-utilisation-de-modèles-darchitecture--couche-dabstraction-de-los-osal">7. Utilisation de modèles d&amp;rsquo;architecture : Couche d&amp;rsquo;abstraction de l&amp;rsquo;OS (OSAL)
&lt;/h2>&lt;p>La clé du développement multiplateforme est de séparer complètement les traitements dépendants du système (manipulation de fichiers, création de processus/threads, gestion de la mémoire, communication par sockets, etc.) de la logique métier (business logic) qui constitue le cœur de l&amp;rsquo;application.&lt;/p>
&lt;p>Pour y parvenir, nous utilisons un modèle appelé &lt;strong>Couche d&amp;rsquo;abstraction de l&amp;rsquo;OS (OS Abstraction Layer, OSAL)&lt;/strong>.&lt;/p>
&lt;p>Voici un exemple de conception de classe qui encapsule (wrap) les API spécifiques de chaque OS et fournit une interface commune. L&amp;rsquo;implémentation est basculée en utilisant le polymorphisme ou des commutateurs macro (macro switches) au moment de la compilation.&lt;/p>
&lt;pre class="mermaid">
classDiagram
class SystemInterface {
&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;
+createDirectory(path: string) bool
+getSystemMemoryUsage() uint64
+spawnProcess(command: string) int
}
class WindowsSystem {
+createDirectory(path: string) bool
+getSystemMemoryUsage() uint64
+spawnProcess(command: string) int
}
class PosixSystem {
+createDirectory(path: string) bool
+getSystemMemoryUsage() uint64
+spawnProcess(command: string) int
}
SystemInterface &amp;lt;|-- WindowsSystem
SystemInterface &amp;lt;|-- PosixSystem
&lt;/pre>
&lt;p>De cette manière, en isolant le code spécifique à la plateforme à un seul endroit (généralement dans des répertoires comme &lt;code>src/platform/windows/&lt;/code> ou &lt;code>src/platform/posix/&lt;/code>), il est possible de maintenir les 95 % du code restants (logique de l&amp;rsquo;interface graphique, traitement des données, analyse syntaxique des protocoles de communication, etc.) de manière entièrement multiplateforme et testable.&lt;/p>
&lt;hr>
&lt;h2 id="8-validation-multiplateforme-en-cicd-build-matriciel">8. Validation multiplateforme en CI/CD (Build matriciel)
&lt;/h2>&lt;p>Quel que soit le soin avec lequel un développeur code dans son environnement local, le bastion final de la compatibilité multiplateforme est le &lt;strong>pipeline CI/CD (Intégration Continue / Déploiement Continu)&lt;/strong>. Les cas où le code fonctionne dans un environnement local (comme sur Mac) mais entraîne des erreurs de compilation sur d&amp;rsquo;autres OS (Windows) sont innombrables.&lt;/p>
&lt;p>Utilisez les derniers outils CI tels que GitHub Actions ou GitLab CI, et configurez un build matriciel (Matrix Build) pour &lt;strong>exécuter en parallèle les builds et les tests dans tous les environnements (Windows, macOS, Linux)&lt;/strong> à chaque création de Pull Request.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Exemple de configuration CI multiplateforme via GitHub Actions&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Cross-Platform Build and Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">push, pull_request]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ matrix.os }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">strategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">fail-fast&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Continuer les tests sur les autres OS même si l&amp;#39;un échoue&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matrix&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Spécifier 3 runners : Windows, macOS et Linux&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">os&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">ubuntu-latest, windows-latest, macos-latest]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Set up Python Environment&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-python@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.11&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cache&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;pip&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Mettre en cache les dépendances même pour le multiplateforme&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install dependencies&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">python -m pip install --upgrade pip &amp;amp;&amp;amp; pip install -r requirements.txt&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Run Test Suite&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytest -v&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>La visualisation de ce flux CI/CD donne le résultat suivant.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant Dev as &amp;#34;Développeur&amp;#34;
participant GitHub as &amp;#34;GitHub Actions (Coordinateur)&amp;#34;
participant Ubuntu as &amp;#34;Runner Linux (VM)&amp;#34;
participant Windows as &amp;#34;Runner Windows (VM)&amp;#34;
participant Mac as &amp;#34;Runner macOS (VM)&amp;#34;
Dev-&amp;gt;&amp;gt;GitHub: &amp;#34;git push origin feature-branch&amp;#34;
GitHub-&amp;gt;&amp;gt;Ubuntu: &amp;#34;Lancement du job (ubuntu-latest)&amp;#34;
GitHub-&amp;gt;&amp;gt;Windows: &amp;#34;Lancement du job (windows-latest)&amp;#34;
GitHub-&amp;gt;&amp;gt;Mac: &amp;#34;Lancement du job (macos-latest)&amp;#34;
par Parallel Execution Matrix
Ubuntu--&amp;gt;&amp;gt;Ubuntu: &amp;#34;Checkout, Configuration de l&amp;#39;environnement, Build, Test&amp;#34;
Windows--&amp;gt;&amp;gt;Windows: &amp;#34;Checkout, Configuration de l&amp;#39;environnement, Build, Test&amp;#34;
Mac--&amp;gt;&amp;gt;Mac: &amp;#34;Checkout, Configuration de l&amp;#39;environnement, Build, Test&amp;#34;
end
Ubuntu--&amp;gt;&amp;gt;GitHub: &amp;#34;Résultat : Succès (Pass)&amp;#34;
Windows--&amp;gt;&amp;gt;GitHub: &amp;#34;Résultat : Échec (Fail - erreur d&amp;#39;encodage)&amp;#34;
Mac--&amp;gt;&amp;gt;GitHub: &amp;#34;Résultat : Succès (Pass)&amp;#34;
GitHub--&amp;gt;&amp;gt;Dev: &amp;#34;Statut : Échec (La vérification Windows a échoué)&amp;#34;
&lt;/pre>
&lt;p>En collectant automatiquement les résultats des tests sur chaque OS, et en configurant des règles de protection de branche (branch protection rules) de sorte à n&amp;rsquo;&lt;strong>autoriser la fusion (merge) vers la branche main que si tous les environnements sont au vert (succès)&lt;/strong>, vous éviterez de manière proactive que des bugs liés à la plateforme ne s&amp;rsquo;infiltrent dans l&amp;rsquo;environnement de production ou les versions (releases).&lt;/p>
&lt;hr>
&lt;h2 id="en-résumé">En résumé
&lt;/h2>&lt;p>Le développement multiplateforme pour Mac et Windows présente de nombreux défis enracinés dans leur contexte historique.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Caractères de fin de ligne&lt;/strong> : Forcer la normalisation (unification en LF, etc.) au niveau du dépôt avec &lt;code>.gitattributes&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Majuscules et minuscules&lt;/strong> : Ne pas se reposer sur le comportement &amp;ldquo;insensible à la casse&amp;rdquo; de macOS/Windows ; établir des règles strictes de nommage des fichiers et veiller à une correspondance exacte de la casse.&lt;/li>
&lt;li>&lt;strong>Séparateurs de chemin&lt;/strong> : Utiliser les API standard de manipulation de chemins des langages (modules &lt;code>std::filesystem&lt;/code>, &lt;code>pathlib&lt;/code>, &lt;code>path&lt;/code>) pour masquer les différences entre les OS.&lt;/li>
&lt;li>&lt;strong>Encodage&lt;/strong> : Toujours spécifier UTF-8 et éliminer systématiquement les effets du comportement par défaut de Windows (CP932).&lt;/li>
&lt;li>&lt;strong>Variables d&amp;rsquo;environnement et shell&lt;/strong> : Utiliser des outils d&amp;rsquo;abstraction tels que &lt;code>cross-env&lt;/code>, ou unifier les environnements d&amp;rsquo;exécution avec WSL/Docker, etc.&lt;/li>
&lt;li>&lt;strong>Systèmes de build&lt;/strong> : Dans le cas de C/C++, exploiter des systèmes de méta-build comme CMake pour générer la chaîne d&amp;rsquo;outils native optimale pour chaque OS.&lt;/li>
&lt;li>&lt;strong>Code dépendant de l&amp;rsquo;OS&lt;/strong> : Concevoir une couche d&amp;rsquo;abstraction de l&amp;rsquo;OS (OSAL) afin de séparer et isoler la logique dépendante de la plateforme.&lt;/li>
&lt;li>&lt;strong>CI/CD&lt;/strong> : Introduire des builds matriciels, automatiser les builds propres et les tests sur tous les OS cibles, et éliminer la dépendance aux environnements individuels.&lt;/li>
&lt;/ol>
&lt;p>Bien qu&amp;rsquo;aujourd&amp;rsquo;hui de puissants frameworks tels que Electron, Tauri et .NET absorbent bon nombre de ces différences, la connaissance du comportement natif de l&amp;rsquo;OS sous-jacent (systèmes de fichiers, encodage) reste indispensable pour résoudre les problèmes graves de performances et les bugs complexes. En partageant et en appliquant ces meilleures pratiques avec toute l&amp;rsquo;équipe dès les premières étapes d&amp;rsquo;un projet, vous pourrez réduire considérablement le temps de débogage inutile lié aux différences d&amp;rsquo;OS, et vous concentrer sur la création essentielle de valeur logicielle.&lt;/p></description></item></channel></rss>