Добавление Boost делает сборку Debug зависимой от "не-D" библиотек времени выполнения MSVC
У меня есть досадная проблема, которую я мог бы как-то обойти, но с другой стороны, я бы предпочел быть на вершине и понять, что именно происходит, так как похоже, что эти вещи действительно здесь, чтобы остаться.
Вот история: у меня есть простое приложение 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
вместо этого использовать макросы, но, вероятно, не смог найти все ссылки на них, так как это не помогло. (Я использую некоторые внешние библиотеки, для которых у меня нет доступного исходного кода. Но даже если бы я мог сделать это - я не думаю, что это действительно правильный путь.)
Итак, мои вопросы - я думаю, - это:
- Почему мы ищем не отладочную DLL, хотя работаем с отладочной сборкой?
- Как правильно решить проблему? Или даже быстрый и грязный?
У меня было это сначала в довольно ванильной установке 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>
Некоторые наблюдения:
- Если я закомментирую строку
SP_join
A.cpp, проблема уходит. - Если я закомментирую единственную строку B.cpp, проблема исчезнет.
- Если я переместлю или скопирую отдельную строку B.cpp в начало или конец A.cpp, проблема исчезнет.
(В сценариях 2 и 3 происходит сбой программы при вызове SP_join
, но это только потому, что почтовый ящик недействителен... это не имеет ничего общего с рассматриваемой проблемой.)
Кроме того, ядро библиотеки Spread связано, и это, безусловно, часть ответа на мой вопрос № 1, поскольку в моей системе нет отладочной сборки этой библиотеки.
В настоящее время я пытаюсь найти что-то, что позволило бы воспроизвести проблему в другой среде. (Даже если я буду очень удивлен, если это на самом деле можно повторить за пределами моего помещения...)
Редактировать 2: Хорошо, теперь у нас есть пакет, с помощью которого я смог воспроизвести проблему на почти ванильной установке WinXP32 + VS2008 + Boost 1.36.0 (все еще предварительно скомпилированные двоичные файлы из BoostPro Computing).
Виновником, несомненно, является библиотека Spread, моя сборка которой почему-то требует довольно архаичной версии STLPort для MSVC 6! Тем не менее, я все еще нахожу симптомы довольно забавными. Кроме того, было бы неплохо услышать, если вы действительно можете воспроизвести проблему - в том числе сценарии 1-3 выше. Упаковка довольно маленькая, и в ней должны быть все необходимые кусочки.
Как выясняется, проблема на самом деле не имела ничего общего с Boost.Thread, поскольку в этом примере теперь используется библиотека Boost Filesystem. Кроме того, теперь он жалуется на MSVCR90.dll, а не на P, как ранее.
6 ответов
Boost.Thread имеет довольно много возможных комбинаций сборок, чтобы попытаться удовлетворить все различия в сценариях связывания, возможных с MSVC. Во-первых, вы можете либо статически связать Boost.Thread, либо ссылку на Boost.Thread в отдельной DLL. Затем вы можете связать с версией DLL среды выполнения MSVC или статической библиотеки времени выполнения. Наконец, вы можете связать со средой отладки или средой выпуска.
Заголовки Boost.Thread пытаются автоматически определить сценарий сборки, используя предопределенные макросы, которые генерирует компилятор. Для связи с версией, которая использует среду отладки, вам нужно иметь _DEBUG
определены. Это автоматически определяется ключами компилятора /MD и /MDd, так что все должно быть в порядке, но в описании вашей проблемы предлагается иное.
Откуда вы взяли готовые двоичные файлы? Вы явно выбираете библиотеку в настройках своего проекта или позволяете механизму автоматической ссылки выбрать соответствующий файл.lib?
Это классическая ошибка ссылки. Похоже, что вы ссылаетесь на 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 в прошлом. Насколько я понимаю, это происходит потому, что заголовки Boost используют инструкцию препроцессора для связи с соответствующей библиотекой. Если ваши библиотеки отладки и выпуска находятся в одной и той же папке и имеют разные имена, функция автоматической ссылки не будет работать должным образом.
Что я сделал, так это определил BOOST_ALL_NO_LIB для моего проекта (что не позволяет заголовкам "автоматически связывать"), а затем использовал настройки проекта VC для связи с правильными библиотеками.
Похоже, что другие люди ответили на 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++, которые, как вы знаете, вам не нужны. Я использовал это в прошлом без проблем, но я не уверен, что это всегда будет работать... может быть, кто-то выйдет из работы по дереву и расскажет мне, как это "решение" может заставить вашу программу есть детей во вторник после обеда,
Из памяти различным частям библиотек boost необходимо определить некоторые флаги препроцессора для правильной компиляции. Вещи как BOOST_THREAD_USE_DLL
и так далее.
BOOST_THREAD_USE_DLL
не будет причиной этой конкретной ошибки, но может ожидать, что вы определите _DEBUG
или что-то типа того. Я помню несколько лет назад в наших проектах над C++, у нас было довольно много BOOST_XYZ
определения препроцессора, объявленные в опциях компилятора Visual Studio (или makefile)
Проверить config.hpp
файл в каталоге ветки Boost. Когда вы тянете в ptime
вещи это, возможно, в том числе другой config.hpp
файл, который может затем определить эти вещи препроцессора по-разному.
Теперь это стало даже немного интереснее... Если я просто добавлю это где-нибудь в источнике:
boost::posix_time::ptime pt = boost::posix_time::microsec_clock::universal_time();
(вместе с соответствующими #include
вещи), то опять работает нормально. Так что это одно быстрое и даже не слишком грязное решение, но эй - что здесь происходит, правда?