<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Best Practices on kenji.blog</title><link>http://kenji.blog/ar/categories/best-practices/</link><description>Recent content in Best Practices on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 08:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/categories/best-practices/index.xml" rel="self" type="application/rss+xml"/><item><title>ما يجب الانتباه إليه في تطوير المنصات المشتركة بين Mac و Windows</title><link>http://kenji.blog/ar/p/cross-platform-development-mac-windows/</link><pubDate>Sun, 13 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/ar/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 ما يجب الانتباه إليه في تطوير المنصات المشتركة بين Mac و Windows" />&lt;p>يعد تطوير المنصات المشتركة عبر أنظمة تشغيل (OS) متعددة مثل Mac (macOS) و Windows، وحتى Linux (بما في ذلك WSL)، مسارًا لا مفر منه في هندسة البرمجيات الحديثة. عند بناء تطوير الويب، أو الواجهات الخلفية لتطبيقات الأجهزة المحمولة، أو تطبيقات سطح المكتب عبر الأنظمة الأساسية (مثل Electron و Tauri و Qt)، فإن استخدام أنظمة تشغيل مختلفة داخل الفريق يؤدي إلى مواجهة العديد من &amp;ldquo;الأخطاء الناتجة عن اختلافات نظام التشغيل&amp;rdquo;.&lt;/p>
&lt;p>يتمتع كل نظام تشغيل بخلفية تاريخية وفلسفة تصميم مختلفة. يمتلك Windows بنية فريدة مشتقة من MS-DOS (واجهة برمجة تطبيقات Win32، نواة NT)، بينما يعتمد macOS على UNIX (نظام Darwin المستند إلى FreeBSD)، ويتوافق Linux مع معيار POSIX. يخلق هذا الاختلاف الأساسي &amp;ldquo;فخاخاً&amp;rdquo; تزعج المطورين في كل جانب، مثل أنظمة الملفات، والشبكات، ومعالجة العمليات.&lt;/p>
&lt;p>في هذه المقالة، سنشرح بالتفصيل وبشكل عملي الاختلافات الفنية وأفضل الممارسات التي يجب معرفتها تمامًا في فرق التطوير التي تمزج بين Mac و Windows، أو في تطوير التطبيقات التي تستهدف كلا نظامي التشغيل.&lt;/p>
&lt;hr>
&lt;h2 id="1-فخاخ-رموز-نهاية-السطر-crlf-مقابل-lf-والإعدادات-الصارمة-لـ-git">1. فخاخ رموز نهاية السطر (CRLF مقابل LF) والإعدادات الصارمة لـ Git
&lt;/h2>&lt;p>أحد الأسباب الأكثر شيوعًا والتي تؤدي إلى إرباك تطوير الفريق هو مشكلة &amp;ldquo;رموز نهاية السطر (Line Endings)&amp;rdquo;. هذه مشكلة تاريخية تعود إلى عصر الآلات الكاتبة.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Windows&lt;/strong>: يستخدم &lt;strong>CRLF&lt;/strong>، وهو مزيج من إرجاع النقل (CR, &lt;code>\r&lt;/code>, &lt;code>0x0D&lt;/code>) وتغذية السطر (LF, &lt;code>\n&lt;/code>, &lt;code>0x0A&lt;/code>)، كرمز قياسي لنهاية السطر.&lt;/li>
&lt;li>&lt;strong>macOS / Linux&lt;/strong>: يستخدم تغذية السطر الفردية &lt;strong>LF&lt;/strong> كرمز قياسي لنهاية السطر. (*حتى الإصدارات الأولى من Mac OS 9، كان يتم استخدام CR وحده، ولكن منذ Mac OS X أصبح مبنيًا على UNIX وأصبح يستخدم LF)&lt;/li>
&lt;/ul>
&lt;p>بسبب هذا الاختلاف، عند مشاركة التعليمات البرمجية المصدر في مستودع Git، قد تمتد الفروق (diff) إلى الملف بأكمله، أو قد يصبح البرنامج النصي للصدفة (&lt;code>.sh&lt;/code>) الذي يُفترض تشغيله في بيئة Linux يحتوي على CRLF لأنه تم تحريره في Windows، مما يتسبب في أخطاء مثل &lt;code>\r: command not found&lt;/code> حيث يتم تفسير &lt;code>\r&lt;/code> كحرف غير صالح عند التنفيذ.&lt;/p>
&lt;h3 id="الحل-في-git-الإدارة-باستخدام-gitattributes">الحل في Git: الإدارة باستخدام &lt;code>.gitattributes&lt;/code>
&lt;/h3>&lt;p>يحتوي Git على إعداد يسمى &lt;code>core.autocrlf&lt;/code>، لكن الاعتماد عليه أمر خطير. وذلك لأنه يعتمد على الإعدادات العالمية للآلة المحلية الخاصة بالمطور الفردي، مما يجعله عرضة للمشاكل بسبب نسيان الإعداد عند انضمام أعضاء جدد إلى الفريق.&lt;/p>
&lt;p>أفضل ممارسة هي وضع ملف &lt;code>.gitattributes&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;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"># بشكل افتراضي، تعامل كملفات نصية، وقم بتسويتها إلى LF داخل المستودع (على قاعدة بيانات Git)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># سيتم تحويلها إلى رمز نهاية السطر القياسي لكل نظام تشغيل عند الخروج (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"># ومع ذلك، للامتدادات المعينة مثل التعليمات البرمجية المصدر، فرض LF دائمًا بغض النظر عن نظام التشغيل
&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"># فرض CRLF للملفات الدفعية المخصصة لـ Windows وما شابه ذلك
&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"># لا تقم بتحويل رموز نهاية السطر للملفات مثل الصور أو الثنائيات المبنية مسبقًا (لمنع التلف)
&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-حساسية-حالة-الأحرف-في-نظام-الملفات-case-sensitivity">2. حساسية حالة الأحرف في نظام الملفات (Case Sensitivity)
&lt;/h2>&lt;p>تعتبر حساسية حالة الأحرف (Case Sensitivity) في أنظمة الملفات أيضًا واحدة من أكبر العقبات في تطوير المنصات المشتركة.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>macOS (APFS / HFS+)&lt;/strong>: بشكل افتراضي &lt;strong>غير حساس لحالة الأحرف (Case-Insensitive)&lt;/strong>، ولكنه &lt;strong>يحافظ على الحالة (Case-Preserving)&lt;/strong>. بمعنى آخر، إذا قمت بحفظه كـ &lt;code>File.txt&lt;/code> فسيتم عرضه كـ &lt;code>File.txt&lt;/code>، ولكن يمكنك أيضًا قراءته عن طريق الوصول إليه كـ &lt;code>file.txt&lt;/code> من البرنامج.&lt;/li>
&lt;li>&lt;strong>Windows (NTFS)&lt;/strong>: تمامًا مثل macOS، بشكل افتراضي &lt;strong>غير حساس لحالة الأحرف (Case-Insensitive)&lt;/strong>، و&lt;strong>يحافظ على الحالة (Case-Preserving)&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Linux / WSL (مثل ext4)&lt;/strong>: &lt;strong>حساس تمامًا لحالة الأحرف (Case-Sensitive)&lt;/strong>. يمكن أن يتعايش &lt;code>File.txt&lt;/code> و &lt;code>file.txt&lt;/code> في نفس الدليل كملفات مختلفة تمامًا.&lt;/li>
&lt;/ul>
&lt;h3 id="الأخطاء-النموذجية-التي-تحدث">الأخطاء النموذجية التي تحدث
&lt;/h3>&lt;p>أثناء التطوير على Mac أو Windows، حتى إذا حددت أحرفًا صغيرة في التعليمات البرمجية المصدر كـ &lt;code>#include &amp;quot;myclass.h&amp;quot;&lt;/code> (أو &lt;code>import &amp;quot;./myclass&amp;quot;&lt;/code>)، وكان الملف الفعلي هو &lt;code>MyClass.h&lt;/code>، فإن البناء سينجح لأن نظام التشغيل في البيئة المحلية غير حساس لحالة الأحرف.&lt;/p>
&lt;p>ومع ذلك، إذا قمت بالالتزام (commit) بهذا الكود وتشغيل البناء على خادم CI/CD (عادةً Linux مثل Ubuntu)، فسيؤدي ذلك إلى خطأ في التجميع يوضح &amp;ldquo;لم يتم العثور على الملف&amp;rdquo; لأن نظام ملفات ext4 الخاص بـ Linux حساس لحالة الأحرف.&lt;/p>
&lt;h3 id="منظور-خوارزمي-تعقيد-وقت-البحث-عن-الملفات-والتسوية-normalization">منظور خوارزمي: تعقيد وقت البحث عن الملفات والتسوية (Normalization)
&lt;/h3>&lt;p>دعونا نفكر رياضيًا في نوع المعالجة التي تحدث داخليًا عندما يحل نظام الملفات مسار الملف.&lt;/p>
&lt;p>في حالة ext4 الذي يميز بين الأحرف الكبيرة والصغيرة، تتم إدارة الإدخالات في الدليل باستخدام هياكل مثل جداول التجزئة (Hash Tables) أو أشجار B (B-Trees). بافتراض أن عدد الملفات في الدليل هو $N$، وطول اسم الملف هو $L$، فإن تعقيد الوقت للبحث الثنائي البسيط أو البحث في الشجرة سيكون على النحو التالي:&lt;/p>
$$ T_{search}(N) = O(L \log N) $$&lt;p>من ناحية أخرى، في أنظمة الملفات التي لا تميز بين الأحرف الكبيرة والصغيرة مثل NTFS و APFS، هناك حاجة إلى تسوية (Case Folding) كلا السلسلتين إلى نفس الحالة (كبيرة أو صغيرة) قبل مقارنة السلاسل. لا يمكن إنجاز تحويل الأحرف الكبيرة/الصغيرة الذي يأخذ في الاعتبار تسوية Unicode واللغة (Locale) بمجرد عمليات بت ASCII البسيطة، ويتطلب البحث في الجداول (Table Lookup).&lt;/p>
&lt;p>إذا افترضنا أن التكلفة الحسابية لدالة التحويل هي ثابت $C_{fold}$، فسيكون هناك عبء إضافي لكل عملية مقارنة بين السلاسل.&lt;/p>
$$ T_{insensitive\_search}(N) = O( (L \times C_{fold}) \log N ) $$&lt;p>تقوم أنظمة التشغيل الحديثة بتخزين هذا بشكل متقدم (Caching)، ولكن الاختلاف الأساسي في السلوك لا يمكن تقييده إلا من خلال الاتفاقيات على مستوى التطوير. الطريقة الأكثر أمانًا هي وضع قاعدة للمشروع تنص على &lt;strong>&amp;ldquo;توحيد جميع أسماء الملفات والأدلة لتكون بأحرف صغيرة مع شرطات (kebab-case) أو شرطات سفلية (snake_case)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="3-فواصل-المسارات-path-separators-وتجريد-مسار-الملف">3. فواصل المسارات (Path Separators) وتجريد مسار الملف
&lt;/h2>&lt;p>يعكس التعامل مع الفواصل التي تشير إلى التسلسل الهرمي للدليل اختلافات أساسية بين أنظمة التشغيل.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Windows&lt;/strong>: يستخدم الشرطة المائلة العكسية &lt;code>\&lt;/code> (قد تظهر كرمز الين &lt;code>¥&lt;/code> بناءً على الخط في البيئات اليابانية)، ويوجد أيضًا مفهوم حروف محركات الأقراص (مثل &lt;code>C:\&lt;/code>) ومسارات UNC (مثل &lt;code>\\Server\Share&lt;/code>).&lt;/li>
&lt;li>&lt;strong>macOS / Linux&lt;/strong>: يستخدم الشرطة المائلة &lt;code>/&lt;/code>، وتمتلك جميع أنظمة الملفات بنية هرمية تبدأ من جذر واحد &lt;code>/&lt;/code> (Single Root Hierarchy).&lt;/li>
&lt;/ul>
&lt;p>تقوم العديد من لغات البرمجة بتفسير &lt;code>/&lt;/code> كفاصل ملفات بشكل صحيح حتى على Windows (لأن واجهة برمجة تطبيقات Win32 نفسها تدعم &lt;code>/&lt;/code> في بعض الأجزاء). ومع ذلك، فإن تمرير المسارات كوسيطات لسطر الأوامر، أو استدعاء النظام (System Call) مباشرة، أو مقارنة وتحليل المسارات كسلاسل سيؤدي إلى أخطاء فادحة.&lt;/p>
&lt;h3 id="أفضل-الممارسات-لكل-لغة-تجريد-نظام-التشغيل">أفضل الممارسات لكل لغة (تجريد نظام التشغيل)
&lt;/h3>&lt;p>&lt;strong>تجنب تمامًا&lt;/strong> بناء مسارات الملفات من خلال تسلسل السلاسل (مثال: &lt;code>path + &amp;quot;\\&amp;quot; + filename&lt;/code>). استخدم المكتبات القياسية لمعالجة المسار المتوفرة في كل لغة (طبقة تجريد نظام التشغيل - OS Abstraction Layer).&lt;/p>
&lt;h4 id="مثال-c-stdfilesystem">مثال C++ (&lt;code>std::filesystem&lt;/code>)
&lt;/h4>&lt;p>منذ C++17، تم تقديم &lt;code>&amp;lt;filesystem&amp;gt;&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;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">// بناء مسار مستقل عن نظام التشغيل (تجريد من خلال التحميل الزائد للمشغل - Operator Overloading)
&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">// يصبح &amp;#34;data\config.json&amp;#34; في Windows، و &amp;#34;data/config.json&amp;#34; في 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="مثال-python-pathlib">مثال Python (&lt;code>pathlib&lt;/code>)
&lt;/h4>&lt;p>في الماضي كان يتم استخدام &lt;code>os.path.join()&lt;/code>، لكن المعيار الآن هو استخدام وحدة &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"># تم تجاوز المشغل / لإنشاء كائن مسار يتوافق مع نظام التشغيل&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"># يمكن حل المسارات وقراءة الملفات باستخدام طرق متسقة&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="مثال-nodejs-وحدة-path">مثال Node.js (وحدة &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 يأخذ الوسائط ويجمعها باستخدام الفاصل المناسب لنظام التشغيل الحالي
&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-ترميز-الأحرف-utf-8-مقابل-cp932shift-jis-وجدار-unicode">4. ترميز الأحرف (UTF-8 مقابل CP932/Shift-JIS) وجدار Unicode
&lt;/h2>&lt;p>أكبر مصدر للصداع في البيئة اليابانية لنظام Windows هو ترميز الأحرف.
في التطوير الحديث، يتم توحيد macOS و Linux بالكامل مع &lt;strong>UTF-8&lt;/strong> للنظام بأكمله، والمحطة الطرفية (Terminal)، وحتى ترميز الملفات. ومع ذلك، فإن الترميز القياسي للنسخة اليابانية من Windows (&amp;ldquo;صفحة رموز ANSI&amp;rdquo; المستندة إلى لغة النظام) لا يزال يعمل غالبًا مع &lt;strong>CP932 (امتداد Microsoft لـ Shift-JIS)&lt;/strong> كإعداد افتراضي.
*تمثيل السلسلة الداخلي لواجهة برمجة تطبيقات Win32 هو UTF-16LE (&lt;code>wchar_t&lt;/code>).&lt;/p>
&lt;p>عند قراءة وكتابة الملفات في Python وما إلى ذلك، إذا لم تحدد الترميز بوضوح، فسيحاول Windows تفسيره وفقًا لنتيجة &lt;code>locale.getpreferredencoding()&lt;/code> (والتي هي CP932). نتيجة لذلك، قد تحدث &lt;code>UnicodeDecodeError&lt;/code> عند محاولة قراءة ملف محفوظ بـ UTF-8، أو قد يظهر نص مشوه (Mojibake).&lt;/p>
&lt;h3 id="النموذج-الرياضي-لتحويل-رمز-الأحرف-والعبء-الإضافي-overhead">النموذج الرياضي لتحويل رمز الأحرف والعبء الإضافي (Overhead)
&lt;/h3>&lt;p>عند تحويل سلسلة من ترميز (UTF-8) إلى ترميز آخر (UTF-16 أو CP932)، يتناسب تعقيد الحالة الأسوأ مع طول السلسلة. إذا افترضنا أن طول السلسلة بالبايت هو $B$، فإن تعقيد التحويل هو $O(B)$. ومع ذلك، بسبب تحليل UTF-8 (وهو ترميز متغير الطول)، وحساب أزواج البدائل (Surrogate Pairs)، والبحث في جدول التحويل (Lookup)، ينشأ عبء إضافي لا يمكن تجاهله.&lt;/p>
&lt;p>إذا كان طول السلسلة هو $N$، ودالة التعيين (Mapping Function) من الأحرف متعددة البايتات إلى نقاط تشفير Unicode هي $f_{decode}$، ودالة التعيين من نقاط التشفير إلى الترميز الهدف هي $f_{encode}$، فسيتم تقريب وقت التحويل الإجمالي $T_{conv}$ على النحو التالي:&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>في التطبيقات المشتركة بين المنصات، من الضروري إدراك أن تكلفة التحويل هذه تحدث في كل مرة يتم فيها استدعاء واجهة برمجة التطبيقات الأصلية (Native API) لنظام التشغيل (تجاوز حدود الإدخال/الإخراج) (خاصة عند التطوير بـ C++ لـ Windows، تحدث تحويلات إلى UTF-16 بشكل متكرر باستخدام &lt;code>MultiByteToWideChar&lt;/code> وما إلى ذلك).&lt;/p>
&lt;h3 id="التدابير-المضادة-للترميز">التدابير المضادة للترميز
&lt;/h3>&lt;p>أكثر التدابير المؤكدة هو &lt;strong>&amp;ldquo;تحديد UTF-8 دائمًا بوضوح في جميع الأوقات&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"># مثال جيد في Python: حدد دائمًا 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;مرحباً، أيها العالم!&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>بالإضافة إلى ذلك، لعرض مخرجات UTF-8 بشكل صحيح في أجهزة Windows الطرفية (Command Prompt أو PowerShell)، قد تحتاج إلى تعيين متغير البيئة &lt;code>PYTHONUTF8=1&lt;/code> عند بدء تشغيل التطبيق، أو تغيير صفحة رموز وحدة التحكم (Console Code Page) مؤقتًا إلى UTF-8 باستخدام الأمر &lt;code>chcp 65001&lt;/code> في بيئات مثل Node.js.&lt;/p>
&lt;hr>
&lt;h2 id="5-الاختلافات-في-متغيرات-البيئة-وبيئات-الصدفة-bashzsh-مقابل-powershell">5. الاختلافات في متغيرات البيئة وبيئات الصدفة (bash/zsh مقابل PowerShell)
&lt;/h2>&lt;p>تعتبر الاختلافات في الصدفة (Shell) (مترجم سطر الأوامر) عند تنفيذ نصوص البناء البرمجية وأدوات التطوير عقبة رئيسية أخرى عبر الأنظمة الأساسية.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>macOS / Linux&lt;/strong>: &lt;code>bash&lt;/code> أو &lt;code>zsh&lt;/code> هما السائدان. يقومان بمعالجة خطوط الأنابيب (Pipeline) القائمة على النصوص.&lt;/li>
&lt;li>&lt;strong>Windows&lt;/strong>: موجه الأوامر (&lt;code>cmd.exe&lt;/code>) أو &lt;code>PowerShell&lt;/code>. يعتمد PowerShell على .NET ويحتوي على خط أنابيب قوي موجه للكائنات، لكن بناء الجملة الخاص به يختلف تمامًا عن صدفة POSIX.&lt;/li>
&lt;/ul>
&lt;p>نظرًا لأن طرق الإشارة إلى متغيرات البيئة وتعيينها مختلفة، فإن كتابة رموز تعتمد على نظام التشغيل في منطقة &lt;code>scripts&lt;/code> من &lt;code>package.json&lt;/code> الخاصة بـ Node.js ستجعلها تتوقف عن العمل في بيئات أخرى.&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">// ❌ مثال سيء: في Windows، لن يتم التعرف على &amp;#34;NODE_ENV&amp;#34; كأمر وسيحدث خطأ
&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="الحل-الاستفادة-من-الأدوات-المشتركة-بين-المنصات">الحل: الاستفادة من الأدوات المشتركة بين المنصات
&lt;/h3>&lt;p>في بيئة Node.js، يمكنك استخدام حزم مثل &lt;code>cross-env&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;/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">// ✅ مثال جيد: يستوعب cross-env اختلافات نظام التشغيل ويعين متغيرات البيئة بشكل صحيح لبدء 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">// استخدم مزيلًا مشتركًا بين المنصات بدلاً من 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>للمشاريع واسعة النطاق التي تتطلب برامج نصية معقدة للصدفة، تتمثل أفضل الممارسات الحالية في جعل استخدام WSL (النظام الفرعي لـ Windows لـ Linux) أو Git Bash قياسيًا حتى للمطورين في بيئة Windows، وإدارة جميع المعالجات الدفعية بشكل موحد كبرامج نصية &lt;code>.sh&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="6-أنظمة-البناء-والمجمعين-compilers-المشتركة-بين-المنصات">6. أنظمة البناء والمجمعين (Compilers) المشتركة بين المنصات
&lt;/h2>&lt;p>عند التعامل مع التعليمات البرمجية الأصلية (اللغات التي يتم تجميعها مباشرة في كود الآلة) مثل C++ أو Rust، من الضروري التغلب على اختلافات نظام البناء والمترجم، وليس فقط واجهات برمجة التطبيقات الخاصة بنظام التشغيل.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>المجمّعون (Compilers)&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>تنسيق الثنائيات (Binary Format)&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="الاستفادة-من-أنظمة-البناء-الوصفية-meta-build-systems-باستخدام-cmake">الاستفادة من أنظمة البناء الوصفية (Meta-Build Systems) باستخدام CMake
&lt;/h3>&lt;p>في مشاريع C/C++، يُعد &lt;strong>CMake&lt;/strong> المعيار العالمي الفعلي لتحقيق التوافق عبر الأنظمة الأساسية. لا يقوم CMake بتجميع الكود المصدري مباشرة، بل يعمل كـ &amp;ldquo;منشئ (Generator)&amp;rdquo; يقوم بإنشاء ملفات تكوين البناء الأصلية المصممة لكل بيئة (ملفات حل Visual Studio لنظام Windows، ونصوص البناء لـ Makefile أو Ninja لنظامي Linux/Mac).&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;CMakeLists.txt (مستقل عن المنصة)&amp;#34;] --&amp;gt; B(&amp;#34;محرك CMake&amp;#34;)
B --&amp;gt; C{&amp;#34;نظام التشغيل الهدف&amp;#34;}
C --&amp;gt;|Windows| D[&amp;#34;حل Visual Studio / MSBuild&amp;#34;]
C --&amp;gt;|macOS| E[&amp;#34;مشروع Xcode / Apple Clang&amp;#34;]
C --&amp;gt;|Linux| F[&amp;#34;Makefile / Ninja / GCC&amp;#34;]
D --&amp;gt; G[&amp;#34;برنامج تنفيذي لـ Windows (.exe)&amp;#34;]
E --&amp;gt; H[&amp;#34;برنامج تنفيذي لـ macOS (Mach-O)&amp;#34;]
F --&amp;gt; I[&amp;#34;برنامج تنفيذي لـ Linux (ELF)&amp;#34;]
&lt;/pre>
&lt;p>باستخدام CMake، يمكنك استيعاب الاختلافات بين البيئات وإنشاء ثنائيات محسّنة لكل نظام تشغيل من ملف تكوين واحد (&lt;code>CMakeLists.txt&lt;/code>). يمكن أيضًا كتابة حلول المكتبات التابعة (&lt;code>find_package&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;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"># مثال لجزء من 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"># ربط مكتبات خاصة بـ Windows (مثل 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"># ربط إطارات عمل خاصة بـ 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"># ربط لـ Linux (مثل 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-الاستفادة-من-الأنماط-المعمارية-طبقة-تجريد-نظام-التشغيل-osal">7. الاستفادة من الأنماط المعمارية: طبقة تجريد نظام التشغيل (OSAL)
&lt;/h2>&lt;p>يعد فصل العمليات المعتمدة على النظام (عمليات الملفات، إنشاء العمليات/المؤشرات الترابطية، إدارة الذاكرة، اتصالات مآخذ التوصيل، إلخ) تمامًا عن منطق الأعمال الأساسي للتطبيق أمرًا ضروريًا في التطوير المشترك بين الأنظمة الأساسية.&lt;/p>
&lt;p>ولتحقيق ذلك، نستخدم نمطًا يسمى &lt;strong>طبقة تجريد نظام التشغيل (OS Abstraction Layer, OSAL)&lt;/strong>.&lt;/p>
&lt;p>فيما يلي مثال لتصميم فئة (Class) يغلف واجهات برمجة التطبيقات الخاصة بكل نظام تشغيل ويوفر واجهة مشتركة. يمكنك تبديل التنفيذ باستخدام تعدد الأشكال (Polymorphism) أو باستخدام مفاتيح الماكرو أثناء وقت التجميع.&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>من خلال عزل التعليمات البرمجية الخاصة بالمنصة في مكان واحد (عادةً في أدلة مثل &lt;code>src/platform/windows/&lt;/code> أو &lt;code>src/platform/posix/&lt;/code>)، يمكنك الحفاظ على 95٪ من التعليمات البرمجية المتبقية (منطق واجهة المستخدم الرسومية، ومعالجة البيانات، وتحليل بروتوكولات الاتصال، إلخ) بشكل مشترك تمامًا بين المنصات وقابل للاختبار.&lt;/p>
&lt;hr>
&lt;h2 id="8-التحقق-من-المنصات-المشتركة-في-cicd-بناء-المصفوفة---matrix-build">8. التحقق من المنصات المشتركة في CI/CD (بناء المصفوفة - Matrix Build)
&lt;/h2>&lt;p>بغض النظر عن مدى دقة المطورين في البرمجة في بيئاتهم المحلية، فإن الحصن الأخير للتوافق عبر الأنظمة الأساسية هو &lt;strong>خط أنابيب CI/CD (التكامل المستمر / النشر المستمر)&lt;/strong>. لا حصر للحالات التي يعمل فيها الرمز في بيئة محلية (مثل Mac) ولكنه يؤدي إلى أخطاء في التجميع في نظام تشغيل آخر (Windows).&lt;/p>
&lt;p>استفد من أدوات CI الحديثة مثل GitHub Actions و GitLab CI، وقم بإعداد بناء المصفوفة (Matrix Build) &lt;strong>لإجراء البناء والاختبار بالتوازي في جميع بيئات Windows و macOS و Linux&lt;/strong> في كل مرة يتم فيها إنشاء طلب سحب (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"># مثال على تكوين CI للمنصات المشتركة باستخدام 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"># استمر في اختبار أنظمة التشغيل الأخرى حتى في حالة فشل أحدهما&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"># حدد ثلاثة أنظمة تشغيل: Windows و macOS و 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"># التخزين المؤقت للتبعيات حتى عبر المنصات&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>إذا قمنا بتصور تدفق CI/CD هذا، فسيبدو كالتالي:&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant Dev as &amp;#34;مطور&amp;#34;
participant GitHub as &amp;#34;GitHub Actions (منسق)&amp;#34;
participant Ubuntu as &amp;#34;Linux Runner (جهاز ظاهري)&amp;#34;
participant Windows as &amp;#34;Windows Runner (جهاز ظاهري)&amp;#34;
participant Mac as &amp;#34;macOS Runner (جهاز ظاهري)&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;إرسال مهمة (ubuntu-latest)&amp;#34;
GitHub-&amp;gt;&amp;gt;Windows: &amp;#34;إرسال مهمة (windows-latest)&amp;#34;
GitHub-&amp;gt;&amp;gt;Mac: &amp;#34;إرسال مهمة (macos-latest)&amp;#34;
par Parallel Execution Matrix
Ubuntu--&amp;gt;&amp;gt;Ubuntu: &amp;#34;سحب الكود، إعداد البيئة، البناء، الاختبار&amp;#34;
Windows--&amp;gt;&amp;gt;Windows: &amp;#34;سحب الكود، إعداد البيئة، البناء، الاختبار&amp;#34;
Mac--&amp;gt;&amp;gt;Mac: &amp;#34;سحب الكود، إعداد البيئة، البناء، الاختبار&amp;#34;
end
Ubuntu--&amp;gt;&amp;gt;GitHub: &amp;#34;النتيجة: نجاح (مرور)&amp;#34;
Windows--&amp;gt;&amp;gt;GitHub: &amp;#34;النتيجة: فشل (فشل - خطأ في الترميز)&amp;#34;
Mac--&amp;gt;&amp;gt;GitHub: &amp;#34;النتيجة: نجاح (مرور)&amp;#34;
GitHub--&amp;gt;&amp;gt;Dev: &amp;#34;الحالة: فشل (فشل فحص Windows)&amp;#34;
&lt;/pre>
&lt;p>من خلال جمع نتائج الاختبار تلقائيًا لكل نظام تشغيل وتعيين قواعد حماية الفرع (Branch Protection Rules) بحيث &lt;strong>يُسمح بالدمج في الفرع main فقط إذا كانت جميع البيئات خضراء (ناجحة)&lt;/strong>، فإنك تمنع دخول الأخطاء المعتمدة على النظام الأساسي إلى بيئة الإنتاج أو بنيات الإصدار مسبقًا.&lt;/p>
&lt;hr>
&lt;h2 id="الملخص">الملخص
&lt;/h2>&lt;p>يحتوي التطوير المشترك بين منصات Mac و Windows على مجموعة متنوعة من التحديات المتجذرة في الخلفية التاريخية.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>رموز نهاية السطر&lt;/strong>: فرض التسوية على مستوى المستودع (مثل توحيد LF) باستخدام &lt;code>.gitattributes&lt;/code>.&lt;/li>
&lt;li>&lt;strong>حساسية حالة الأحرف&lt;/strong>: لا تعتمد على السلوك &amp;ldquo;غير الحساس&amp;rdquo; لـ macOS/Windows، بل ضع قواعد صارمة لتسمية الملفات، واحرص على مطابقة حالة الأحرف بدقة.&lt;/li>
&lt;li>&lt;strong>فواصل المسارات&lt;/strong>: استخدم واجهات برمجة تطبيقات معالجة المسارات القياسية للغة (وحدات &lt;code>std::filesystem&lt;/code>, &lt;code>pathlib&lt;/code>, &lt;code>path&lt;/code>) لاستيعاب اختلافات نظام التشغيل.&lt;/li>
&lt;li>&lt;strong>الترميز&lt;/strong>: حدد UTF-8 دائمًا للتخلص تمامًا من تأثير CP932، وهو السلوك الافتراضي لـ Windows.&lt;/li>
&lt;li>&lt;strong>متغيرات البيئة والصدفة&lt;/strong>: استخدم أدوات التجريد مثل &lt;code>cross-env&lt;/code>، أو وحّد بيئة التنفيذ إلى WSL/Docker وما إلى ذلك.&lt;/li>
&lt;li>&lt;strong>أنظمة البناء&lt;/strong>: في حالة C/C++، استفد من أنظمة البناء الوصفية مثل CMake لإنشاء أفضل سلسلة أدوات أصلية (Native Toolchain) لكل نظام تشغيل.&lt;/li>
&lt;li>&lt;strong>التعليمات البرمجية المعتمدة على نظام التشغيل&lt;/strong>: صمم طبقة تجريد نظام التشغيل (OSAL) لفصل وعزل المنطق المعتمد على المنصة.&lt;/li>
&lt;li>&lt;strong>CI/CD&lt;/strong>: قم بتقديم بناء المصفوفة (Matrix Build) لأتمتة البناء والاختبار النظيف على جميع أنظمة التشغيل المستهدفة، والقضاء على الاعتماد على الأفراد.&lt;/li>
&lt;/ol>
&lt;p>اليوم، تستوعب أطر العمل القوية مثل Electron و Tauri و .NET الكثير من هذه الاختلافات، لكن المعرفة بالسلوك الأصلي لنظام التشغيل الأساسي (نظام الملفات والترميز) لا تزال ضرورية عند حل مشاكل الأداء الخطيرة أو الأخطاء المستعصية. من خلال مشاركة أفضل الممارسات هذه وتطبيقها بدقة عبر الفريق بأكمله من المراحل الأولى للمشروع، ستتمكن من تقليل وقت التصحيح العقيم الناتج عن اختلافات نظام التشغيل بشكل كبير، والتركيز على خلق القيمة الأساسية للبرنامج.&lt;/p></description></item></channel></rss>