سؤال

أي ممارسات موصى بها لتنظيف "Spaghetti رأس" والتي تسبب أوقات تجميع بطيئة للغاية (Linux/UNIX)؟

هل هناك ما يعادل "#pragma مرة واحدة" مع دول مجلس التعاون الخليجي؟
(وجدت رسائل متضاربة بخصوص هذا)

شكرًا.

هل كانت مفيدة؟

المحلول

بافتراض أنك على دراية بـ "includeguards" (#ifdef في بداية الرأس..)، هناك طريقة إضافية لتسريع وقت البناء وهي استخدام حراس التضمين الخارجيين.تمت مناقشته في "تصميم برامج C++ واسعة النطاق".الفكرة هي أن التضمين الكلاسيكي للحراس، على عكس #pragma مرة واحدة، لا يوفر عليك تحليل المعالج المسبق المطلوب لتجاهل الرأس من المرة الثانية فصاعدًا (أي.لا يزال يتعين عليه التحليل والبحث عن بداية ونهاية واقي التضمين.باستخدام أدوات الحماية الخارجية، يمكنك وضع #ifdef حول سطر #include نفسه.

لذلك يبدو مثل هذا:

#ifndef MY_HEADER
#include "myheader.h"
#endif

وبالطبع داخل ملف H لديك حارس التضمين الكلاسيكي

#ifndef MY_HEADER
#define MY_HEADER

// content of header

#endif

بهذه الطريقة لا يتم حتى فتح/تحليل ملف myheader.h بواسطة المعالج المسبق، ويمكن أن يوفر لك الكثير من الوقت في المشاريع الكبيرة، خاصة عندما تكون ملفات الرأس موجودة في مواقع بعيدة مشتركة، كما يحدث أحيانًا.

مرة أخرى، كل شيء في هذا الكتاب.hth

نصائح أخرى

إذا كنت ترغب في إجراء عملية تنظيف كاملة ولديك الوقت الكافي للقيام بذلك، فإن الحل الأفضل هو حذف كافة التضمينات في جميع الملفات (باستثناء الملفات الواضحة، على سبيل المثال.abc.h في abc.cpp) ثم قم بتجميع المشروع.أضف الإعلان أو الرأس اللازم لإعادة التوجيه لإصلاح الخطأ الأول ثم كرر ذلك حتى تكتمل بشكل نظيف.

لا يؤدي هذا إلى إصلاح المشكلات الأساسية التي يمكن أن تؤدي إلى مشكلات التضمين، ولكنه يضمن أن عمليات التضمين الوحيدة هي تلك المطلوبة.

لقد قرأت أن دول مجلس التعاون الخليجي تعتبر #pragma once إهمال، على الرغم من حتى #pragma once لا يمكن إلا أن تفعل الكثير لتسريع الأمور.

لمحاولة فك التشابك #include السباغيتي، يمكنك أن تنظر إلى دوكسيجين.يجب أن يكون قادرًا على إنشاء رسوم بيانية للعناوين المضمنة، مما قد يمنحك ميزة في تبسيط الأمور.لا أستطيع تذكر التفاصيل مرتجلة، لكن ميزات الرسم البياني قد تتطلب منك التثبيت GraphViz وأخبر Doxygen بالمسار حيث يمكنه العثور على dotty.exe الخاص بـ GraphViz.

هناك طريقة أخرى قد تفكر فيها إذا كان وقت الترجمة هو اهتمامك الأساسي وهو الإعداد الرؤوس المترجمة مسبقًا.

قرأت في اليوم الآخر عن خدعة رائعة لتقليل تبعيات الرأس:اكتب السيناريو الذي سوف

  • ابحث عن جميع عبارات #include
  • إزالة عبارة واحدة في وقت واحد وإعادة ترجمة
  • إذا فشل التحويل البرمجي، قم بإضافة عبارة التضمين مرة أخرى

في النهاية، نأمل أن تحصل في النهاية على الحد الأدنى من العناصر المطلوبة في التعليمات البرمجية الخاصة بك.يمكنك كتابة برنامج نصي مشابه يعيد ترتيب التضمينات لمعرفة ما إذا كانت مكتفية ذاتيًا، أو تتطلب تضمين رؤوس أخرى قبلها (قم بتضمين الرأس أولاً، ومعرفة ما إذا كان التجميع قد فشل، والإبلاغ عنه).يجب أن يؤدي ذلك إلى حد ما لتنظيف التعليمات البرمجية الخاصة بك.

بعض الملاحظات الإضافية:

  • تتعرف المترجمات الحديثة (من بينها دول مجلس التعاون الخليجي) على حراس الرأس، وتقوم بالتحسين بنفس الطريقة التي كانت تفعلها pragma من قبل، حيث تفتح الملف مرة واحدة فقط.
  • pragma مرة واحدة يمكن أن تكون مشكلة عندما يكون للملف نفسه أسماء مختلفة في نظام الملفات (أي.مع الروابط الناعمة)

  • يدعم gcc #pragma مرة واحدة، لكنه يصفه بأنه "قديم"
  • pragma مرة واحدة غير مدعومة من قبل جميع المترجمين، وليست جزءًا من معيار C

  • لا يمكن أن يكون المترجمون وحدهم مشكلة.أدوات مثل Incredibuild تواجه أيضًا مشكلات مع #pragma مرة واحدة

كان ريتشارد على حق إلى حد ما (لماذا تم تدوين الحل الذي قدمه؟).

على أية حال، يجب أن تستخدم جميع رؤوس C/C++ أدوات حماية داخلية.

وقال هذا إما:

1 - لم يعد يتم الحفاظ على التعليمات البرمجية القديمة الخاصة بك بعد الآن، ويجب عليك استخدام الرؤوس المجمعة مسبقًا (والتي تعتبر اختراقًا، ولكن مهلاً...حاجتك هي تسريع عملية التحويل البرمجي، وليس إعادة صياغة التعليمات البرمجية التي لم تتم صيانتها)

2 - رمزك القديم لا يزال حيًا.بعد ذلك، يمكنك إما استخدام الرؤوس المترجمة مسبقًا و/أو الحراس/الحراس الخارجيين لحل مؤقت، ولكن في النهاية، ستحتاج إلى إزالة جميع التضمينات الخاصة بك، ملف .C أو .CPP واحد في كل مرة، وتجميع كل ملف . ملف C أو .CPP واحدًا تلو الآخر، مع تصحيح التضمينات الخاصة بهم من خلال التصريحات الأمامية أو التضمين عند الضرورة (أو حتى تقسيم التضمين الكبير إلى ملفات أصغر للتأكد من أن كل ملف .C أو .CPP سيحصل فقط على الرؤوس التي يحتاجها).على أي حال، يعد اختبار وإزالة العناصر القديمة جزءًا من صيانة المشروع، لذا...

تجربتي الخاصة مع الرؤوس المترجمة مسبقًا لم تكن تجربة جيدة تمامًا، لأنه في نصف الوقت، لم يتمكن المترجم من العثور على الرمز الذي حددته، ولذلك حاولت إجراء "تنظيف/إعادة بناء" كامل، للتأكد من أنه لم يكن الرأس المترجم مسبقًا كان ذلك عفا عليه الزمن.لذا أعتقد أن استخدامه للمكتبات الخارجية التي لن تلمسها (مثل رؤوس STL وC API وBoost وما إلى ذلك).ومع ذلك، كانت تجربتي الخاصة مع Visual C++ 6، لذا أعتقد (آمل؟) أنهم فهموا الأمر بشكل صحيح الآن.

والآن شيء أخير:يجب أن تكون الرؤوس دائمًا مكتفية ذاتيًا.وهذا يعني أنه إذا كان إدراج الرؤوس يعتمد على ترتيب التضمين، فهذا يعني أن لديك مشكلة.على سبيل المثال، إذا كنت تستطيع أن تكتب:

#include "AAA.hpp"
#include "BBB.hpp"

لكن لا:

#include "BBB.hpp"
#include "AAA.hpp"

نظرًا لأن BBB يعتمد على AAA، فكل ما لديك هو تبعية لم تعترف بها مطلقًا في الكود.عدم الاعتراف بذلك بتعريف لن يؤدي إلا إلى جعل تجميعك كابوسًا.يجب أن يتضمن BBB AAA أيضًا (حتى لو كان أبطأ إلى حد ما:في النهاية، ستعمل التصريحات الأمامية على أي حال على تنظيف التضمينات غير المفيدة، لذلك يجب أن يكون لديك مؤقت ترجمة أسرع).

استخدم واحدًا أو أكثر من هؤلاء لتسريع وقت الإنشاء

  1. استخدم الرؤوس المترجمة مسبقًا
  2. استخدم آلية التخزين المؤقت (scons على سبيل المثال)
  3. استخدم نظام البناء الموزع ( distcc, Incredibuild($))

في الرؤوس:قم بتضمين الرؤوس فقط إذا كنت لا تستطيع استخدام التصريح الأمامي، ولكن دائمًا # قم بتضمين أي ملف تحتاجه (تضمين التبعيات أمر شرير!).

كما هو مذكور في الإجابة الأخرى، يجب عليك بالتأكيد استخدام الإعلانات الأمامية كلما أمكن ذلك.على حد علمي، لا يوجد لدى دول مجلس التعاون الخليجي أي شيء يعادل #pragma مرة واحدة، ولهذا السبب أتمسك بأسلوب الموضة القديم المتمثل في تضمين الحراس.

شكرًا على الردود، ولكن السؤال يتعلق بالرمز الحالي الذي يتضمن "ترتيب التضمين" الصارم وما إلى ذلك.السؤال هو ما إذا كانت هناك أي أدوات/نصوص برمجية لتوضيح ما يحدث بالفعل.

حراس الرأس ليسوا الحل لأنهم لا يمنعون المترجم من قراءة الملف بأكمله مرارًا وتكرارًا ...

بي سي لينت سوف تقطع شوطا طويلا لتنظيف رؤوس السباغيتي.كما أنه سيحل مشاكل أخرى لك أيضًا مثل عدم ظهور المتغيرات غير المهيأة، وما إلى ذلك.

كما علق onebyone.livejournal.com ردًا على سؤالك، فإن بعض المترجمين يدعمون ذلك تشمل تحسين الحراسة, ، والتي تحددها الصفحة التي قمت بربطها على النحو التالي:

يتم تحسين حماية التضمين عندما يتعرف المترجم على لغة حماية التضمين الداخلية الموضحة أعلاه ويتخذ خطوات لتجنب فتح الملف عدة مرات.يمكن للمترجم أن ينظر إلى ملف التضمين، ويزيل التعليقات والمسافات البيضاء ويحدد ما إذا كان الملف بأكمله موجودًا ضمن حراس التضمين.إذا كان الأمر كذلك، فإنه يقوم بتخزين اسم الملف ويتضمن حالة الحماية في الخريطة.في المرة التالية التي يُطلب فيها من المترجم تضمين الملف، يمكنه التحقق من حالة حماية التضمين واتخاذ القرار بشأن تخطي الملف أو #تضمينه دون الحاجة إلى فتح الملف.

ثم مرة أخرى، لقد أجبت بالفعل على أن الحراس الخارجيين ليسوا الإجابة على سؤالك.لتفكيك ملفات الرأس التي يجب تضمينها بترتيب معين، أود أن أقترح ما يلي:

  • كل .c أو .cpp ينبغي للملف #include المناظرة .h الملف أولا، والباقي منه #include يجب أن يتم فرز التوجيهات أبجديا.ستتلقى عادةً أخطاء في الإنشاء عندما يؤدي ذلك إلى قطع التبعيات غير المعلنة بين ملفات الرأس.
  • إذا كان لديك ملف رأس يحدد typedefs العامة للأنواع الأساسية أو global #define التوجيهات المستخدمة لمعظم التعليمات البرمجية، كل منها .h ينبغي للملف #include هذا الملف أولاً، والباقي منه #include يجب أن يتم فرز التوجيهات أبجديا.
  • عندما تتسبب هذه التغييرات في حدوث أخطاء في الترجمة، سيتعين عليك عادةً إضافة تبعية صريحة من ملف رأس إلى آخر، في شكل ملف #include.
  • عندما لا تسبب هذه التغييرات أخطاء في الترجمة، فقد تسبب تغييرات سلوكية.نأمل أن يكون لديك نوع من مجموعة الاختبار التي يمكنك استخدامها للتحقق من وظائف التطبيق الخاص بك.

يبدو أيضًا أن جزءًا من المشكلة قد يكون أن عمليات البناء المتزايدة تكون أبطأ بكثير مما ينبغي.يمكن تحسين هذا الوضع من خلال الإعلانات الأمامية أو نظام البناء الموزع، كما أشار آخرون.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top