我有一个恼人的问题,我也许能够以某种方式规避它,但另一方面,我更愿意解决它并了解到底发生了什么,因为看起来这个东西真的会留下来。

故事是这样的:我有一个简单的 OpenGL 应用程序,运行良好:在编译、链接或运行它时从来都不是一个大问题。现在,我决定尝试将一些更密集的计算转移到工作线程中,以便可能使 GUI 的响应速度更快——当然是使用 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

接下来,我尝试转换每个实例 minmax 使用宏来代替,但可能找不到对它们的所有引用,因为这没有帮助。(我正在使用一些外部库,但我没有可用的源代码。但即使我能做到这一点——我也不认为这真的是正确的方式。)

所以,我想我的问题是:

  1. 即使使用调试版本,为什么我们还要寻找非调试 DLL?
  2. 解决问题的正确方法是什么?或者甚至是一种快速而肮脏的方式?

我首先在 Visual Studio 2008 的普通安装中遇到了这个问题。然后尝试安装Feature Pack和SP1,但它们也没有帮助。当然也尝试过Rebuild几次。

我正在使用预构建的二进制文件进行 Boost (v1.36.0)。这不是我第一次在这个项目中使用 Boost,但这可能是我第一次使用基于单独来源的部件。

禁用增量链接没有帮助。该程序是 OpenGL 的事实似乎也无关紧要——当我将相同的三行代码添加到一个简单的控制台程序中时,我遇到了类似的问题(但它抱怨 MSVCR90.dll 和 _mkdir, ,当我将后者替换为 boost::create_directory, ,问题就消失了!!)。实际上,只需删除或添加这三行即可使程序正常运行或根本不运行。

我不能说我理解并排(甚至不知道这是否相关,但这就是我现在的假设),说实话,我也不是超级感兴趣 - 只要我能构建、调试和部署我的应用程序...


编辑1: 在尝试构建一个无论如何都能重现该问题的精简示例时,我发现该问题与 传播工具包, ,它的使用是我所有遇到此问题的程序的共同因素。(但是,在开始链接 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 的答案的一部分,因为我的系统中没有该库的调试版本。

目前,我正在尝试想出一些方法,可以在另一个环境中重现该问题。(尽管如果它实际上可以在我的场所之外重复,我会感到非常惊讶......)


编辑2: 好吧,那么 这里 我们现在有了一个包,我可以使用它在几乎普通的 WinXP32 + VS2008 + Boost 1.36.0 安装上重现该问题(仍然是 来自 BoostPro 计算的预构建二进制文件).

罪魁祸首肯定是 Spread 库,我的构建不知何故需要一个相当古老的 STLPort 版本 MSVC 6!尽管如此,我仍然觉得这些症状比较有趣。另外,如果您能真正重现该问题(包括上面的场景 1-3),那就太好了。包装很小,应该包含所有必需的部件。

事实证明,该问题实际上与 Boost.Thread 没有任何关系,因为此示例现在使用 Boost Filesystem 库。此外,它现在抱怨 MSVCR90.dll,而不是像以前那样抱怨 P。

有帮助吗?

解决方案

Boost.Thread有很多可能的构建组合,以尝试和满足MSVC可能的链接方案的所有差异。首先,您可以静态链接到Boost.Thread,也可以链接到单独的DLL中的Boost.Thread。然后,您可以链接到MSVC运行时的DLL版本或静态库运行时。最后,您可以链接到调试运行时或发布运行时。

Boost.Thread标头尝试使用编译器生成的预定义宏自动检测构建方案。为了链接使用调试运行时的版本,您需要定义 _DEBUG 。这是由/ MD和/ MDd编译器开关自动定义的,所以它应该没问题,但是你的问题描述也是如此。

你从哪里获得预先建立的二进制文件?您是在项目设置中明确选择库,还是让自动链接机制选择适当的.lib文件?

其他提示

我相信我过去曾遇到过与Boost相同的问题。根据我的理解,它发生是因为Boost头使用预处理器指令链接到正确的lib。如果您的调试和发布库位于同一文件夹中并且具有不同的名称,则“自动链接”将显示在同一文件夹中。功能无法正常工作。

我所做的是为我的项目定义BOOST_ALL_NO_LIB(这会阻止标题“自动链接”),然后使用VC项目设置链接到正确的库。

看起来其他人已经回答了问题的升压方面。这里有一些关于 MSVC 方面的背景信息,这可能会避免进一步的麻烦。

C(和 C++)运行时有 4 个版本:

  • /公吨:libcmt.lib (C)、libcpmt.lib (C++)
  • /MTd:libcmtd.lib、libcpmtd.lib
  • /医学博士:msvcrt.lib、msvcrt.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 东西),然后再次正常工作。所以这是一个快速,甚至不太脏的解决方案,但嘿&#8212;这是怎么回事,真的吗?

从内存中,boost库的各个部分需要您定义一些预处理程序标志,以便能够正确编译。像 BOOST_THREAD_USE_DLL 等等。

BOOST_THREAD_USE_DLL 不会导致此特定错误,但可能需要您定义 _DEBUG 或类似的东西。我记得几年前在我们的boost C ++项目中,我们在visual studio编译器选项(或makefile)中声明了很多额外的 BOOST_XYZ 预处理器定义

检查boost thread目录中的 config.hpp 文件。当您输入 ptime 时,它可能包含一个不同的 config.hpp 文件,然后可能以不同的方式定义这些预处理器。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top