【问题标题】:Using Visual Studio 2010, how can one link to a DLL generated by Visual Studio 2008使用 Visual Studio 2010,如何链接到由 Visual Studio 2008 生成的 DLL
【发布时间】:2011-05-09 10:56:03
【问题描述】:

我的问题是:

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

  • 如果不是,为什么看起来是 可以链接到静态库 由VS2008生成。

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

  • 即使我使用 /Z7 编译器 switch,为什么我还需要一个 .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 */

How to link with the correct C Run-Time (CRT) library 说:

一个可重用的库及其所有 用户应该使用相同的 CRT 库 类型,因此是相同的编译器 切换...

如果您确实选择混合 CRT 库, 记住你有两个分开的 CRT 的副本,带有单独的和 不同的州,所以你必须是 小心你尝试做的事情 跨越 CRT 边界。有许多 两个惹麻烦的方法 阴极射线管。这里只是一些:

  • 有两个独立的堆。你不能分配(明确地用新的, 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 low-level IO”的意思。

/MD, /MT, /LD (Use Run-Time Library) 说:

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

没有说所有模块都必须由相同版本的编译器编译。我确实对我的所有模块始终正确地使用 /MD(或 /MDd)。

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

我的测试用例似乎表明与 VS2008 生成的静态库的链接是可行的,但也许我只是走运了?为什么在使用 VS2010 时链接到 VS2008 生成的静态库有效,而链接到 VS2008 生成的 DLL 则无效?

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


那么新的平台工具集选项呢?即使没有 VS2008,VS2010 用户也可以将其更改为 v900 吗?如果是这样,那么我可以告诉人们为我的 Leptonlib-1.67 项目更改该设置。


最后,我在创建库时使用了 /Z7 开关。 /Z7, /Zi, /ZI (Debug Information Format) 的文档指出:

/Z7

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

对于第三方库的分销商,有 没有 .pdb 文件的优势。然而 预编译头文件的 .obj 文件是必需的 在链接阶段和调试。如果只有 在 .pch 目标文件中输入信息(没有代码), 你还必须编译 /Yl(为调试库注入 PCH 参考)。

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

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

参考文献

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

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

我的 Leptonica VS2008 解决方案可在http://www.leptonica.com/source/vs2008-1.67.zip 获得。我的二进制库位于http://leptonica.com/source/leptonica-1.67-win32-lib-include-dirs.zip 的zip 文件中。 Leptonica 的来源是http://www.leptonica.com/source/leptonlib-1.67.tar.gz

【问题讨论】:

    标签: visual-studio-2008 visual-studio-2010 visual-c++ dll linker


    【解决方案1】:

    我遗漏的一点是,当您使用 DLL 时,有 两次 调用链接器,一次用于 DLL,一次用于与 DLL 链接的应用程序。当您使用静态库时,只有一次调用链接器(创建静态库使用 LIB)。

    因此,DLL 链接到 C 运行时库,与链接到该 DLL 的任何应用程序分开。如果这两个 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 处理或分配内存 创建只能使用 API 进行操作/释放。我已经在以下位置发布了一个关于此的问题: http://code.google.com/p/leptonica/issues/detail?id=45

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


    我决定不用担心在没有 PDB 的情况下无法调试 DLL。需要调试 Leptonica 的人将拥有源代码,并且可以构建自己的调试版本的库(从而制作 PDB)。


    我仍然有兴趣了解 VS2010 的所有者是否可以使用 v90 Platform Toolset 选项,即使他们没有安装 VS2008。 (但我越想越怀疑他们能做到。)

    【讨论】:

      【解决方案2】:

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

      解决方案是:

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

      • 为 2010 用户提供 2010 版本的 dll 以链接到。这对每个人来说都是最简单的解决方案,因为使用链接器选项并没有任何乐趣。强迫人们将他们的代码定位到旧的运行时以便他们可以使用您的库会使生活变得不可能(一旦他们想使用另一个做同样事情的库,他们就会陷入困境)。好的库是合规且易于使用的,而不是规定性的和困难的。

      至于 pdb:编译和链接是两个不同的过程,它们通过管道连接在一起。如果您更改编译设置,您可能需要以兼容的方式更改链接设置,然后才能正确设置整个管道。

      【讨论】:

        【解决方案3】:

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

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

        我正在使用使用 leptonica 的 tesseract OCR 库。为了避免 DLL 依赖,我也将所有内容都与静态 CRT 进行了静态链接。它最终成为一个 DLL,我从中公开了一些函数。

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

        【讨论】:

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

        我认为可以轻松使用 .dll。如果它们具有相同的 .Net 运行时。 如果没有机会重新编译.dll,那就另当别论了。

        【讨论】:

          猜你喜欢
          • 2012-06-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-01
          • 1970-01-01
          • 2011-07-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多