添加Boost使得调试构建依赖于“非D” MSVC 运行时 DLL
我有一个恼人的问题,我也许能够以某种方式规避它,但另一方面,我更愿意解决它并了解到底发生了什么,因为看起来这个东西真的会留下来。
故事是这样的:我有一个简单的 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
接下来,我尝试将 min
和 max
的每个实例转换为使用宏,但可能找不到对它们的所有引用,因为这没有帮助。 (我正在使用一些外部库,但我没有可用的源代码。但即使我可以做到这一点 - 我认为这确实不是正确的方法。)
所以,我想我的问题是:
- 即使使用调试版本,为什么我们还要寻找非调试 DLL?
- 解决问题的正确方法是什么? 或者甚至是一种快速而肮脏的方式?
我首先在 Visual Studio 2008 的普通安装中遇到了这个问题。然后尝试安装功能包和 SP1,但它们也没有帮助。 当然也尝试过Rebuild几次。
我正在使用预构建的二进制文件进行 Boost (v1.36.0)。 这不是我第一次在这个项目中使用 Boost,但这可能是我第一次使用基于单独来源的部件。
禁用增量链接没有帮助。 该程序是 OpenGL 的事实似乎也不相关——当我将相同的三行代码添加到一个简单的控制台程序中时,我遇到了类似的问题(但它抱怨 MSVCR90.dll 和 _mkdir< /code>,当我用
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>
一些观察:
- 如果我注释掉 A.cpp 的
SP_join
行,问题就会消失。 - 如果我注释掉 B.cpp 的单行,问题就会消失。
- 如果我将 B.cpp 的单行移动或复制到 A.cpp 的开头或结尾,问题就会消失。
(在场景2和3中,程序在调用SP_join
时崩溃,但这只是因为邮箱无效......这与当前问题无关。)
此外,Spread的核心库已链接进来,这肯定是我的问题#1 的答案的一部分,因为我的系统中没有该库的调试版本。
目前,我正在尝试想出一些方法,可以在另一个环境中重现该问题。 (尽管如果它实际上可以在我的场所之外重复,我会感到非常惊讶......)
编辑2:好的,所以这里我们现在有一个包,使用它我能够在 WinXP32 + VS2008 + Boost 1.36.0 的几乎普通安装上重现该问题(仍然来自 BoostPro 计算的预构建二进制文件)。
罪魁祸首肯定是 Spread 库,我的构建不知何故需要一个相当古老的 MSVC 6 版本的 STLPort! 尽管如此,我仍然觉得这些症状比较有趣。 另外,如果您能真正重现该问题(包括上面的场景 1-3),那就太好了。 包装很小,应该包含所有必需的部件。
事实证明,这个问题实际上与 Boost.Thread 没有任何关系,因为此示例现在使用 Boost Filesystem 库。 此外,它现在抱怨 MSVCR90.dll,而不是像以前那样抱怨 P。
I have an annoying problem which I might be able to somehow circumvent, but on the other hand would much rather be on top of it and understand what exactly is going on, since it looks like this stuff is really here to stay.
Here's the story: I have a simple OpenGL app which works fine: never a major problem in compiling, linking, or running it. Now I decided to try to move some of the more intensive calculations into a worker thread, in order to possibly make the GUI even more responsive — using Boost.Thread, of course.
In short, if I add the following fragment in the beginning of my .cpp file:
#include <boost/thread/thread.hpp>
void dummyThreadFun() { while (1); }
boost::thread p(dummyThreadFun);
, then I start getting "This application has failed to start because MSVCP90.dll was not found" when trying to launch the Debug build. (Release mode works ok.)
Now looking at the executable using the Dependency Walker, who also does not find this DLL (which is expected I guess), I could see that we are looking for it in order to be able to call the following functions:
?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
Next, I tried to convert every instance of min
and max
to use macros instead, but probably couldn't find all references to them, as this did not help. (I'm using some external libraries for which I don't have the source code available. But even if I could do this — I don't think it's the right way really.)
So, my questions — I guess — are:
- Why do we look for a non-debug DLL even though working with the debug build?
- What is the correct way to fix the problem? Or even a quick-and-dirty one?
I had this first in a pretty much vanilla installation of Visual Studio 2008. Then tried installing the Feature Pack and SP1, but they didn't help either. Of course also tried to Rebuild several times.
I am using prebuilt binaries for Boost (v1.36.0). This is not the first time I use Boost in this project, but it may be the first time that I use a part that is based on a separate source.
Disabling incremental linking doesn't help. The fact that the program is OpenGL doesn't seem to be relevant either — I got a similar issue when adding the same three lines of code into a simple console program (but there it was complaining about MSVCR90.dll and _mkdir
, and when I replaced the latter with boost::create_directory
, the problem went away!!). And it's really just removing or adding those three lines that makes the program run ok, or not run at all, respectively.
I can't say I understand Side-by-Side (don't even know if this is related but that's what I assume for now), and to be honest, I am not super-interested either — as long as I can just build, debug and deploy my app...
Edit 1: While trying to build a stripped-down example that anyway reproduces the problem, I have discovered that the issue has to do with the Spread Toolkit, the use of which is a factor common to all my programs having this problem. (However, I never had this before starting to link in the Boost stuff.)
I have now come up with a minimal program that lets me reproduce the issue. It consists of two compilation units, A.cpp and 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>
Some observations:
- If I comment out the line
SP_join
of A.cpp, the problem goes away. - If I comment out the single line of B.cpp, the problem goes away.
- If I move or copy B.cpp's single line to the beginning or end of A.cpp, the problem goes away.
(In scenarios 2 and 3, the program crashes when calling SP_join
, but that's just because the mailbox is not valid... this has nothing to do with the issue at hand.)
In addition, Spread's core library is linked in, and that's surely part of the answer to my question #1, since there's no debug build of that lib in my system.
Currently, I'm trying to come up with something that'd make it possible to reproduce the issue in another environment. (Even though I will be quite surprised if it actually can be repeated outside my premises...)
Edit 2: Ok, so here we now have a package using which I was able to reproduce the issue on an almost vanilla installation of WinXP32 + VS2008 + Boost 1.36.0 (still pre-built binaries from BoostPro Computing).
The culprit is surely the Spread lib, my build of which somehow requires a rather archaic version of STLPort for MSVC 6! Nevertheless, I still find the symptoms relatively amusing. Also, it would be nice to hear if you can actually reproduce the issue — including scenarios 1-3 above. The package is quite small, and it should contain all the necessary pieces.
As it turns out, the issue did not really have anything to do with Boost.Thread specifically, as this example now uses the Boost Filesystem library. Additionally, it now complains about MSVCR90.dll, not P as previously.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
Boost.Thread 有相当多可能的构建组合,以便尝试满足 MSVC 可能的链接场景中的所有差异。 首先,您可以静态链接到 Boost.Thread,也可以链接到单独的 DLL 中的 Boost.Thread。 然后,您可以链接到 MSVC 运行时的 DLL 版本或静态库运行时。 最后,您可以链接到调试运行时或发布运行时。
Boost.Thread 标头尝试使用编译器生成的预定义宏自动检测构建场景。 为了链接到使用调试运行时的版本,您需要定义
_DEBUG
。 这是由 /MD 和 /MDd 编译器开关自动定义的,因此应该没问题,但您的问题描述表明并非如此。您从哪里获得预构建的二进制文件? 您是否在项目设置中明确选择了一个库,或者是否让自动链接机制选择适当的 .lib 文件?
Boost.Thread has quite a few possible build combinations in order to try and cater for all the differences in linking scenarios possible with MSVC. Firstly, you can either link statically to Boost.Thread, or link to Boost.Thread in a separate DLL. You can then link to the DLL version of the MSVC runtime, or the static library runtime. Finally, you can link to the debug runtime or the release runtime.
The Boost.Thread headers try and auto-detect the build scenario using the predefined macros that the compiler generates. In order to link against the version that uses the debug runtime you need to have
_DEBUG
defined. This is automatically defined by the /MD and /MDd compiler switches, so it should be OK, but your problem description suggests otherwise.Where did you get the pre-built binaries from? Are you explicitly selecting a library in your project settings, or are you letting the auto-link mechanism select the appropriate .lib file?
我相信我过去在使用 Boost 时也遇到过同样的问题。 根据我的理解,发生这种情况是因为 Boost 标头使用预处理器指令来链接正确的库。 如果您的调试库和发布库位于同一文件夹中并且具有不同的名称,则“自动链接”功能将无法正常工作。
我所做的是为我的项目定义 BOOST_ALL_NO_LIB (这可以防止标头“自动链接”),然后使用 VC 项目设置链接正确的库。
I believe I have had this same problem with Boost in the past. From my understanding it happens because the Boost headers use a preprocessor instruction to link against the proper lib. If your debug and release libraries are in the same folder and have different names the "auto-link" feature will not work properly.
What I have done is define BOOST_ALL_NO_LIB for my project(which prevents the headers from "auto linking") and then use the VC project settings to link against the correct libraries.
看起来其他人已经回答了问题的升压方面。 这里有一些关于 MSVC 方面的背景信息,这可能会避免进一步的麻烦。
有 4 个版本的 C(和 C++)运行时:
DLL 版本仍然需要链接到该静态库(它以某种方式完成所有设置以在运行时链接到 DLL - 我不知道详细信息)。 请注意,在所有情况下,调试版本都有
d
后缀。 C 运行时使用c
中缀,C++ 运行时使用cp
中缀。 看到图案了吗? 在任何应用程序中,您应该只链接到这些行之一中的库。有时(如您的情况),您发现自己链接到其他人的静态库,该静态库配置为使用错误版本的 C 或 C++ 运行时(通过非常烦人的
#pragma comment(lib)
) 。 您可以通过提高链接器的详细程度来检测这一点,但它是真正需要寻找的 PITA。 “用火箭筒杀死啮齿动物”的解决方案是使用/nodefaultlib:...
链接器设置来排除 6 个您知道不需要的 C 和 C++ 库。 我过去使用过这个,没有任何问题,但我不确定它总是有效......也许有人会突然告诉我这个“解决方案”如何导致你的程序在周二下午吃掉婴儿。Looks like other people have answered the Boost side of the issue. Here's a bit of background info on the MSVC side of things, that may save further headache.
There are 4 versions of the C (and C++) runtimes possible:
The DLL versions still require linking to that static lib (which somehow does all of the setup to link to the DLL at runtime - I don't know the details). Notice in all cases debug version has the
d
suffix. The C runtime uses thec
infix, and the C++ runtime uses thecp
infix. See the pattern? In any application, you should only ever link to the libraries in one of those rows.Sometimes (as in your case), you find yourself linking to someone else's static library that is configured to use the wrong version of the C or C++ runtimes (via the awfully annoying
#pragma comment(lib)
). You can detect this by turning your linker verbosity way up, but it's a real PITA to hunt for. The "kill a rodent with a bazooka" solution is to use the/nodefaultlib:...
linker setting to rule out the 6 C and C++ libraries that you know you don't need. I've used this in the past without problem, but I'm not positive it'll always work... maybe someone will come out of the woodwork telling me how this "solution" may cause your program to eat babies on Tuesday afternoons.这是一个典型的链接错误。 您似乎链接到 Boost DLL 本身链接到错误的 C++ 运行时(还有 此页面 ,对“线程”进行文本搜索)。 它看起来也像
boost::posix::time
库链接到正确的 DLL。不幸的是,我没有找到讨论如何选择正确构建的 Boost DLL 的页面(尽管我确实找到了 三年前的电子邮件,似乎指向
BOOST_THREAD_USE_DLL
和BOOST_THREAD_USE_LIB
)。再次查看您的答案,您似乎正在使用预构建的二进制文件。 您无法链接到的 DLL 是 TR1 功能包的一部分(该页面上的第二个问题)。 该功能包位于微软的网站。 或者您需要一个不同的二进制文件来链接。 显然,
boost::posix::time
库链接到未打补丁的 C++ 运行时。由于您已经应用了该功能包,我认为下一步我将采取手动构建 Boost。 这是我一直采取的方法,而且非常简单:下载 BJam 二进制文件,并运行库源中的 Boost Build 脚本。 就是这样。
This is a classic link error. It looks like you're linking to a Boost DLL that itself links to the wrong C++ runtime (there's also this page, do a text search for "threads"). It also looks like the
boost::posix::time
library links to the correct DLL.Unfortunately, I'm not finding the page that discusses how to pick the correctly-built Boost DLL (although I did find a three-year-old email that seems to point to
BOOST_THREAD_USE_DLL
andBOOST_THREAD_USE_LIB
).Looking at your answer again, it appears you're using pre-built binaries. The DLL you're not able to link to is part of the TR1 feature pack (second question on that page). That feature pack is available on Microsoft's website. Or you'll need a different binary to link against. Apparently the
boost::posix::time
library links against the unpatched C++ runtime.Since you've already applied the feature pack, I think the next step I would take would be to build Boost by hand. That's the path I've always taken, and it's very simple: download the BJam binary, and run the Boost Build script in the library source. That's it.
现在这变得更有趣了...如果我只是将其添加到源代码中的某个位置:(
与相应的
#include
内容一起),那么它又可以正常工作了。 所以这是一个快速且不太肮脏的解决方案,但是嘿 - 这里到底发生了什么?Now this got even a bit more interesting... If I just add this somewhere in the source:
(together with the corresponding
#include
stuff), then it again works ok. So this is one quick and not even too dirty solution, but hey — what's going on here, really?从内存中看,boost 库的各个部分需要您定义一些预处理器标志,以便能够正确编译。 像
BOOST_THREAD_USE_DLL
之类的东西。BOOST_THREAD_USE_DLL
不会导致此特定错误,但它可能期望您定义_DEBUG
或类似的内容。 我记得几年前,在我们的 boost C++ 项目中,我们在 Visual Studio 编译器选项(或 makefile)中声明了相当多额外的BOOST_XYZ
预处理器定义。检查
config.hpp
boost 线程目录中的文件。 当您提取 ptime 内容时,它可能包含不同的 config.hpp 文件,该文件可能会以不同的方式定义这些预处理器内容。From memory various parts of the boost libraries need you to define some preprocessor flags in order to be able to compile correctly. Stuff like
BOOST_THREAD_USE_DLL
and so on.The
BOOST_THREAD_USE_DLL
won't be what's causing this particular error, but it may be expecting you to define_DEBUG
or something like that. I remember a few years ago in our boost C++ projects we had quite a few extraBOOST_XYZ
preprocessor definitions declared in the visual studio compiler options (or makefile)Check the
config.hpp
file in the boost thread directory. When you pull in theptime
stuff it's possibly including a differentconfig.hpp
file, which may then define those preprocessor things differently.