Добавление 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 не найден» при попытке запустить отладочную сборку.(Режим выпуска работает нормально.)

Теперь, посмотрев на исполняемый файл с помощью 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, проблема ушла!!).И на самом деле просто удаление или добавление этих трех строк позволяет программе работать нормально или вообще не работать соответственно.

Я не могу сказать, что понимаю 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, поскольку в моей системе нет отладочной сборки этой библиотеки.

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


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

Виновником, безусловно, является библиотека Spread, моя сборка которой почему-то требует довольно архаичной версии 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 используют инструкцию препроцессора для связи с соответствующей библиотекой.Если ваши библиотеки отладки и выпуска находятся в одной папке и имеют разные имена, функция «автоматического связывания» не будет работать должным образом.

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

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

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

  • /МТ:libcmt.lib (C), libcpmt.lib (C++)
  • /МТд:libcmtd.lib, libcpmtd.lib
  • /МД:msvcrt.lib, msvcprt.lib
  • /МДд:msvcrtd.lib, msvcprtd.lib

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

Иногда (как в вашем случае) вы ссылаетесь на чью-то статическую библиотеку, которая настроена на использование неправильной версии среды выполнения C или C++ (через ужасно раздражающую #pragma comment(lib)).Вы можете обнаружить это, увеличив уровень детализации компоновщика, но это настоящая PITA, за которой стоит охотиться.Решение «убить грызуна из базуки» — использовать /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 или что-то вроде того.Я помню, несколько лет назад в наших проектах Boost C++ у нас было немало дополнительных BOOST_XYZ определения препроцессора, объявленные в параметрах компилятора Visual Studio (или make-файле)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top