【问题标题】:Adding Boost makes Debug build depend on "non-D" MSVC runtime DLLs添加 Boost 使 Debug 构建依赖于“非 D”MSVC 运行时 DLL
【发布时间】:2010-09-18 09:02:56
【问题描述】:

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

故事是这样的:我有一个简单的 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 替换后者时,问题就消失了!!)。实际上只是分别删除或添加使程序运行正常或根本不运行的那三行。

我不能说我理解 Side-by-Side(甚至不知道这是否相关,但这是我现在的假设),老实说,我也不是很感兴趣——只要我可以构建、调试和部署我的应用程序...


编辑 1: 在尝试构建一个能够重现问题的精简示例时,我发现问题与 the 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. 如果我注释掉 A.cpp 的 SP_join 行,问题就消失了。
  2. 如果我注释掉 B.cpp 的单行,问题就消失了。
  3. 如果我将 B.cpp 的单行移动或复制到 A.cpp 的开头或结尾,问题就会消失。

(在场景2和场景3中,调用SP_join时程序崩溃,但那只是因为邮箱无效......这与手头的问题无关。)

此外,Spread 的核心库已链接,这肯定是我的问题 #1 答案的一部分,因为我的系统中没有该库的调试版本。

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


编辑 2: 好的,所以here 我们现在有了一个包,我可以使用它在几乎普通的 WinXP32 + VS2008 + Boost 1.36.0 安装上重现该问题(仍然是 @ 987654323@)。

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

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

【问题讨论】:

    标签: c++ visual-studio-2008 dll boost sxs


    【解决方案1】:

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

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

    (连同相应的#include 东西),然后它又可以正常工作了。因此,这是一种快速且不太脏的解决方案,但是,嘿——这是怎么回事,真的吗?

    【讨论】:

      【解决方案2】:

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

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

      检查提升线程目录中的config.hpp 文件。当您拉入 ptime 内容时,它可能包含不同的 config.hpp 文件,然后可能会以不同的方式定义这些预处理器内容。

      【讨论】:

        【解决方案3】:

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

        不幸的是,我没有找到讨论如何选择正确构建的 Boost DLL 的页面(尽管我确实找到了似乎指向 BOOST_THREAD_USE_DLLBOOST_THREAD_USE_LIBthree-year-old email)。


        再次查看您的答案,您似乎正在使用预构建的二进制文件。您无法链接到的 DLL 是 part of the TR1 feature pack(该页面上的第二个问题)。 That feature pack is available on Microsoft's website。或者你需要一个不同的二进制文件来链接。显然,boost::posix::time 库链接到未修补的 C++ 运行时。

        既然您已经应用了功能包,我想下一步我会手动构建 Boost。这就是我一直走的路,而且非常简单:download the BJam binary,然后在库源中运行 Boost Build 脚本。就是这样。

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

          • 我确实定义了 _DEBUG... 预构建的二进制文件来自 BoostPro Computing (boostpro.com/products/free),我让自动链接机制完成它的工作。
          • 这太离奇了。我现在很难过。您能否在可以发布的完整程序中重现该问题?
          • 现在很难说,但我得看看这种可能性。
          • 因为这个问题与我无关,我接受这个答案;毕竟,我想它帮助我走上了正轨。
          【解决方案5】:

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

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

          【讨论】:

          • 我不确定这个答案是否对 OP 有帮助,但它确实对我有帮助。
          【解决方案6】:

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

          【讨论】:

          • 使用 /nodefaultlib 修复链接错误的问题是,一些运行时库结构的定义会根据编译器设置而改变。此外,库可能会根据编译器设置更改 它们的 结构。然后你可能会遇到奇怪的行为。
          猜你喜欢
          • 1970-01-01
          • 2014-01-29
          • 1970-01-01
          • 2010-11-19
          • 2013-03-27
          • 1970-01-01
          • 1970-01-01
          • 2022-01-18
          • 2015-08-28
          相关资源
          最近更新 更多