Добавление Boost делает сборку Debug зависимой от «не-D» библиотек времени выполнения MSVC - PullRequest
5 голосов
/ 21 октября 2008

У меня есть досадная проблема, которую я мог бы как-то обойти, но с другой стороны, я бы предпочел быть на вершине и понять, что именно происходит, так как похоже, что эти вещи действительно здесь, чтобы остаться.

Вот история: у меня есть простое приложение OpenGL, которое прекрасно работает: никогда не возникает серьезных проблем при компиляции, компоновке или запуске. Теперь я решил попробовать перенести некоторые из более интенсивных вычислений в рабочий поток, чтобы сделать GUI еще более отзывчивым - конечно, с помощью 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. Затем попытался установить Feature Pack и SP1, но они тоже не помогли. Конечно, также пытался восстановить несколько раз.

Я использую готовые двоичные файлы для Boost (v1.36.0). Это не первый раз, когда я использую Boost в этом проекте, но это может быть первый раз, когда я использую деталь, основанную на отдельном источнике.

Отключение инкрементных ссылок не помогает. Тот факт, что программа OpenGL, похоже, тоже не актуален - у меня возникла похожая проблема при добавлении тех же трех строк кода в простую консольную программу (но там она жаловалась на MSVCR90.dll и _mkdir, и когда я заменил последний на boost::create_directory, проблема ушла !!). И действительно, просто удаляя или добавляя эти три строки, программа работает нормально или вообще не запускается, соответственно.

Не могу сказать, что понимаю «бок о бок» (даже не знаю, связано ли это с этим, но сейчас я так предполагаю), и, честно говоря, я тоже не очень заинтересован - пока Я могу просто собрать, отладить и развернуть свое приложение ...


Редактировать 1: При попытке создать урезанный пример, который в любом случае воспроизводит проблему, я обнаружил, что проблема связана с Spread Toolkit , использование что является общим фактором для всех моих программ, имеющих эту проблему. (Однако у меня никогда не было этого до того, как я начал ссылаться в Boost.)

Теперь я разработал минимальную программу, которая позволяет мне воспроизвести проблему. Он состоит из двух блоков компиляции, A.cpp и B.cpp.

a.cpp:

#include "sp.h"

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

    return 0;
}

B.cpp:

#include <boost/filesystem.hpp>

Некоторые наблюдения:

  1. Если я закомментирую строку SP_join файла A.cpp, проблема исчезнет.
  2. Если я закомментирую одну строку B.cpp, проблема исчезнет.
  3. Если я переместлю или скопирую одну строку B.cpp в начало или конец A.cpp, проблема исчезнет.

(В сценариях 2 и 3 происходит сбой программы при вызове SP_join, но это только потому, что почтовый ящик недействителен ... это не имеет никакого отношения к рассматриваемой проблеме.)

Кроме того, ядро ​​библиотеки Spread связано, и это, безусловно, часть ответа на мой вопрос # 1, поскольку в моей системе нет отладочной сборки этой библиотеки.

CurrenВ общем, я пытаюсь придумать что-то, что позволило бы воспроизвести проблему в другой среде. (Даже если я буду очень удивлен, если это действительно будет повторяться за пределами моего помещения ...)


Редактировать 2: Хорошо, поэтому здесь теперь у нас есть пакет, с помощью которого я смог воспроизвести проблему на почти ванильной установке WinXP32 + VS2008 + Boost 1.36.0 (по-прежнему предварительно собранные двоичные файлы от BoostPro Computing ).

Виновником, безусловно, является библиотека Spread, моя сборка которой почему-то требует довольно архаичной версии STLPort для MSVC 6 ! Тем не менее, я все еще нахожу симптомы довольно забавными. Кроме того, было бы неплохо услышать, если вы действительно можете воспроизвести проблему - в том числе сценарии 1-3 выше. Упаковка довольно маленькая и должна содержать все необходимые кусочки.

Как выяснилось, проблема на самом деле не имела ничего общего с Boost. В частности, поскольку в этом примере теперь используется библиотека Boost Filesystem. Кроме того, теперь он жалуется на MSVCR90.dll, а не на P, как ранее.

Ответы [ 6 ]

2 голосов
/ 22 октября 2008

