تؤدي إضافة Boost إلى جعل إنشاء Debug يعتمد على ملفات DLL الخاصة بوقت تشغيل MSVC "غير D".

StackOverflow https://stackoverflow.com/questions/222778

سؤال

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

ها هي القصة:لدي تطبيق OpenGL بسيط يعمل بشكل جيد:لا توجد مشكلة كبيرة أبدًا في تجميعها أو ربطها أو تشغيلها.قررت الآن أن أحاول نقل بعض الحسابات الأكثر كثافة إلى سلسلة عمليات، من أجل جعل واجهة المستخدم الرسومية أكثر استجابة - باستخدام Boost.Thread، بالطبع.

باختصار، إذا قمت بإضافة الجزء التالي في بداية ملف .cpp الخاص بي:

#include <boost/thread/thread.hpp>

void dummyThreadFun() { while (1); }    

boost::thread p(dummyThreadFun);

, ، ثم أبدأ في الحصول على رسالة "فشل هذا التطبيق في البدء لأنه لم يتم العثور على MSVCP90.dll" عند محاولة تشغيل إصدار Debug.(وضع الإصدار يعمل بشكل جيد.)

الآن بالنظر إلى الملف القابل للتنفيذ باستخدام Dependency Walker، الذي لم يعثر أيضًا على ملف DLL هذا (وهو أمر متوقع على ما أعتقد)، أستطيع أن أرى أننا نبحث عنه حتى نتمكن من استدعاء الوظائف التالية:

?max@?$numeric_limits@K@std@@SAKXZ
?max@?$numeric_limits@_J@std@@SA_JXZ
?min@?$numeric_limits@K@std@@SAKXZ
?min@?$numeric_limits@_J@std@@SA_JXZ

بعد ذلك، حاولت تحويل كل مثيل لـ min و max لاستخدام وحدات الماكرو بدلاً من ذلك، ولكن ربما لم تتمكن من العثور على كافة المراجع الخاصة بها، لأن هذا لم يساعد.(أنا أستخدم بعض المكتبات الخارجية التي لا يتوفر لدي كود المصدر لها.ولكن حتى لو تمكنت من القيام بذلك، فلا أعتقد أن هذه هي الطريقة الصحيحة حقًا.)

لذا فإن أسئلتي – على ما أعتقد – هي:

  1. لماذا نبحث عن ملف DLL غير قابل للتصحيح على الرغم من العمل مع بنية التصحيح؟
  2. ما هي الطريقة الصحيحة لإصلاح المشكلة؟أو حتى واحدة سريعة وقذرة؟

لقد حصلت على هذا أولاً في تثبيت الفانيليا إلى حد كبير لبرنامج Visual Studio 2008.ثم حاولت تثبيت حزمة الميزات وحزمة الخدمة SP1، لكنهما لم يساعدا أيضًا.بالطبع حاول أيضًا إعادة البناء عدة مرات.

أنا أستخدم الثنائيات المعدة مسبقًا لـ Boost (الإصدار 1.36.0).هذه ليست المرة الأولى التي أستخدم فيها Boost في هذا المشروع، ولكن قد تكون المرة الأولى التي أستخدم فيها جزءًا يعتمد على مصدر منفصل.

تعطيل الارتباط المتزايد لا يساعد.حقيقة أن البرنامج هو OpenGL لا تبدو ذات صلة أيضًا - لقد واجهت مشكلة مماثلة عند إضافة نفس الأسطر الثلاثة من التعليمات البرمجية إلى برنامج وحدة تحكم بسيط (ولكن هناك كان يشكو من MSVCR90.dll و _mkdir, ، وعندما استبدلت الأخير بـ boost::create_directory, ، انتهت المشكلة!!).وهي في الحقيقة مجرد إزالة أو إضافة تلك الأسطر الثلاثة التي تجعل البرنامج يعمل بشكل جيد، أو لا يعمل على الإطلاق، على التوالي.

لا أستطيع أن أقول إنني أفهم برنامج Side-by-Side (لا أعرف حتى ما إذا كان هذا مرتبطًا ولكن هذا ما أفترضه في الوقت الحالي)، ولكي أكون صادقًا، فأنا لست مهتمًا جدًا أيضًا - طالما أستطيع فقط إنشاء تطبيقي وتصحيحه ونشره...


تحرير 1: أثناء محاولتي إنشاء مثال بسيط يعيد إنتاج المشكلة على أي حال، اكتشفت أن المشكلة تتعلق بـ مجموعة أدوات الانتشار, ، والذي يعد استخدامه عاملاً مشتركًا بين جميع برامجي التي تعاني من هذه المشكلة.(ومع ذلك، لم أحصل على هذا مطلقًا قبل البدء في الارتباط بعناصر Boost.)

لقد توصلت الآن إلى الحد الأدنى من البرامج التي تتيح لي إعادة إنتاج المشكلة.وهو يتألف من وحدتي تجميع، A.cpp وB.cpp.

أ.CPP:

