T P*_*ers 12 dll linker visual-studio-2010 visual-studio-2008 visual-c++
我的问题是:
是否可以使用VS2010链接到VS2008生成的DLL?
如果没有,为什么似乎可以链接到VS2008生成的静态库.
我看到VS2010现在有一个Platform Toolset选项.但是,即使他们没有安装VS2008,人们会将它设置为v90而不是v100吗?
即使我使用/ 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 */
Run Code Online (Sandbox Code Playgroud)
不久之后,在leptonlib.dll中完成以下操作,崩溃:
rewind(fp); /* in leptonlib.dll */
Run Code Online (Sandbox Code Playgroud)
可重用的库及其所有用户应使用相同的CRT库类型,因此编译器切换相同...
如果您确实选择混合使用CRT库,请记住您有两个独立的CRT副本,具有独立且不同的状态,因此您必须小心尝试跨越CRT边界.有两种方法可以解决两个CRT的问题.这里仅仅是少数:
- 有两个单独的堆.您不能分配(显式地使用new,malloc等 - 或者使用strdup,strstreambuf :: str等隐式),然后将指针传递给要释放的CRT边界.
- 您不能跨CRT边界传递FILE*或文件句柄,并期望"stdio低级IO"工作.
- 您不能将语言环境设置为一个,并期望设置另一个语言环境.
从Visual C++ 4.0开始,如果生成的模块尝试组合CRT库的多个副本,链接器将发出警告(LNK4098).有关更多信息,请在LNK4098的帮助文件中搜索.
但我没有从VS2010链接器收到任何LNK4098错误消息.
Leptonica使用fopen(),rewind(),fclose()等文档归类为Stream I/O而不是"低级别IO",但那些传递了FILE ptrs.我想这就是微软在说"stdio低级IO"时的意思.
传递给链接器的给定调用的所有模块必须使用相同的运行时库编译器选项(/ 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二进制文件.
有关如何构建Leptonica库的详细信息,请参见http://leptonica.com/vs2008doc/building-leptonlib.html和http://leptonica.com/vs2008doc/building-image-libraries.html.http://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
我缺少的是当你使用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句柄或分配的内存只能使用API进行操作/释放.我在以下网址发布了一个相关问题:http: //code.google.com/p/leptonica/issues/detail?id = 45
现在我了解问题的原因,我也可能在我的下一个二进制版本中提供了VS2010版本的DLL.
我决定不担心没有PDB就无法调试DLL.需要调试Leptonica的人将拥有源代码并可以构建自己的库调试版本(因此将生成一个PDB).
我仍然有兴趣听听VS2010的所有者是否可以使用v90平台工具集选项,即使他们没有安装VS2008.(但我想的越多,我就越强烈怀疑他们能做到.)
您可以使用 2010 链接到 2008 代码。但是,正如您自己回答的那样,如果您使用一个运行时 (2008) 创建一个对象(例如内存或文件句柄)并将其传递给另一个运行时 (2010) 来销毁它,你会遇到问题 - 这些系统是不同的实例(例如管理它们自己的堆),所以如果你尝试互换使用其中两个系统将无法工作,因为你将把内存块指针传递给一个不知道什么的系统他们是谁或来自哪里。
解决方案是:
确保所有这些调用都发生在一侧或另一侧(因此,如果您的 dll 分配内存,它应该正确封装该进程并提供 API 来释放它)。无论如何,这种内在化都是一个很好的库设计原则。
提供 2010 年版本的 dll 供 2010 年用户链接。这对每个人来说都是最简单的解决方案,因为乱搞链接器选项没有任何乐趣。强迫人们将他们的代码定位到旧的运行时,以便他们可以使用你的库可能会让生活变得不可能(一旦他们想使用另一个做同样事情的库,他们就会陷入困境)。好的库是合规且易于使用的,而不是规定性的且困难的。
至于 pdb:编译和链接是两个不同的过程,通过管道连接在一起。如果更改编译设置,则可能需要在正确设置整个管道之前更改以兼容方式链接的设置。