إصلاح بناء ويندوز في السحابة: ترميز UTF-8 صريح وعدّاء مستضاف - #302
Conversation
الشيفرة المصدرية تحوي نصوصاً عربية داخلها - رسائل ومعرّفات وحالات switch مكتوبة بأحرف عربية - وهي محفوظة بترميز UTF-8 بلا علامة BOM. وحين لا يُذكر الترميز صريحاً يقرؤها المترجم بصفحة ترميز النظام: FormatterUStr.cpp(221): error C2196: case value '217' already used لأن L'ف' و L'ه' يبدآن كلاهما بالبايت D9 فينهاران إلى القيمة نفسها. فعلى جهاز صفحته عربية يمر البناء، وعلى غيره يفشل بعشرين خطأ. لذا يضاف /utf-8 إلى تهيئات الترجمة الاثنتي عشرة، وعلمان مقابلان في Makefile - لـ gcc وحده، فـ clang يعامل المصدر بـ UTF-8 دائماً ويرفض -fexec-charset فتفشل ترجمة ماك. ويبقى بعد ذلك موضع ثالث: FreezeModule يتلقى مسار الوحدة المراد تجميدها من سطر الأوامر، وويندوز يسلّم المعاملات إلى main بترميز صفحة النظام، فتتحول حروف اسم الملف العربية إلى '?' ويفشل فتحه في حدث ما بعد البناء. فتُستقبل عريضة عبر wmain وتُحوّل إلى UTF-8، ويُضبط ترميز مكتبة C على UTF-8 حتى تقبل fopen المسارات العربية. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
سير بناء ويندوز كان مربوطاً بـ runs-on: [Win-MSBuild]، وهو عداء ذاتي الاستضافة لا يلتقط الوظائف إلا حين يكون جهازه متصلاً - فيبقى فحص ويندوز في الفروع وطلبات الدمج الواردة معلقاً بلا رسالة ولا مهلة انتهاء. وفيه أيضاً أن شيفرة الطلبات الواردة من المتفرعات تُنفَّذ على ذلك الجهاز. ومع النقل إلى windows-latest: - تُرقّى setup-msbuild من v1.0.2 إلى v2، فالقديمة تعتمد إصداراً من Node لم يعد مدعوماً على العدّاءات. - تُذكر المنصة x64 صراحةً بدل الاتكال على التهيئة الافتراضية في الحل. ويستحق الانتباه أن تهيئة Release|Win32 في FreezeModule.vcxproj وحدها بلا PostBuildEvent، فمن بنى بها لا يتولد عنده GetPath.h. - يُحذف working-directory لأنه يشير إلى env.GITHUB_WORKSPACE، وهي متغير بيئة افتراضي لا مفتاح في سياق env، فيتمدد فارغاً. - يُضاف workflow_dispatch إلى سيري العمل ليشغّل المشرف البناء يدوياً على أي فرع قبل أن يفتح طلب دمج. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
البناء الأخضر يثبت أن الشيفرة تُرجمت، لا أن المفسّر يعمل. وعلة الترميز بالذات تمر من الترجمة ثم تظهر عند التشغيل: اسم ملف لا يُفتح، أو نص عربي يُطبع مشوهاً. فيُضاف فحص يشغّل الأمثلة المتعقّبة في git، ثم يكتب ملفاً عربي الاسم والمحتوى ويتحقق من أن المطبوع هو ما كُتب. ويجهّز الفحص حزمة كما تُشحن - المفسّر ومكتبته وأمثلته في مجلد واحد - ثم يشغّل منها، لا من مجلد البناء: المفسّر يحتاج library بجواره. وهو مقصور على لينكس وماك: بناء ويندوز يخرج بالرمز 1 بلا أي مخرَج على هذه الشجرة، حتى لبرنامج من سطر واحد، فتشغيله غير مغطّى هنا. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
المستورد يفتح مسارات UTF-8 بدوال ضيقة، وهي على ويندوز تفسّر البايتات بصفحة النظام (ANSI) لا بـUTF-8. ومكتبة الإقلاع library/نظام_التشغيل.aliflib اسمها عربي، فلا تراها الدوال الضيقة على نظام صفحته ليست 65001، ويموت الإقلاع قبل قراءة أي وسيط: رمز الخروج 1 بلا حرف على المخرج أو الخطأ. قيس على windows-latest من هذه الشجرة قبل الرقعة: ست صور تشغيل (من جذر المستودع، ومن حزمة فيها library جنب التنفيذي، بمسار نسبي ومطلق، عبر bash وعبر cmd، وبلا وسائط أصلاً) كلها رمز 1 وصفر بايت، وثمانية اختبارات من ثمانية فاشلة. ثلاثة مواضع، وكل واحد منها لازم قيس أثره: - path_fopen: فتح المكتبة عربية الاسم، وبها وحدها يقلع المفسّر (7/8) - path_stat: كشف مجلد الحزمة عربي الاسم، فـGetFileAttributesW بدل stat - case_ok: مطابقة __تهيئة__.aliflib بعد إيجاد المجلد، بـMultiByteToWideChar بدل mbstowcs، وبمقارنة تامة بدل wcsncmp بطول بايتي كان يقبل أي اسم يكون المطلوب سابقة له الأخيران يظهر أثرهما في examples/Status.alif وحده لأنه المثال الوحيد الذي يستورد حزمة من مجلدات عربية (examples/مكتبة/فرعية)، فبدونهما 7/8 وبهما 8/8. التغيير كله محجوب بـ#ifdef _WINDOWS، وفرع غير ويندوز يبقى stat و fopen كما كانا لأن المسارات هناك بايتات UTF-8 أصلاً.
فحص التشغيل كان يعمل على لينكس وماك دون ويندوز، وويندوز أولى المنصات به: علة الترميز تمر من الترجمة ثم تظهر عند التشغيل، فبناء أخضر لا يعني مفسّراً عاملاً. وبعد رقعة الدوال العريضة صار يمر: ثمانية اختبارات من ثمانية في Release و Debug، وهي الأمثلة السبعة المتعقّبة في تخطيط الحزمة كما تُشحن، وملف عربي الاسم والمحتوى. وبناء Debug يفعّل AddressSanitizer فيعتمد على clang_rt.asan_dynamic-x86_64.dll وهي في مجلد أدوات MSVC لا في مسار النظام، فيخرج التنفيذي بالرمز 127 قبل أن يبدأ. فتُضاف إلى المسار بدل تعطيل ASAN. وصُحّح تعليقان كانا يقولان ما لم يُقس: - الحل يسمّي المنصتين x86 و x64، و Win32 اسم على مستوى المشاريع لا الحل، فتمريره إلى الحل يُرفض قبل أي ترجمة. لا علاقة للأمر بـPostBuildEvent. - فشل التشغيل من شجرة البناء على ويندوز لم يكن لغياب library بالجوار، بل لأن المستورد كان يفتح المكتبة عربية الاسم بدالة ضيقة.
Shad7ows
left a comment
There was a problem hiding this comment.
تمت المراجعة مع إقتراح بعض التعديلات
ملاحظة: يرجى عدم رفع أكثر من حالة في نفس الطلب وكل منها تحل مشكلة معينة, ويفضل أن يحل الطلب مشكلة واحدة محددة جدا ليتم مراجعتها واختبارها بشكل اسرع وافصل
| run: cd linuxBuild && make ${{matrix.BUILD-CONFIGURATION}} | ||
|
|
||
| # البناء يثبت أن الشيفرة تُرجمت لا أن المفسّر يعمل، فنشغّل ما بُني | ||
| - name: تشغيل ما بُني |
| run: cd linuxBuild && make ${{matrix.BUILD-CONFIGURATION}} | ||
|
|
||
| # البناء يثبت أن الشيفرة تُرجمت لا أن المفسّر يعمل، فنشغّل ما بُني | ||
| - name: تشغيل ما بُني |
| branches: ["main"] | ||
| pull_request: | ||
| branches: ["main"] | ||
| # زر تشغيل يدوي: يتيح تجربة البناء على أي فرع بلا فتح طلب دمج. |
| jobs: | ||
| build: | ||
| runs-on: [Win-MSBuild] | ||
| # عداء مستضاف لدى GitHub بدل عداء ذاتي الاستضافة: الذاتي لا يلتقط |
| #ifdef _WINDOWS | ||
| /* على ويندوز تصل المعاملات إلى main بترميز صفحة النظام (ANSI)، فتتحول | ||
| الحروف العربية في اسم الملف ولاحقته إلى '?' ويفشل فتح الملف على كل نظام | ||
| لغته ليست العربية. لذا نستقبلها عريضة عبر wmain ونحولها إلى UTF-8، | ||
| ونضبط ترميز مكتبة C على UTF-8 حتى تقبل fopen المسارات العربية. */ | ||
| static char* utf8_fromWide(const wchar_t* _wide) { | ||
| int size = WideCharToMultiByte(CP_UTF8, 0, _wide, -1, nullptr, 0, nullptr, nullptr); | ||
| if (size <= 0) return nullptr; | ||
| char* out = (char*)malloc((size_t)size); | ||
| if (out == nullptr) return nullptr; | ||
| if (WideCharToMultiByte(CP_UTF8, 0, _wide, -1, out, size, nullptr, nullptr) <= 0) { | ||
| free(out); | ||
| return nullptr; | ||
| } | ||
| return out; | ||
| } | ||
| #endif |
There was a problem hiding this comment.
نقل هذا الجزء إلى أسفل freeze_main
استجابةً لمراجعة Shad7ows، ورئيسُها: «لا ترفع أكثر من حالة في نفس الطلب». الطلب الآن يحل مشكلة واحدة محددة — فشل بناء ويندوز في السحابة بسبب الترميز — ويتقلص من تسعة ملفات و٢٤٧ سطراً إلى ستة ملفات و٤٧ سطراً. نُقل إلى طلبات لاحقة: - .github/scripts/run_check.sh وخطوات «تشغيل ما بُني» الثلاث - إضافة -finput-charset/-fexec-charset في linuxBuild/Makefile - دوال المسار العريضة في source/AlifCore/Objects/Import.cpp - خطوة إضافة وقت تشغيل ASAN إلى المسار (تابعة لـ run_check) ونُفذت الملاحظات السطرية: - حذف التعليقات من msbuild.yml - إعادة working-directory إلى خطوة Build - حذف /p:Platform=x64. اختُبر: msbuild بلا تحديد منصة يبني إلى x64 ويخرج بالرمز صفر، فالإضافة كانت زائدة. - تبسيط wmain كما اقتُرح، وسقطت معه الدالة المساعدة utf8_fromWide فلم تعد هناك حاجة لنقلها. أُبقي فحص واحد على قيمة WideCharToMultiByte الأولى: بدونه يبقى argv[i] غير مهيأ حين تفشل (نص UTF-16 غير صالح) ثم يُستعمل مساراً. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
مراجعةٌ داخليّةٌ ثانيةٌ للطلب بعد تطبيق ملاحظات Shad7ows الست عشرة كشفت ثلاثة أمور، اثنان منها يخالفان مبدأه المعلن «طلب واحد لمشكلة واحدة»: - `.github/workflows/makebuild.yml` كان تغييره الوحيد الباقي سطر `workflow_dispatch` — ملف سير عمل لينكس وماك في طلب عنوانه بناء ويندوز. لا علاقة له بالترميز، فأُخرج. والملف الآن خارج الطلب كلّه، فلم تبق فيه إلا ملفات ويندوز: ثلاثة vcxproj و msbuild.yml و FreezeModule.cpp. - التعليق فوق `wmain` كان قبل `#ifdef _WINDOWS`، فيبقى في بناء لينكس وماك حيث لا معنى له. نُقل داخل الشرط. وبقي `workflow_dispatch` في `msbuild.yml` عمداً: هو تشغيل يدوي لبناء ويندوز نفسه، والمراجع علّق على السطر الذي فوقه مباشرة فطلب حذف التعليق دون السطر. و`runs-on: windows-latest` باق أيضاً: عنوان الطلب يذكر «وعدّاء مستضاف» صراحةً، فهو معلن لا مهرَّب، وبدونه لا تعمل وظيفة ويندوز في السحابة أصلاً وهي موضوع الطلب. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
شكراً على المراجعةِ الدقيقة @Shad7ows. نُفِّذت الملاحظاتُ الستَّ عشرةُ كلُّها. |
Shad7ows
left a comment
There was a problem hiding this comment.
تمت مراجعة التصحيحات المقدمة وقد تم إعتمادها
يوجد بعض الملاحظات البسيطة التي تتطلب العمل عليها قبل دمج الطلب
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <locale.h> |
There was a problem hiding this comment.
بما أنه لا يتم إستخدامها إلا مع ويندوز, يفضل نقلها لداخل وسم تعريف ويندوز
#ifdef _WINDOWS
| /* تصل المعاملات إلى main بترميز صفحة النظام، فتتحول الحروف العربية في | ||
| المسار إلى '?' ويفشل فتح الملف على نظام لغته ليست العربية. */ |
There was a problem hiding this comment.
هذا التعليق غير ضروري فالبرنامج يشرح نفسه
يرجى حذفه
- `locale.h` تدخل `#ifdef _WINDOWS`: لا تُستعمل إلا في `wmain` وهي كلها داخل الوسم، فكانت تُحمَّل على لينكس وماك بلا مستعمل واحد. - حذف التعليق فوق `wmain`. لا شيء غيرهما: أربعة أسطر في الأثر. البناء نظيف (`BUILD=0`). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
شكرا على المراجعة ، تفذ الملاحظتين |
Shad7ows
left a comment
There was a problem hiding this comment.
تمت المراجعة والموافقة على دمج الطلب
نحن فريق محراب — بيئةُ تطويرٍ عربيّة شحنّا فيها إضافةَ لغة ألف ومفسِّرَها.
Important
حُدِّث بعد مراجعة @Shad7ows. كان الطلبُ يحمل خمسَ مسائلَ في تسعةِ ملفّاتٍ و٢٤٧ سطراً. عملاً بقاعدتكم «طلبٌ واحدٌ لمشكلةٍ واحدةٍ محدَّدة» صار خمسةَ ملفّاتٍ و٤٦ سطراً، كلُّها ملفّاتُ ويندوز، ويحلّ مشكلةً واحدة: بناءُ ويندوز في السحابة لا يُترجَم.
ما فيه
winBuild/Alif.vcxproj·AlifCore.vcxproj·FreezeModule.vcxproj/utf-8في التهيئاتِ الأربعِ لكلٍّ منها (١٢ سطراً).github/workflows/msbuild.ymlsetup-msbuild@v2· زرُّ تشغيلٍ يدويّsource/FreezeModule/FreezeModule.cppwmainليصل المسارُ العربيُّ إلىFreezeModuleسليماًلماذا
/utf-8ضروريّفي
FormatterUStr.cppحالاتُswitchمكتوبةٌL'ف'وL'ه'وL'ط'. حين يُقرأ المصدرُ بصفحةِ ترميزٍ غير UTF-8 تنهار الأحرفُ إلى بايتِها الأوّلِ فتتكرّر قيمُ الحالاتِ وتُرفض الترجمة.مقيسٌ على جهازٍ صفحةُ ترميزه ANSI هي 1255:
فالعلّةُ ليست خاصّةً بالعدّاء: تصيب كلَّ من يبني من الشجرةِ على نظامٍ صفحتُه ليست عربيّة.
ولماذا
wmainالبناءُ نفسُه يستدعي
FreezeModule.exeبمسارٍ عربيّ:والمعاملاتُ تصل إلى
mainبترميزِ صفحةِ النظام، فتتحوّل الحروفُ العربيّةُ إلى?ويفشل فتحُ الملفّ. الشيفرةُ هنا هي التي اقترحها @Shad7ows حرفيّاً، وزيادةُ سطرٍ واحد:بدونه يبقى
argv[i]غيرَ مهيّأٍ حين يفشلWideCharToMultiByte(نصُّ UTF-16 غيرُ صالح) ثمّ يُستعمَل مساراً.النتيجة
ويندوز ٢/٢ على هذا الرأس — Debug وRelease.
ولا يمسّ الطلبُ لينكس ولا ماك في شيء، فملفُّ سيرِ عملهما خارجَه.
ما أُخرِج إلى طلباتٍ لاحقة
استجابةً للمراجعة، ولم يُحذف بل نُقل:
source/AlifCore/Objects/Import.cpp— دوالُّ المسار العريضة. وهذا أوْلاها بالتقديم، لأنّ الطلبَ الحاليَّ يُصلح الترجمةَ لا التشغيل. مقيسٌ على الجهازِ نفسِه (صفحة 1255):origin/mainImport.cppمرحبا بالعالم✓أي أنّ
statوfopenلا تريان المكتبةَ العربيّةَ الاسمِ على نظامٍ صفحتُه ليست عربيّة. ليس انحداراً —mainأسوأُ حالاً — لكنّ «إصلاحَ بناءِ ويندوز» يبقى ناقصاً بلا هذا.linuxBuild/Makefile—-finput-charsetو-fexec-charsetلِـgcc، مشروطَين بألّا يكون المترجمُ clang (فclang لا يقبل الثاني وتفشل الترجمةُ على ماك)..github/scripts/run_check.shوخطواتُ «تشغيل ما بُني» — الأخضرُ يعني «تُرجم» لا «يعمل».نفتحها في الترتيب الذي ترونه.