#include "sp.h"

int main(int argc, char* argv[])
{
    mailbox mbox = -1;
    SP_join(mbox, "foo");

    return 0;
}

ب.CPP:

#include <boost/filesystem.hpp>

بعض الملاحظات:

  1. إذا قمت بالتعليق خارج الخط SP_join من A.cpp، تختفي المشكلة.
  2. إذا قمت بالتعليق على سطر واحد من B.cpp، فستختفي المشكلة.
  3. إذا قمت بنقل أو نسخ سطر B.cpp المفرد إلى بداية A.cpp أو نهايته، فستختفي المشكلة.

(في السيناريوهين 2 و3، يتعطل البرنامج عند الاتصال SP_join, ولكن هذا فقط لأن صندوق البريد غير صالح...وهذا لا علاقة له بالمسألة المطروحة.)

بالإضافة إلى ذلك، تم ربط مكتبة Spread الأساسية، وهذا بالتأكيد جزء من الإجابة على سؤالي رقم 1، حيث لا يوجد بناء تصحيح لهذا lib في نظامي.

أحاول حاليًا التوصل إلى شيء يجعل من الممكن إعادة إنتاج المشكلة في بيئة أخرى.(على الرغم من أنني سأفاجأ تمامًا إذا كان من الممكن تكرار ذلك خارج المبنى الخاص بي ...)


تحرير 2: حسنا اذا هنا لدينا الآن حزمة تمكنت من خلالها من إعادة إنتاج المشكلة على تثبيت بسيط تقريبًا لـ WinXP32 + VS2008 + Boost 1.36.0 (لا يزال الثنائيات المعدة مسبقًا من BoostPro Computing).

من المؤكد أن السبب وراء ذلك هو Spread lib، الذي يتطلب تصميمي منه بطريقة ما إصدارًا قديمًا إلى حد ما من STLPort لـ إم إس في سي 6!ومع ذلك، ما زلت أجد الأعراض مسلية نسبيًا.سيكون من الجيد أيضًا معرفة ما إذا كان بإمكانك إعادة إظهار المشكلة بالفعل، بما في ذلك السيناريوهات 1-3 أعلاه.الحزمة صغيرة جدًا ويجب أن تحتوي على جميع القطع الضرورية.

كما اتضح، لم يكن للمشكلة أي علاقة بـ Boost.Thread على وجه التحديد، حيث يستخدم هذا المثال الآن مكتبة Boost Filesystem.بالإضافة إلى ذلك، فهو الآن يشكو من MSVCR90.dll، وليس P كما كان سابقًا.

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

المحلول

يحتوي Boost.Thread على عدد لا بأس به من مجموعات البناء الممكنة لمحاولة تلبية جميع الاختلافات في ربط السيناريوهات الممكنة مع MSVC.أولاً، يمكنك إما الارتباط بشكل ثابت بـ Boost.Thread، أو الارتباط بـ Boost.Thread في ملف DLL منفصل.يمكنك بعد ذلك الارتباط بإصدار DLL الخاص بوقت تشغيل MSVC، أو وقت تشغيل المكتبة الثابتة.وأخيرًا، يمكنك الارتباط بوقت تشغيل التصحيح أو وقت تشغيل الإصدار.

تحاول رؤوس Boost.Thread اكتشاف سيناريو الإنشاء تلقائيًا باستخدام وحدات الماكرو المحددة مسبقًا التي ينشئها المترجم.من أجل الارتباط بالإصدار الذي يستخدم وقت تشغيل التصحيح، يجب أن يكون لديك _DEBUG مُعرف.يتم تعريف ذلك تلقائيًا بواسطة مفاتيح التحويل البرمجي /MD و /MDd، لذلك يجب أن يكون الأمر على ما يرام، ولكن وصف مشكلتك يشير إلى خلاف ذلك.

من أين حصلت على الثنائيات المعدة مسبقًا؟هل تقوم بتحديد مكتبة بشكل صريح في إعدادات مشروعك، أم أنك تسمح لآلية الارتباط التلقائي بتحديد ملف .lib المناسب؟

نصائح أخرى

أعتقد أنني واجهت نفس المشكلة مع Boost في الماضي.من وجهة نظري يحدث ذلك لأن رؤوس Boost تستخدم تعليمات المعالج المسبق للربط مع lib المناسب.إذا كانت مكتبات التصحيح والإصدار موجودة في نفس المجلد ولها أسماء مختلفة، فلن تعمل ميزة "الارتباط التلقائي" بشكل صحيح.

ما قمت به هو تحديد BOOST_ALL_NO_LIB لمشروعي (مما يمنع الرؤوس من "الربط التلقائي") ثم استخدام إعدادات مشروع VC للربط بالمكتبات الصحيحة.

يبدو أن الأشخاص الآخرين قد أجابوا على الجانب المعزز من المشكلة.فيما يلي بعض المعلومات الأساسية عن جانب MSVC للأشياء، والتي قد توفر المزيد من الصداع.

