问题 使用Visual Studio 2010,如何链接到Visual Studio 2008生成的DLL


我的问题是:

  • 是否可以链接到VS2008 使用VS2010生成DLL?

  • 如果没有,为什么它似乎是 可以链接到静态库 由VS2008生成。

  • 我看到VS2010现在有一个平台 工具集选项。但那会让 人们把它设置为v90而不是v100 即使他们没有VS2008 安装?

  • 即使我使用/ Z7编译器 开关,为什么我还需要一个 .pdb来调试DLL。

细节

我可以使用Visual Studio 2010链接到Visual Studio 2008生成的Leptonica C静态库,没有任何问题。 (见 参考 以下部分详细介绍了如何构建Leptonica并链接到它。)

但是,当我尝试将同一程序(leptonlib-1.67 \ prog \ ioformats_reg.c)与我的VS2008生成的Leptonica DLL版本链接时程序崩溃。调试,我可以看到问题是ioformats_reg.c这样做:

fp = fopen(filename, "rb"); /* in ioformats_reg.c */

不久之后,在leptonlib.dll中完成以下操作,崩溃:

rewind(fp);                 /* in leptonlib.dll */

如何链接到正确的C运行时(CRT)库  说:

一个可重用的库和它的所有   用户应使用相同的CRT库   类型,因此相同的编译器   开关...

如果你确实选择混合CRT库,   记住你有两个独立的   CRT的副本,单独和   不同的状态,所以你一定是   小心你尝试做什么   横跨CRT边界。有许多   如何解决两个人的麻烦   CRT显示器。这里仅仅是少数:

  • 有两个单独的堆。你不能分配(明确地用new,   malloc,或者其他 - 或者隐式地使用   strdup,strstreambuf :: str等),   然后将指针传递给   CRT边界被释放。
  • 您无法跨CRT边界传递FILE *或文件句柄   期待“stdio低级别IO”   工作。
  • 您不能将语言环境设置为一个,并期望设置另一个语言环境。

从Visual C ++ 4.0开始,   链接器将发出警告(LNK4098)   如果结果模块尝试   合并多个CRT副本   图书馆。有关更多信息,请搜索   LNK4098的帮助文件。

但是我愿意  从VS2010链接器获取任何LNK4098错误消息。

Leptonica使用fopen(),rewind(),fclose()等文档归类为Stream I / O而不是“低级别IO”,但是它们会传递给FILE ptrs。我想这就是微软在说“stdio低级IO”时的意思。

/ MD,/ MT,/ LD(使用运行时库) 说:

所有模块都传递给给定的调用   链接器必须使用相同的运行时编译   库编译器选项(/ MD,/ MT,/ LD)。

 说所有模块都必须由相同版本的编译器编译。我对所有模块都使用/ MD(或/ MDd)一致且正确。

当使用DLL时,似乎DLL不仅必须使用相同的/ MD开关,而且它们也必须由VS2010编译?

我的测试用例似乎表明与VS2008生成的静态库链接有效,但也许我很幸运?为什么链接到VS2008生成的静态库工作,而链接到VS2008生成的DLL时不使用VS2010?

这是否意味着我需要运送单独的DLL供VS2008和VS2010用户使用?


那么新的Platform Toolset选项呢? VS2010用户可以将其更改为v900,即使他们没有VS2008吗?如果是这样,那么我可以告诉人们改变我的Leptonlib-1.67项目的设置。


最后,在创建库时使用/ Z7开关。文档在 / Z7,/ Zi,/ ZI(调试信息格式) 状态:

/ Z7

生成包含完整符号的.obj文件   用于调试器的调试信息。   符号调试信息包括名称   和变量的类型,以及函数和行   数字。没有生成.pdb文件。

对于第三方图书馆的经销商,有   没有.pdb文件的优点。但是,那   预编译头文件的.obj文件是必需的   在链接阶段,和调试。如果只有   .pch对象文件中的类型信息(和无代码),   你还需要编译   / Yl(为调试库注入PCH参考)。

我没有使用任何预编译的头文件。但是,只有当我有.pdb可用时才可以调试我的Leptonica DLL。即使它说“没有生成.pdb文件”。事实上,.pdb是使用我当前的项目设置生成的。在编译时,我的链接器选项中的/ PDB是否以某种方式覆盖指定的/ Z7?

编辑:我也应该提一下 上午 能够调试Leptonica的静态库版本,即使没有任何PDB。

参考

Leptonica是Dan Bloomberg提供的开源C图像处理库 http://www.leptonica.com。我提供了使用VS2008 / VS2010构建Leptonica的说明,并提供了Windows二进制文件。

看到 http://leptonica.com/vs2008doc/building-leptonlib.html 和 http://leptonica.com/vs2008doc/building-image-libraries.html 有关如何构建Leptonica库的详细信息。 http://www.leptonica.org/vs2008doc/building-prog-dir.html 讨论我如何链接ioformats_reg。

