
موافق ، إنه أمر جيد ومفيد عندما تبدو الشفرة المصدرية في المشروع جميلة ومتسقة. هذا يسهل فهمه ودعمه. نعرض ونخبرك بكيفية تنفيذ تنسيق شفرة المصدر باستخدام
clang-format و
git و
sh .
مشاكل التنسيق وكيفية حلها
في معظم المشاريع ، هناك قواعد معينة لتصميم الكود. كيف تتأكد من قيام جميع المشاركين بتنفيذها؟ تأتي البرامج الخاصة للإنقاذ - تنسيق clang ، astyle ، غير موثوق به ، - لكن لها عيوبها.
تكمن المشكلة الرئيسية في التنسيق في تغيير الملفات بالكامل ، وليس فقط تغيير الخطوط. سنخبرك بكيفية تعاملنا مع هذا ، باستخدام ClangFormat كجزء من أحد مشاريع تطوير البرامج الثابتة للإلكترونيات ، حيث كانت لغة C ++ هي اللغة الرئيسية. عمل العديد من الأشخاص في الفريق ، لذلك كان من المهم بالنسبة لنا توفير نمط رمز موحد. يمكن أن يكون حلنا مناسبًا ليس فقط لمبرمجي C ++ ، ولكن أيضًا لأولئك الذين يكتبون الكود في C و Objective-C و JavaScript و Java و Protobuf.
للتنسيق ، استخدمنا clang-format-diff-6.0 . في البداية ، بدأوا الفريق
بوابة فرق -U0 - لا لون | clang-format-diff-6.0 -i -p1 ، ولكن كانت هناك مشاكل معها:
- حدد البرنامج أنواع الملفات فقط بالامتداد. على سبيل المثال ، يتم اعتبار ملفات ذات ملحق ts ، والتي كانت لدينا بتنسيق xml ، بمثابة JavaScript وتعطلت عند التنسيق. ثم ، لسبب ما ، حاولت إصلاح الملفات المؤيدة لمشاريع كيو تي ، ربما مثل بروتوبوف.
- كان يجب بدء البرنامج يدويًا قبل إضافة الملفات إلى فهرس git. كان من السهل نسيانها.
الحل
كانت النتيجة هي sh-script التالية ، تشغيل
كالتزام مسبق - ربط git:
#!/bin/sh CLANG_FORMAT="clang-format-diff-6.0 -p1 -v -sort-includes -style=Chromium -iregex '.*\.(cxx|cpp|hpp|h)$' " GIT_DIFF="git diff -U0 --no-color " GIT_APPLY="git apply -v -p0 - " FORMATTER_DIFF=$(eval ${GIT_DIFF} --staged | eval ${CLANG_FORMAT}) echo "\n------Format code hook is called-------" if [ -z "${FORMATTER_DIFF}" ]; then echo "Nothing to be formatted" else echo "${FORMATTER_DIFF}" echo "${FORMATTER_DIFF}" | eval ${GIT_APPLY} --cached echo " ---Format of staged area completed. Begin format unstaged files---" eval ${GIT_DIFF} | eval ${CLANG_FORMAT} | eval ${GIT_APPLY} fi echo "------Format code hook is completed----\n" exit 0
ماذا يفعل البرنامج النصي:
GIT_DIFF = "git diff -U0 - no-color" - التغييرات في التعليمات البرمجية التي سيتم إدخالها إلى
clang-format-diff-6.0.- -U0 : git diff يعرض عادة ما يسمى "السياق": بضعة أسطر من الشفرات لم تتغير حول تلك التي تم تغييرها. لكن clang-format-diff-6.0 يقوم بتنسيقها أيضًا! لذلك ، ليست هناك حاجة السياق في هذه الحالة.
CLANG_FORMAT = "clang-format-diff-6.0 -p1 -v -sort-include -style = Chromium -iregex '. * \. (Cxx | cpp | hpp | h) $'" - أمر لتنسيق الفرق المستلم عبر المعيار المدخلات.
- clang-format-diff-6.0 - برنامج نصي من الحزمة clang-format-6.0 . هناك إصدارات أخرى ، ولكن جميع الاختبارات كانت فقط على هذا واحد.
- -p1 مأخوذة من أمثلة في الوثائق ، يوفر التوافق مع إخراج فرق بوابة .
- -style = Chromium - إعداد مسبق لتنسيق الكود جاهز. القيم المحتملة الأخرى: LLVM ، Google ، Mozilla ، WebKit .
- -sort-include - خيار الفرز الأبجدي # يتضمن التوجيهات (اختياري).
- -iregex '. * \. (cxx | cpp | hpp | h) $' هو تعبير عادي يقوم بتصفية أسماء الملفات حسب الامتداد. فقط تلك الملحقات التي تحتاج إلى تنسيق مدرجة هنا. هذا سيوفر البرنامج من السقوط ومواطن الخلل غير المتوقعة. على الأرجح ستحتاج القائمة إلى استكمالها في مشاريع جديدة. بالإضافة إلى C ++ ، يمكنك تنسيق C / Objective-C / JavaScript / Java / Protobuf . رغم أننا لم نختبر هذه الأنواع من الملفات.
GIT_APPLY = "git apply -v -p0 -" - قم بتطبيق التصحيح الذي أصدره الأمر السابق على الكود.
- -p0 : بشكل افتراضي ، يتخطى تطبيق git المكون الأول في مسار الملف ، وهذا غير متوافق مع التنسيق الذي ينتجه clang -format-diff-6.0 . تم تعطيل هذا الطفر هنا.
FORMATTER_DIFF = $ (eval $ {GIT_DIFF} - Staged | eval $ {CLANG_FORMAT}) - تغييرات التنسيق للفهرس.
صدى "$ {FORMATTER_DIFF}" | eval $ {GIT_APPLY} - التنسيقات
المخزنة مؤقتًا الشفرة المصدرية في الفهرس (بعد
إضافة git ). لسوء الحظ ، لا يوجد ربط يعمل قبل إضافة الملفات إلى الفهرس. لذلك ، يتم تقسيم التنسيق إلى جزأين: تنسيق ما في الفهرس وفصل ما لم تتم إضافته إلى الفهرس.
eval $ {GIT_DIFF} | eval $ {CLANG_FORMAT} | eval $ {GIT_APPLY} - تنسيق الكود ليس في الفهرس (يبدأ فقط عندما يتم تنسيق شيء ما في الفهرس). التنسيقات بشكل عام جميع التغييرات الحالية في المشروع (تحت التحكم في الإصدار) ، وليس فقط من الخطوة السابقة. هذا قرار مثير للجدل للوهلة الأولى. ولكن اتضح أنها مريحة ، لأن عاجلاً أو آجلاً ، يجب تنسيق التغييرات الأخرى أيضًا. يمكنك استبدال
"| eval $ {GIT_APPLY}" بخيار
-i ، والذي سيجبر
$ {CLANG_FORMAT} على تغيير الملفات بأنفسهم.
مظاهرة العمل
- تثبيت clang-format-6.0
- cd / tmp && mkdir temp_project && cd temp_project
- بوابة الحرف الأول
- إضافة عنصر تحكم الإصدار والالتزام بأي ملف C ++ تحت اسم wrong.cpp . ويفضل أن يكون> 50 سطرًا من التعليمات البرمجية غير المنسقة.
- تأكد من البرنامج النصي .git / hooks / pre-الالتزام الموضح أعلاه.
- عيّن الحق في تشغيل البرنامج النصي (من أجل git): chmod + x .git / hooks / pre-الالتزام .
- قم بتشغيل البرنامج النصي .git / hooks / pre-الالتزام يدويًا ، يجب تشغيله مع الرسالة "لا شيء لتنسيقه" ، دون أخطاء في الترجمة.
- قم بإنشاء file.cpp مع المحتويات int main () {for (int i = 0؛ i <100؛ ++ i) {std :: cout << "الحالة الأولى" << std :: endl؛ الأمراض المنقولة جنسيا :: cout << "الحالة الثانية" << std :: endl؛ الأمراض المنقولة جنسيا :: cout << "الحالة الثالثة" << std :: endl؛ }} مع سطر واحد أو مع تنسيق غير صحيح. في نهاية خط تغذية!
- git add file.cpp && git الالتزام - يجب أن يكون "file.cpp" عبارة عن رسائل من برنامج نصي مثل "Patch file.cpp مطبقًا دون أخطاء" .
- يجب أن تظهر git log -p -1 إضافة ملف منسق.
- إذا حصلت file.cpp على الالتزام المنسق فعلاً ، فيمكنك اختبار التنسيق في فرق فقط. قم بتغيير زوج wrong.cpp من الأسطر بحيث يستجيب المنسق لها. على سبيل المثال ، أضف مسافة بادئة غير كافية في الشفرة مع التغييرات الأخرى. git الالتزام -a -m "تنسيق فرق فقط" يجب ملء التغييرات المنسقة ، ولكن لا يؤثر على أجزاء أخرى من الملف.
العيوب والمشاكل
git diff - staged (وهو هنا
{{GIT_DIFF} - staged ) فقط
فرق الملفات التي تمت إضافتها إلى الفهرس. و
clang-format-diff-6.0 يصل إلى النسخ الكاملة للملفات خارجها. لذلك ، إذا قمت بتغيير أحد الملفات ، وقمت
بإضافة git ، ثم قمت بتغيير نفس الملف ،
فسيقوم clang-format-diff-6.0 بإنشاء تصحيح لتنسيق الكود (في الفهرس) استنادًا إلى ملف مختلف. وبالتالي ، فمن الأفضل عدم تحرير الملف بعد
إضافة git وقبل الالتزام.
فيما يلي مثال على هذا الخطأ:
- أضف std :: endl إضافية إلى file.cpp ، "الحالة الثانية" . (std :: cout << "الحالة الثانية" << std :: endl << std :: endl؛) وبعض علامات تبويب المسافة البادئة الزائدة قبل السطر.
- بوابة إضافة file.cpp
- امسح السطر (في نفس الملف) مع "الحالة الأولى" بحيث تبقى فاصل الأسطر فقط في مكانه (!).
- بوابة الالتزام - م "خطأ المنسق على الالتزام" .
يجب أن يبلغ البرنامج النصي عن
"خطأ: أثناء البحث:" ، أي
بوابة تطبيق لم تجد سياق التصحيح الصادر عن
clang-format-diff-6.0 . إذا كنت لا تفهم ما المشكلة هنا ، لا تقم بتغيير الملفات بعد
إضافتها وقبل
الالتزام . إذا كنت بحاجة إلى التغيير ، فيمكنك الالتزام (بدون دفع) ثم
الالتزام - تعديل التغييرات الجديدة.
أخطر قيود هو الحاجة إلى وجود فاصل أسطر في نهاية كل ملف. هذه ميزة git قديمة ، لذا يدعم معظم برامج تحرير الشفرة الإدراج التلقائي لمثل هذه الترجمة في نهاية الملف. بدون هذا ، سيتعطل البرنامج النصي عند ارتكاب ملف جديد ، لكنه لن يتسبب في أي ضرر.
نادرًا ما ، يقوم clang-format-diff-6.0 بتنسيق الكود بشكل غير لائق. في هذه الحالة ، يمكنك إضافة بعض العناصر غير المجدية إلى الكود ، مثل فاصلة منقوطة. أو ، قم بإحاطة الكود الإشكالي بالتعليقات ، و / * clang-format off * / و / * clang-format on * / .
أيضا clang-format-diff-6.0 قد ينتج رقعة غير كافية. ينتهي هذا الأمر بتطبيق git وعدم قبوله ، ويظل رمز جزء الالتزام غير منسق. السبب هو داخل clang-format-diff . لا يوجد وقت لفهم جميع أخطاء البرنامج. في هذه الحالة ، يمكنك إلقاء نظرة على تصحيح التنسيق باستخدام الأمر git diff -U0 - لا لون HEAD ^ | clang-format-diff-6.0 -p1 -v -sort-include -style = Chromium -iregex '. * \. (cxx | cpp | hpp | h) $' . الحل الأسهل هو إضافة الخيار -i إلى الأمر السابق. في هذه الحالة ، لن تصدر الأداة المساعدة تصحيحًا ، ولكنها ستقوم بتنسيق التعليمات البرمجية. إذا لم ينجح ذلك ، فيمكنك محاولة التنسيق للملفات الفردية بشكل كامل clang-format-6.0 -i -sort-include -style = Chromium file.cpp . التالي هو git add file.cpp و git ارتكاب - تعديل .
هناك افتراض أنه كلما كان تنسيق .clang الخاص بك أقرب إلى أحد الإعدادات المسبقة ، كلما قلت هذه الأخطاء. (هنا يتم استبداله بخيار النمط = Chromium ).
تصحيح الأخطاء
إذا كنت تريد معرفة التغييرات التي
سيجريها البرنامج النصي على تعديلاتك الحالية (وليس في الفهرس) ، فاستخدم
git diff -U0 - no-color | clang-format-diff-6.0 -p1 -v -sort-include -style = Chromium -iregex '. * \. (cxx | cpp | hpp | h) $' يمكنك أيضًا التحقق من كيفية عمل البرنامج النصي في آخر عمليات الالتزام ، على سبيل المثال ، في الثلاثين:
git filter-branch -f --tree-filter "$ {PWD} /. git / hooks / pre-duty" --prune-blank HEAD ~ 30..HEAD . يجب أن يكون هذا الأمر منسقًا لطلبات سابقة ، لكن في الحقيقة يتغير هويتهم فقط. لذلك ، يجدر إجراء مثل هذه التجارب في نسخة منفصلة من المشروع! بعد أن تصبح غير صالحة للاستعمال.
الخاتمة
ذاتي ، مثل هذا القرار هو أكثر بكثير من الضرر. لكنك تحتاج إلى اختبار سلوك
clang-format-diff للإصدارات المختلفة على رمز مشروعك ، من خلال تكوين لنمط الكود الخاص بك.
لسوء الحظ ، لم نفعل نفس بوابة git لنظام التشغيل Windows. أقترح في التعليقات كيفية القيام بذلك هناك. وإذا كنت بحاجة إلى مقال لبداية سريعة
بتنسيق clang ،
فننصحك بالاطلاع على وصف ClangFormat .