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

时间:2016-01-31 16:49:01

标签: c++ visual-studio visual-c++ visual-studio-2013 protocol-buffers

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

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

我的项目使用在mapbox矢量图块规范的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)

1 个答案:

答案 0 :(得分:7)

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

让我们说一些 C 代码。该代码的目的是运行。比可以实现:

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

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

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

  • 静态 CRT 位于 libcmt.lib
  • 动态 CRT 位于 msvcrt.lib 中,其中"指向" msvcr ###。dll 2 msvcr120.dll VStudio 2013

备注

  • A" d "在库名称的末尾( msvcr d .lib ),意味着它已使用调试符号进行编译
  • C ++ 运行时库正是在这种情况下;名称有一个额外的 p libc p mt.lib msvc p rt.lib < / em>, msvc p 120.dll
  • 有关详情,请查看[MS.Docs]: CRT Library Features

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

  1. 多线程( / MT
  2. 多线程调试( / MTd
  3. 多线程DLL( / MD
  4. 多线程调试DLL( / MDd
  5. 显然,那些包含&#34; Debug&#34;在构建 Debug 配置时,其他用于 Release ;关键点是 DLL 的那些使用动态运行时版本,而其他版本使用静态版本。

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

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

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

    <强> @ EDIT0

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

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

    1. 图书馆类型(正在构建的方式):动态 / 静态
    2. VCRTLib 类型(它使用 VCRTLib 的方式):再次,动态 / 静态< / em>的
    3. 所以,有4种完全有效的组合:

      1. 使用动态 VCRTLib
      2. 的动态库
      3. 使用静态 VCRTLib
      4. 的动态库
      5. 使用动态 VCRTLib
      6. 的静态库
      7. 使用静态 VCRTLib
      8. 的静态库

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

        1. 图书馆类型: protobuf_BUILD_SHARED_LIBS
        2. VCRTLib 类型: protobuf_MSVC_STATIC_RUNTIME
        3. 可以通过以下任一方式设置2个标志:

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

          以上4种组合因此可能(至少在 v 3.5 中),但 #2。< / em> 默认情况下已停用(指定-Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_MSVC_STATIC_RUNTIME=ON将构建一个 .dll ,它将链接到动态 VCRTLib ),为了避免可能的运行时问题,并启用它需要手动干预。

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


          1 :只有在库导出符号时才会创建 .lib 文件,否则它将无法理解(链接时不需要, .dll 将被创建,但几乎无法使用)

          2 :对于较新的 VStudio 版本(从 2015 开始), msvcr(t) 部分已被 vcruntime 取代(或者至少这是入口点,因为它被分成较小的逻辑部分)