我的Leptonica VS2008解决方案现已上市 http://www.leptonica.com/source/vs2008-1.67.zip。我的二进制库在zip文件中 http://leptonica.com/source/leptonica-1.67-win32-lib-include-dirs.zip。 Leptonica的消息来源是 http://www.leptonica.com/source/leptonlib-1.67.tar.gz


12905
2017-11-13 07:06


起源



答案:


我缺少的是当你使用DLL时  链接器的调用,一次用于DLL,一次用于与DLL链接的应用程序。使用静态库时,只有一个链接器调用(创建静态库使用LIB)。

因此,DLL与任何与该DLL链接的应用程序分开链接到C运行时库。如果这两个C运行时不同,则会出现问题。

我可以使用VS2010调试器来查看通过Debug - > Windows - > Modules窗口加载的模块。当我链接Leptonica静态库时,我看到msvcrt.dll和msvcr100d.dll。但是,当我与Leptonica leptonlibd.dll链接时,我可以看到msvcrt.dll,msvcr90d.dll和msvcr100d.dll。

运行“dumpbin / imports leptonlibd.dll”也会显示对msvcr90d.dll的引用。

我想说这个问题有3个解决方案:

  • 人们可以静静地与Leptonica联系以完全避免这个问题。

  • 供应VS2008和VS2010版本的leptonlib.dll。

  • 更改leptonica API,以便任何FILE处理或分配内存 create只能使用API​​进行操作/释放。我在以下网址发布了一个问题: http://code.google.com/p/leptonica/issues/detail?id=45

现在我了解问题的原因,我也可能在我的下一个二进制版本中提供了VS2010版本的DLL。


我决定不担心没有PDB就无法调试DLL。需要调试Leptonica的人将拥有源并可以构建自己的库调试版本(因此将生成PDB)。


我仍然有兴趣听听VS2010的所有者是否可以使用v90平台工具集选项,即使他们没有安装VS2008。 (但我想的越多,我就越强烈怀疑他们能做到。)


7
2017-11-14 18:42





您可以使用2010链接到2008代码。但是,正如您自己回答的那样,如果使用一个运行时(2008)创建对象(例如内存或文件句柄)并将其传递给另一个运行时(2010)以将其销毁,你会遇到问题 - 这些系统是不同的实例(例如管理它们自己的堆),所以如果你试图互换使用其中两个就行不通,因为你要将内存块指针传递给一个不知道是什么的系统他们是或来自哪里。

解决方案是:

  • 确保所有这些调用都发生在一方或另一方(因此,如果你的dll分配内存,它应该正确封装该进程并提供API来解除分配它)。无论如何,这种内化是一个很好的图书馆设计原则。

  • 为2010用户提供2010年版本的dll链接。对于每个人来说,这是最简单的解决方案,因为链接器选项的存在并不是很有趣。强迫人们将他们的代码定位到一个旧的运行时只是为了让他们可以使用你的库可能会让生活变得不可能(一旦他们想要使用另一个做同样事情的库,他们就会被卡住)。好的库兼容且易于使用,而不是规定性和困难。

至于pdb:编译和链接是两个流水线化的不同进程。如果更改了编译设置,则可能需要在正确设置整个管道之前以兼容方式更改链接设置。


3
2017-11-13 08:58





很抱歉发布问题作为答案,但......

我有同样的问题,除了Visual Studio 2010中的一切!

我正在使用使用leptonica的tesseract OCR库。为了避免DLL依赖,我还静态地将所有内容与静态CRT相关联。它最终成为一个DLL,我从中暴露了一些函数。

当我链接并构建一个测试程序时,我可以单步执行代码并看到tesseract调用fopen()的部分可以工作,但是当它从leptonica代码中调用时,它会崩溃!


1
2017-11-19 19:42



静态链接(通常是好的)与链接到静态CRT(通常是坏的)不同。我提供的Leptonica二进制文件都是用/ MD(或/ MDd)开关编译的。除非你自己重新编译了所有的图像库和Leptonica,否则你应该这样做 也 在构建DLL时使用/ MD开关而不是/ MT开关。 (链接器应该抱怨混合两种不同的CRT) - T Powers
我需要每个依赖项都在一个单独的编译DLL中,所以我可以通过extern“C”API从任何语言/平台使用它。 leptonica我用静态CRT重新编译,因此也是tesseract。换句话说,所有相关的依赖项都是“多线程调试”和“多线程”w.r.t.运行时库选项。这个想法是最终的DLL不应该依赖于任何MSVC * .DLL - rep_movsd
嗯。在VS2010调试器中,当从tesseract调用fopen()与来自Leptonica的调用崩溃时,调用堆栈窗口中的CRT名称是什么?模块窗口中加载了哪些CRT模块? Leptonica v1.68将解决 我的 原始问题......你可能要等到它并且tesseract-ocr v3.01出来并看看问题是否仍然存在。如果是这样,请在 code.google.com/p/leptonica/issues/list 和 code.google.com/p/tesseract-ocr/issues/list 详细信息。我也有兴趣确保tesseract-ocr使用Leptonica(至少在Windows XP上)。 - T Powers


