在MS Visual C上链接到protobuf 3时出错

问题描述 投票:5回答:1

在Visual Studio 2013上遇到,但它可以与任何版本重现。

我从github克隆了协议缓冲库,在它上面运行了CMake-gui(我将所有内容都保留为默认值,因此它是静态版本),只构建libprotobuf(其他项目由于某种原因失败,cmd.exe错误,可能有事情要做有测试,但libprotobuf构建良好)。

我的项目使用在mapbox矢量tile规范的github上找到的.proto文件生成的标题。

当我链接时,我首先有这个错误

Error 1 error C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators' s:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility

我尝试在其他命令行参数中使用-D_SCL_SECURE_NO_WARNINGS禁用它,但后来我有其他错误:

Error 1 error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug' in main.obj S:\eiogit3\misc-projs\mapload\mapload\libprotobufd.lib(common.obj)

c++ visual-studio visual-c++ visual-studio-2013 protocol-buffers
1个回答
9
投票

这与您的项目和libprotobuf项目如何使用VStudio C(和C ++)运行时库(VCRTLib - check [SO]: How to circumvent Windows Universal CRT headers dependency on vcruntime.h (@CristiFati's answer))不匹配。让我详细说明:

假设有一些C(C ++)代码。该代码的目的是运行。比可以实现:

  • 直接:在VC应用程序类型项目中包含该代码 - 这将生成.exe
  • 间接地:将代码包含在VC库类型项目中 - 这将生成一个只能在从另一个.exe(调用该库)调用时才能运行的库。该库可以是: static:所有C(C ++)代码都将被编译并存储在.lib文件中。在链接时,在另一个项目(无论是应用程序还是库)中使用库时,您将需要该文件。请注意,.lib中所有需要的代码将被“复制”到另一个项目中 动态:你现在将有2个文件:一个.dll文件,它将包含已编译(和链接)的代码,一个.lib文件1将包含“指针”(如果你愿意)到.dll文件中的代码。在另一个项目中使用库时,您还需要链接时的.lib文件,但现在它不会包含代码,因此不会在其他库中复制(其他库会更小),但是在运行时,其他库将需要.dll文件

您可以查看[SO]: LNK2005 Error in CLR Windows Form (@CristiFati's answer)以获取有关如何以可执行格式转换C(C ++)代码的详细信息。 Google还有很多关于静态库和动态库之间差异的文章,何时使用其中一个,可以在[SO]: When to use dynamic vs. static libraries上找到一个例子。

正如您所猜测的那样,CRT或C运行时库(包含使C代码能够运行的底层系统 - 一个例子是内存管理函数:malloc,free)也不例外 - 它相当于Nix的libc.a(静态或存档)与libc.so(动态或共享对象) - 但在VStudio中它有点复杂:

  • 静态CRT驻留在libcmt.lib中
  • 动态CRT驻留在msvcrt.lib中,它“指向”msvcr ###。dll2(适用于VStudio 2013的msvcr120.dll)

笔记:

  • 库名(msvcrd.lib)末尾的“d”表示它是使用调试符号编译的
  • C ++运行时库是在确切的情况下;名称有一个额外的p:libcpmt.lib,msvcprt.lib,msvcp120.dll
  • 有关更多详细信息,请查看[MS.Docs]: CRT Library Features

现在,VCRTLib部件不像任何其他lib一样包含在项目中(项目属性 - >链接器 - >输入 - >附加依赖项),但由于在编译时需要它们的性质(静态或动态),因此它们的配置来自:[MS.Docs]: /MD, /MT, /LD (Use Run-Time Library) ,有4种可供选择:

  1. 多线程(/ MT)
  2. 多线程调试(/ MTd)
  3. 多线程DLL(/ MD)
  4. 多线程调试DLL(/ MDd)

显然,包含“Debug”的是在构建Debug配置时,而其他包含Release;关键点是拥有DLL的是使用动态运行时版本,而其他版本是静态版本。

回到你的错误:链接器抱怨main.obj(项目的一部分)有MDd_DynamicDebug(链接动态调试版本),而common.obj(libprotobuf项目的一部分)有MTd_StaticDebug(链接静态调试版本),所以你在同一个可执行文件(或.dll)中链接2个运行时 - 这是不可能的。

为了解决这个问题,你应该确保libprotobuf和你的主项目都具有相同的VCRTLib值。 当然,更改主项目设置以匹配libprotobuf更简单,但建议使用动态运行时版本(在涉及.dll的大型项目中,事情会变得混乱),即使这需要重新编译libprotobuf(好吧,如果更改)该选项会生成错误,使libprotobuf很难构建,并且您的项目将保持这么简单,您可以使用静态VCRTLib)。

注意:不要误解VCRTLib类型(静态/动态)与构建libprotobuf的方式(此时是静态的,但我确信它也可以构建为动态的)。

@ EDIT0:

在上面的注释中添加一些额外的信息,就像一些注释所要求的那样,它可能对其他用户有用。

关于库(包括libprotobuf)有两个方面,它们完全不相关:

  1. 库类型(它的构建方式):动态/静态
  2. VCRTLib类型(它使用VCRTLib的方式):再次,动态/静态

所以,有4个完全有效的组合:

  1. 使用动态VCRTLib的动态库
  2. 使用静态VCRTLib的动态库
  3. 使用动态VCRTLib的静态库
  4. 静态库使用静态VCRTLib

对于libprotobuf,每个方面都由布尔cmake选项控制:

  1. 库类型:protobuf_BUILD_SHARED_LIBS
  2. VCRTLib类型:protobuf_MSVC_STATIC_RUNTIME

可以通过以下任一方式设置2个标志:

  • cmake的桂
  • cmake cmdline(将它们作为参数传递 - 例如:-Dprotobuf_BUILD_SHARED_LIBS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF

因此,上述4种组合是可能的(至少在v3.5中),但是#2。默认情况下禁用(指定-Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_MSVC_STATIC_RUNTIME=ON将构建将链接到动态VCRTLib的.dll),以避免可能的运行时问题,并启用它需要手动干预。

有关构建说明(通过cmake)的更多详细信息,请检查:[GitHub]: protocolbuffers/protobuf - (master) protobuf/cmake/README.md


1:只有在库导出符号时才会创建.lib文件,因为它没有意义(链接时不需要,并且会创建.dll,但几乎无法使用)

2:对于较新的VStudio版本(从v2015开始),msvcr(t)部分已被vcruntime替换(或者至少这是入口点,因为它被分成较小的逻辑部分(在开头检查URL))

© www.soinside.com 2019 - 2024. All rights reserved.