هناك 4 إصدارات ممكنة من أوقات التشغيل C (وC++):

  • / طن متري:libcmt.lib (C)، libcpmt.lib (C++)
  • / مليون دينار:libcmtd.lib، libcpmtd.lib
  • /إم دي:msvcrt.lib، msvcprt.lib
  • / م د:msvcrtd.lib، msvcptd.lib

لا تزال إصدارات DLL تتطلب الارتباط بهذا lib الثابت (والذي يقوم بطريقة ما بتنفيذ جميع عمليات الإعداد للربط بـ DLL في وقت التشغيل - لا أعرف التفاصيل).لاحظ في جميع الحالات أن إصدار التصحيح يحتوي على d لاحقة.يستخدم وقت التشغيل C c infix، ويستخدم وقت التشغيل C++ ملحق cp أقحم.انظر النمط؟في أي تطبيق، يجب عليك فقط الارتباط بالمكتبات الموجودة في أحد هذه الصفوف.

في بعض الأحيان (كما في حالتك)، تجد نفسك ترتبط بمكتبة ثابتة لشخص آخر تم تكوينها لاستخدام الإصدار الخاطئ من أوقات تشغيل C أو C++ (عبر الرابط المزعج للغاية #pragma comment(lib)).يمكنك اكتشاف ذلك عن طريق رفع مستوى إسهاب الرابط الخاص بك، ولكنه برنامج بيتا حقيقي يجب البحث عنه.الحل "اقتل القوارض بالبازوكا" هو استخدام /nodefaultlib:... إعداد رابط لاستبعاد مكتبات 6 C وC++ التي تعلم أنك لا تحتاج إليها.لقد استخدمت هذا في الماضي دون مشكلة، لكنني لست متأكدًا من أنه سيعمل دائمًا ...ربما سيخرج شخص ما من العمل الخشبي ليخبرني كيف قد يؤدي هذا "الحل" إلى قيام برنامجك بأكل الأطفال بعد ظهر يوم الثلاثاء.

هذا خطأ ارتباط كلاسيكي.يبدو أنك كذلك الارتباط بـ Boost DLL يرتبط هذا في حد ذاته بوقت تشغيل C++ خاطئ (يوجد أيضًا هذه الصفحة, ، قم بالبحث النصي عن "المواضيع").ويبدو أيضًا أن boost::posix::time روابط المكتبة إلى DLL الصحيح.

لسوء الحظ، لم أجد الصفحة التي تناقش كيفية اختيار Boost DLL المبني بشكل صحيح (على الرغم من أنني وجدت البريد الإلكتروني لمدة ثلاث سنوات يبدو أن هذا يشير إلى BOOST_THREAD_USE_DLL و BOOST_THREAD_USE_LIB).


بالنظر إلى إجابتك مرة أخرى، يبدو أنك تستخدم الثنائيات المعدة مسبقًا.ملف DLL الذي لا يمكنك الارتباط به هو جزء من حزمة ميزات TR1 (السؤال الثاني في تلك الصفحة). تتوفر حزمة الميزات هذه على موقع Microsoft على الويب.أو ستحتاج إلى ثنائي مختلف للارتباط به.على ما يبدو boost::posix::time روابط المكتبة مقابل وقت تشغيل C++ غير المصحح.

نظرًا لأنك قمت بالفعل بتطبيق حزمة الميزات، أعتقد أن الخطوة التالية التي سأتخذها هي إنشاء Boost يدويًا.هذا هو الطريق الذي أتبعه دائمًا، وهو بسيط جدًا: قم بتنزيل ثنائي BJam, وتشغيل البرنامج النصي Boost Build في مصدر المكتبة.هذا كل شيء.

الآن أصبح هذا أكثر إثارة للاهتمام قليلاً ...إذا قمت فقط بإضافة هذا في مكان ما في المصدر:

boost::posix_time::ptime pt = boost::posix_time::microsec_clock::universal_time();

(مع المقابلة #include الأشياء)، ثم يعمل بشكل جيد مرة أخرى.إذن هذا حل سريع وليس قذرًا جدًا، ولكن مهلا - ما الذي يحدث هنا، حقًا؟

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

ال BOOST_THREAD_USE_DLL لن يكون السبب وراء هذا الخطأ بالتحديد، ولكن قد يتوقع منك تحديده _DEBUG أو شيء من هذا القبيل.أتذكر أنه قبل بضع سنوات، في مشاريعنا التعزيزية لـ C++، كان لدينا عدد لا بأس به من الإضافات BOOST_XYZ تعريفات المعالج المسبق المعلنة في خيارات مترجم الاستوديو المرئي (أو ملف التعريف)

افحص ال config.hpp ملف في دليل موضوع دفعة.عندما تقوم بسحب ptime الأشياء التي من المحتمل أن تتضمن ملفًا مختلفًا config.hpp file، والذي قد يحدد بعد ذلك أشياء المعالج المسبق بشكل مختلف.

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