【问题标题】:Errors when linking to protobuf 3 on MS Visual C在 MS Visual C 上链接到 protobuf 3 时出错
【发布时间】:2016-05-09 01:43:57
【问题描述】:

在 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)

【问题讨论】:

  • 那么,您使用 CMake 构建了 libprotobuf 静态版本 (.lib),现在您正尝试将其链接到您的 VStudio 应用程序中?
  • 是的,我使用 MSVC 2013 构建了它,现在将它链接到我的项目,同样使用 MSVC 2013
  • here是项目文件

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


【解决方案1】:

VStudio C(和 C++)运行时库VCRTLibUCRT strong> - 检查 [SO]: How to circumvent Windows Universal CRT headers dependency on vcruntime.h (@CristiFati's answer)) 是否被您的项目和 libprotobuf 项目使用。让我详细说明:

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

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

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

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

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

注意事项

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

现在,UCRT 部分不像任何其他库(Project Properties -> Linker -> Input -> Additional Dependencies)一样包含在项目中,而是因为它们编译时需要自然(静态或动态),它们的配置来自:[MS.Docs]: /MD, /MT, /LD (Use Run-Time Library),其中有 4 种可用选择:

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

显然,包含“Debug”的那些是在构建时用于Debug配置,而其他的用于Release;关键是有DLL的使用dynamic运行时版本,而其他的使用static版本。

回到你的错误:链接器抱怨 main.obj(你项目的一部分)有 MDd_DynamicDebug(链接到 dynamic debug 版本),而 common.objlibprotobuf 项目的一部分)有 MTd_StaticDebug(链接到 static debug 版本),因此您链接到同一个可执行文件(或 .dll)中的 2 个运行时 - 这是不可能的.

为了修复它,您应该确保 libprotobuf 和您的主项目具有相同的 UCRT 值。
当然更改更简单您的主要项目设置与 libprotobuf 的设置相匹配,但建议使用动态运行时版本(在涉及 .dll 的较大项目中,事情可能会变得混乱)甚至如果这需要重新编译 libprotobuf(好吧,如果更改该选项会产生错误,使 libprotobuf 很难构建,并且您的项目将保持如此简单,您可以使用静态UCRT)。

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



更新#0

根据一些 cmets 的要求,在上面的注释中添加一些附加信息,它可能对其他用户有用。

关于一个库(包括 libprotobuf)有 2 个方面完全不相关

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

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

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

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

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

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

  • cmake-gui
  • 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 将构建一个.dll,它将链接到动态 UCRT),以避免可能的运行时问题,并且启用它需要手动干预。

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



脚注

  • #1.lib 文件只会在库导出符号时创建,因为它否则就没有意义(在链接时不需要任何东西,并且 .dll 将被创建,但几乎无法使用)

  • #2:适用于较新的 VStudio 版本(从 v2015 开始) , msvcr(t) 部分已被 vcruntime 替换(或者至少这是入口点,如它被分割成更小的逻辑部分(检查开头的 URL))

【讨论】:

  • 这是否可以解决问题github.com/google/protobuf/tree/master/cmake
  • 谢谢,它现在可以构建(在命令行中使用 -D_SCL_SECURE_NO_WARNINGS)。我已经知道静态和动态之间的区别,但我不知道那个运行时库设置。实际上,google protobuf 文档指出建议使用静态版本,而不是动态版本:github.com/google/protobuf/tree/master/…
  • 很高兴听到它有效。我刚刚阅读了您提供的链接上的 cmets。现在关于您之前的问题,如果最后是关于模板导出,那么我认为不会。
  • 问题:我可以构建一个使用动态运行时的静态库吗?
  • 是的。默认情况下,libprotobuf 的构建方式决定了 VCRTLib 的使用方式。构建类型由 2 个标志控制。以下是我使用动态 VCRTLib -Dprotobuf_MSVC_STATIC_RUNTIME=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF 构建静态 libprotobuf 版本的方法。我应该将这条信息添加到答案中。
猜你喜欢
  • 2017-05-16
  • 1970-01-01
  • 2020-09-20
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多