答案:


我缺少的是当你使用DLL时  链接器的调用,一次用于DLL,一次用于与DLL链接的应用程序。使用静态库时,只有一个链接器调用(创建静态库使用LIB)。

因此,DLL与任何与该DLL链接的应用程序分开链接到C运行时库。如果这两个C运行时不同,则会出现问题。

我可以使用VS2010调试器来查看通过Debug - > Windows - > Modules窗口加载的模块。当我链接Leptonica静态库时,我看到msvcrt.dll和msvcr100d.dll。但是,当我与Leptonica leptonlibd.dll链接时,我可以看到msvcrt.dll,msvcr90d.dll和msvcr100d.dll。

运行“dumpbin / imports leptonlibd.dll”也会显示对msvcr90d.dll的引用。

我想说这个问题有3个解决方案:

  • 人们可以静静地与Leptonica联系以完全避免这个问题。

  • 供应VS2008和VS2010版本的leptonlib.dll。

  • 更改leptonica API,以便任何FILE处理或分配内存 create只能使用API​​进行操作/释放。我在以下网址发布了一个问题: http://code.google.com/p/leptonica/issues/detail?id=45

现在我了解问题的原因,我也可能在我的下一个二进制版本中提供了VS2010版本的DLL。


我决定不担心没有PDB就无法调试DLL。需要调试Leptonica的人将拥有源并可以构建自己的库调试版本(因此将生成PDB)。


我仍然有兴趣听听VS2010的所有者是否可以使用v90平台工具集选项,即使他们没有安装VS2008。 (但我想的越多,我就越强烈怀疑他们能做到。)


7
2017-11-14 18:42





您可以使用2010链接到2008代码。但是,正如您自己回答的那样,如果使用一个运行时(2008)创建对象(例如内存或文件句柄)并将其传递给另一个运行时(2010)以将其销毁,你会遇到问题 - 这些系统是不同的实例(例如管理它们自己的堆),所以如果你试图互换使用其中两个就行不通,因为你要将内存块指针传递给一个不知道是什么的系统他们是或来自哪里。

解决方案是:

  • 确保所有这些调用都发生在一方或另一方(因此,如果你的dll分配内存,它应该正确封装该进程并提供API来解除分配它)。无论如何,这种内化是一个很好的图书馆设计原则。

  • 为2010用户提供2010年版本的dll链接。对于每个人来说,这是最简单的解决方案,因为链接器选项的存在并不是很有趣。强迫人们将他们的代码定位到一个旧的运行时只是为了让他们可以使用你的库可能会让生活变得不可能(一旦他们想要使用另一个做同样事情的库,他们就会被卡住)。好的库兼容且易于使用,而不是规定性和困难。

至于pdb:编译和链接是两个流水线化的不同进程。如果更改了编译设置,则可能需要在正确设置整个管道之前以兼容方式更改链接设置。


3
2017-11-13 08:58





很抱歉发布问题作为答案,但......

我有同样的问题,除了Visual Studio 2010中的一切!

我正在使用使用leptonica的tesseract OCR库。为了避免DLL依赖,我还静态地将所有内容与静态CRT相关联。它最终成为一个DLL,我从中暴露了一些函数。

当我链接并构建一个测试程序时,我可以单步执行代码并看到tesseract调用fopen()的部分可以工作,但是当它从leptonica代码中调用时,它会崩溃!


1
2017-11-19 19:42



静态链接(通常是好的)与链接到静态CRT(通常是坏的)不同。我提供的Leptonica二进制文件都是用/ MD(或/ MDd)开关编译的。除非你自己重新编译了所有的图像库和Leptonica,否则你应该这样做 也 在构建DLL时使用/ MD开关而不是/ MT开关。 (链接器应该抱怨混合两种不同的CRT) - T Powers
我需要每个依赖项都在一个单独的编译DLL中,所以我可以通过extern“C”API从任何语言/平台使用它。 leptonica我用静态CRT重新编译,因此也是tesseract。换句话说,所有相关的依赖项都是“多线程调试”和“多线程”w.r.t.运行时库选项。这个想法是最终的DLL不应该依赖于任何MSVC * .DLL - rep_movsd
嗯。在VS2010调试器中,当从tesseract调用fopen()与来自Leptonica的调用崩溃时,调用堆栈窗口中的CRT名称是什么?模块窗口中加载了哪些CRT模块? Leptonica v1.68将解决 我的 原始问题......你可能要等到它并且tesseract-ocr v3.01出来并看看问题是否仍然存在。如果是这样,请在 code.google.com/p/leptonica/issues/list 和 code.google.com/p/tesseract-ocr/issues/list 详细信息。我也有兴趣确保tesseract-ocr使用Leptonica(至少在Windows XP上)。 - T Powers


我认为可以轻松使用.dll。如果它们具有相同的.Net运行时。 如果您没有机会重新编译.dll,那么这是另一个故事。


0
2018-02-17 13:59



这是本机代码 - 不涉及.NET。 - LThode