Boost.Thread имеет довольно много возможных комбинаций сборки, чтобы попытаться учесть все различия в сценариях связывания, возможных с MSVC. Во-первых, вы можете либо статически связать Boost.Thread, либо ссылку на Boost.Thread в отдельной DLL. Затем вы можете связать с версией DLL среды выполнения MSVC или статической библиотеки времени выполнения. Наконец, вы можете связать со средой отладки или средой выпуска.

Заголовки Boost.Thread пытаются автоматически определить сценарий сборки, используя предопределенные макросы, которые генерирует компилятор. Для связи с версией, которая использует среду отладки, вам нужно определить _DEBUG. Это автоматически определяется ключами компилятора / MD и / MDd, так что все должно быть в порядке, но в описании вашей проблемы предлагается иное.

Откуда вы взяли предварительно собранные двоичные файлы? Вы явно выбираете библиотеку в настройках своего проекта или разрешаете механизму автоматической ссылки выбрать соответствующий файл .lib?

1 голос
/ 23 октября 2008

Похоже, что другие люди ответили на Boost сторону вопроса. Вот немного справочной информации о стороне MSVC, которая может избавить от головной боли.

Возможны 4 версии C (и C ++):

  • / MT: libcmt.lib (C), libcpmt.lib (C ++)
  • / MTd: libcmtd.lib, libcpmtd.lib
  • / MD: msvcrt.lib, msvcprt.lib
  • / MDd: msvcrtd.lib, msvcprtd.lib

Версии DLL по-прежнему требуют ссылки на эту статическую библиотеку (которая каким-то образом выполняет всю настройку для связи с DLL во время выполнения - я не знаю деталей). Обратите внимание, что во всех случаях отладочная версия имеет суффикс d. Среда выполнения C использует инфикс c, а среда выполнения C ++ использует инфикс cp. Видите образец? В любом приложении вы должны когда-либо ссылаться только на библиотеки в одной из этих строк.

Иногда (как и в вашем случае) вы обнаруживаете, что связываетесь с чужой статической библиотекой, настроенной на использование неверной версии сред выполнения C или C ++ (через ужасно надоедливую #pragma comment(lib)). Вы можете обнаружить это, повернув многословность вашего компоновщика, но это настоящая PITA, на которую можно охотиться. Решение "убить грызуна с помощью базуки" заключается в использовании параметра компоновщика /nodefaultlib:... для исключения библиотек 6 C и C ++, которые, как вы знаете, вам не нужны. Я использовал это в прошлом без проблем, но я не уверен, что это всегда будет работать ... может быть, кто-то выйдет из работы по дереву и расскажет мне, как это "решение" может заставить вашу программу есть детей во вторник после обеда .

1 голос
/ 22 октября 2008

Я думаю, что у меня была такая же проблема с Boost в прошлом. Насколько я понимаю, это происходит потому, что заголовки Boost используют инструкцию препроцессора для связи с нужной библиотекой. Если библиотеки отладки и выпуска находятся в одной и той же папке и имеют разные имена, функция автоматической ссылки не будет работать должным образом.

Что я сделал, так это определил BOOST_ALL_NO_LIB для моего проекта (что не позволяет заголовкам «автоматически связывать») и затем использовал настройки проекта VC для связи с правильными библиотеками.

1 голос
/ 22 октября 2008

Это классическая ошибка ссылки. Похоже, вы ссылаетесь на 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 в исходном коде библиотеки. Вот и все.

0 голосов
/ 22 октября 2008

Из памяти различным частям библиотек boost необходимо определить некоторые флаги препроцессора для правильной компиляции. Вещи типа BOOST_THREAD_USE_DLL и т. Д.

BOOST_THREAD_USE_DLL не будет причиной этой конкретной ошибки, но может ожидать, что вы определите _DEBUG или что-то в этом роде. Я помню, как несколько лет назад в наших проектах по расширению C ++ у нас было довольно много дополнительных BOOST_XYZ определений препроцессора, объявленных в опциях компилятора Visual Studio (или makefile)

Проверьте файл config.hpp в каталоге ветки поддержки. Когда вы извлекаете материал ptime, он, возможно, включает в себя другой файл config.hpp, который затем может определять эти препроцессоры по-разному.

0 голосов
/ 21 октября 2008

Теперь это стало еще интереснее ... Если я просто добавлю это где-нибудь в источнике:

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

(вместе с соответствующим #include материалом), затем снова работает нормально. Так что это одно быстрое и даже не слишком грязное решение, но, эй, что здесь происходит, правда?

...