2008-10-21 58 views
5

我有一个令人讨厌的问题,我可能会以某种方式规避,但另一方面,将更重要的是它的顶部,并明白究竟是什么继续,因为它看起来像这个东西真的留在这里。添加Boost使调试版本依赖于“非D”MSVC运行时DLL

下面是故事:我有一个简单的OpenGL应用程序,它工作正常:在编译,链接或运行它时从未遇到过大问题。现在我决定尝试将一些更密集的计算转移到工作线程中,以便可能使GUI更加响应 - 当然使用Boost.Thread。

总之,如果我在.cpp文件的开头添加下面的代码片段:

#include <boost/thread/thread.hpp> 

void dummyThreadFun() { while (1); }  

boost::thread p(dummyThreadFun); 

,然后我开始变得“​​这个应用程序未能启动,因为MSVCP90.dll未找到”的时候试图启动Debug版本。 (发布模式工作正常。)

现在看着使用Dependency Walker的可执行文件,谁也没有找到这个DLL(这是我预期的),我可以看到我们正在寻找它以便能够调用以下功能:

[email protected][email protected]@[email protected]@SAKXZ 
[email protected][email protected][email protected]@@SA_JXZ 
[email protected][email protected]@[email protected]@SAKXZ 
[email protected][email protected][email protected]@@SA_JXZ 

接下来,我想每一个实例转换的minmax使用宏来代替,但可能找不到给他们的所有引用,因为这并没有帮助。 (我正在使用一些外部库,但是我没有可用的源代码,但即使我能做到这一点 - 我不认为这是真的。)

所以,我的问题 - 我猜 - 是:

  1. 为什么我们寻找一个非调试DLL,即使使用调试版本?
  2. 解决此问题的正确方法是什么?甚至是一个快速和肮脏的?

我曾在Visual Studio 2008的一个非常香草的安装中首次尝试安装此功能包和SP1,但它们都没有帮助。当然也试图重建好几次。

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

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

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


编辑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 +升压1.36.0(仍然pre-built binaries from BoostPro Computing)。

罪魁祸首肯定是Spread lib,我的内部版本不知何故需要一个相当古老的STLPort版本,用于MSVC 6!尽管如此,我仍然觉得这些症状比较有趣。另外,如果你真的能够重现这个问题 - 包括上面的情况1-3,这将非常令人高兴。包很小,它应该包含所有必要的部分。

事实证明,这个问题并没有真正与Boost.Thread有关,因为这个例子现在使用了Boost Filesystem库。此外,它现在抱怨MSVCR90.dll,而不是像以前那样。

回答

2

Boost.Thread为了尽量满足在连接的情况可能与MSVC的所有分歧有不少可能构建的组合。首先,您可以静态链接到Boost.Thread,或者链接到单独的DLL中的Boost.Thread。然后,您可以链接到MSVC运行时的DLL版本或静态库运行时。最后,您可以链接到调试运行时或发布运行时。

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

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

+0

我确实有_DEBUG定义...预构建的二进制文件来自BoostPro Computing(http://www.boostpro.com/products/free),我让自动链接机制完成它的工作。 – Reunanen 2008-10-22 14:26:16

+0

这是最离奇的。我现在很难过。你可以在一个完整的程序中重现问题,你可以发布? – 2008-10-22 14:37:01

+0

现在很难说,但我必须考虑这种可能性。 – Reunanen 2008-10-22 16:00:22

0

现在,这得到了甚至有点更有趣...如果我只是添加此某处来源:(与相应的#include东西一起)

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

,然后再次工作正常。所以这是一个快速,甚至不太肮脏的解决方案,但嘿 - 这里发生了什么,真的吗?

0

从内存Boost库的各个部分需要你,以便能够正确编译定义一些预处理标志。东西像BOOST_THREAD_USE_DLL等。

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

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

1

这是一个经典的链接错误。它看起来像你自己链接到错误的C++运行时(this page,做一个“线程”的文本搜索)的linking to a Boost DLL。它也看起来像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++运行库链接。

既然你已经应用了功能包,我想下一步我想借此将手工编译升压。这是我一直采用的路径,非常简单:download the BJam binary,并在库源代码中运行Boost Build脚本。而已。

1

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

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

1

看起来像其他人已经回答了问题的提振方面。这里有一些关于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版本仍然需要链接到静态库(这在某种程度上d在运行时链接到DLL的所有设置 - 我不知道细节)。注意在所有情况下调试版本都有d后缀。 C运行时使用c中缀,而C++运行时使用cp中缀。看到模式?在任何应用程序中,您只能链接到其中一行中的库。

有时(和你的情况一样),你会发现自己链接到其他人的静态库,它被配置为使用错误版本的C或C++运行时(通过非常恼人的#pragma comment(lib))。你可以通过链接器详细的方式来检测,但它是一个真正的PITA寻找。 “用火箭筒杀死一个啮齿动物”解决方案是使用/nodefaultlib:...链接器设置来排除你知道你不需要的6个C和C++库。我过去没有用过这个问题,但我不积极,它会一直工作......也许有人会从木制作品中告诉我,这个“解决方案”如何导致您的程序在周二下午吃掉婴儿。