5

我有一个烦人的问题,我可能能够以某种方式规避它,但另一方面,我宁愿在它之上并了解到底发生了什么,因为看起来这些东西真的会留下来。

故事是这样的:我有一个简单的 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:在尝试构建一个能够重现问题的精简示例时,我发现该问题与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_joinA.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 库,我的构建不知何故需要一个用于MSVC 6的相当古老的 STLPort 版本!尽管如此,我仍然觉得这些症状比较有趣。此外,很高兴听到您是否可以真正重现该问题 - 包括上面的场景 1-3。包装很小,应该包含所有必要的部件。

事实证明,这个问题与 Boost.Thread 没有任何关系,因为这个例子现在使用了 Boost Filesystem 库。此外,它现在抱怨 MSVCR90.dll,而不是以前的 P。

4

6 回答 6

2

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

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

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

于 2008-10-22T14:04:37.290 回答
1

这是一个典型的链接错误。看起来您正在链接到本身链接到错误 C++ 运行时的 Boost DLL(还有这个页面,对“线程”进行文本搜索)。它看起来也像boost::posix::time库链接到正确的 DLL。

不幸的是,我没有找到讨论如何选择正确构建的 Boost DLL 的页面(尽管我确实找到了一封似乎指向和的三年前的电子邮件)。BOOST_THREAD_USE_DLLBOOST_THREAD_USE_LIB


再次查看您的答案,您似乎正在使用预构建的二进制文件。您无法链接到的 DLL 是TR1 功能包的一部分(该页面上的第二个问题)。 该功能包可在 Microsoft 的网站上找到。或者你需要一个不同的二进制文件来链接。显然,该boost::posix::time库链接到未修补的 C++ 运行时。

由于您已经应用了功能包,我认为下一步我将采取手动构建 Boost。这是我一直走的路,而且非常简单: 下载 BJam 二进制文件,然后在库源中运行 Boost Build 脚本。就是这样。

于 2008-10-21T20:44:11.633 回答
1

我相信我过去在使用 Boost 时也遇到过同样的问题。据我了解,这是因为 Boost 标头使用预处理器指令链接到正确的库。如果您的调试和发布库在同一个文件夹中并且具有不同的名称,“自动链接”功能将无法正常工作。

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

于 2008-10-22T14:39:53.303 回答
1

看起来其他人已经回答了问题的 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++ 库。我过去使用过这个没有问题,但我不肯定它会一直有效......也许有人会从木制品中走出来告诉我这个“解决方案”如何导致你的程序在周二下午吃掉婴儿.

于 2008-10-23T01:02:40.457 回答
0

现在这变得更有趣了......如果我只是在源代码的某个地方添加它:

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

(连同相应的#include东西),然后它又可以正常工作了。所以这是一个快速且不太脏的解决方案,但是,嘿 - 这里发生了什么,真的吗?

于 2008-10-21T17:53:38.793 回答
0

从内存中,boost 库的各个部分需要您定义一些预处理器标志才能正确编译。之类的东西BOOST_THREAD_USE_DLL

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

检查config.hppboost 线程目录中的文件。当你拉入这些ptime东西时,它可能包含一个不同的config.hpp文件,然后它可能会以不同的方式定义这些预处理器的东西。

于 2008-10-21T20:27:46.707 回答