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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35116437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:28:33  来源:igfitidea点击:

Errors when linking to protobuf 3 on MS Visual C

c++visual-studiovisual-c++visual-studio-2013protocol-buffers

提问by jokoon

Encountered on Visual Studio 2013, but it's reproducible with any version.

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

I cloned the protocol buffer library from github, ran CMake-gui on it (I left everything to default, so it's the static version), only built libprotobuf (other project failed for some reason, cmd.exe error, might have something to do with tests, but libprotobuf builds fine).

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

My project uses headers generated with the .proto file found on the mapbox vector tiles spec's github.

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

When I link, I first have this error

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

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

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

I tried disabling it with -D_SCL_SECURE_NO_WARNINGSin additional command line arguments, but then I have other errors:

我尝试-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)

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)

回答by CristiFati

It's a mismatch of how the VStudio C (and C++) RunTime Library(VCRTLibor UCRT- check [SO]: How to circumvent Windows Universal CRT headers dependency on vcruntime.h (@CristiFati's answer)) is used by your project and by libprotobufproject. Let me detail:

它的如何的不匹配VStudio C(和C ++)运行时库VCRTLibUCRT-检查[SO]:如何规避的Windows通用CRT接头上vcruntime.h依赖(@ CristiFati的答案))是由您的项目,并通过libprotobuf项目。详细说一下:

Let's say there's some C(C++) code. The purpose of that code is to be run. Than can be achieved:

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

  • Directly: including that code in an VC Applicationtype project - which will generate an .exe
  • Indirectly: including the code in an VC Librarytype project - which will generate a librarywhich will only be able to run when called from another .exe(that calls that library). The library can be:
    • static: all the C(C++) code will be compiled and stored in a .libfile. You will need that file when using the library in another project (whether it's an application or a library) - at linktime. Note that all the needed code from your .libwill be "copied" into the other project
    • dynamic: you will have 2 files now: a .dllfile which will contain the compiled (and linked) code, and a .libfile(1)which will contain "pointers" (if you will) to the code in the .dllfile. When using the library in another project, you will also need the .libfile at linktime, but now it won't contain the code so it won't be copied in the other library (the other library will be smaller), but at runtime the other library will need the .dllfile
  • 直接:在VC 应用程序类型项目中包含该代码- 这将生成一个.exe
  • 间接:在VC 库类型项目中包含代码- 这将生成一个,该只能在从另一个.exe(调用该库)调用时才能运行。库可以是:
    • static:所有C( C++) 代码都将被编译并存储在一个.lib文件中。在另一个项目(无论是应用程序还是库)中使用库时,您将需要该文件 - 在链接时。请注意,您的.lib中所有需要的代码都将“复制”到另一个项目中
    • 动态:您现在将有 2 个文件:一个.dll文件,其中包含已编译(和链接)的代码,以及一个.lib文件(1),其中包含指向.dll 中代码的“指针”(如果您愿意的话)文件。在另一个项目中使用该库时,您还需要在链接时使用.lib文件,但现在它不包含代码,因此不会复制到另一个库中(另一个库会更小),但是在运行时,其他库将需要.dll文件

You can check [SO]: LNK2005 Error in CLR Windows Form (@CristiFati's answer)for details of how C(C++) code gets to be transformed in executable format. Also Googleis full of articles about differences between static and dynamic libraries, when to use one or the other, an example can be found on [SO]: When to use dynamic vs. static libraries.

您可以查看[SO]: LNK2005 Error in CLR Windows Form(@CristiFati 的回答),了解如何将C( C++) 代码转换为可执行格式的详细信息。也谷歌是满的有关静态和动态库之间的差异,当使用一种或另一种物品,例如一个上可以找到当使用动态与静态库:[SO]

As you guessed, the CRTor C RunTime library(that contains the underlying system that makes Ccode able to run - one example are memory management functions: malloc, free) makes no exception - it's the equivalent of Nix's libc.a(static or archive) vs. libc.so(dynamic or shared object) - but in VStudioit's a little bit more complicated:

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

  • Static CRTresides in libcmt.lib
  • Dynamic CRTresides in msvcrt.libwhich "points" to msvcr###.dll(2)(msvcr120.dllfor VStudio 2013)
  • 静态CRT驻留在libcmt.lib 中
  • 动态CRT驻留在msvcrt.lib 中,它“指向” msvcr###.dll (2)( msvcr120.dllfor VStudio 2013)

Notes:

注意事项

  • A "d" at the end of the library name (msvcrd.lib), means that it's compiled with debug symbols
  • C++runtime library is under the exact situation; the names have an extra p: libcpmt.lib, msvcprt.lib, msvcp120.dll
  • For more details, check [MS.Docs]: CRT Library Features
  • 库名(msvcr d.lib)末尾的“ d”表示它是用调试符号编译的
  • C++运行时库是在确切的情况下;名称有一个额外的plibc pmt.libmsvc prt.libmsvc p120.dll
  • 有关更多详细信息,请查看[MS.Docs]:CRT 库功能

Now, UCRTparts, are not included in the project like any other lib (Project Properties -> Linker -> Input -> Additional Dependencies), but because their nature (static or dynamic) is required at compile time they are configured from: [MS.Docs]: /MD, /MT, /LD (Use Run-Time Library), where there are 4 available choices:

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

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

Obviously, the ones that contain "Debug" are when building for Debugconfiguration while the other ones for Release; the key point is that the ones that have DLLare using the dynamicruntime version, while the other ones the staticversion.

显然,包含 "Debug" 的那些是在为Debug配置构建时,而其他的用于Release; 关键是那些有DLL的使用的是动态运行时版本,而其他的是静态版本。

Back to your error: the linker complains that main.obj(part of your project) has MDd_DynamicDebug(linking against the dynamic debugversion), while common.obj(part of libprotobufproject) has MTd_StaticDebug(linking against the static debugversion), so you link against 2 runtimes in the same executable (or .dll) - which is not possible.

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

In order to fix it, you should make sure that both libprotobufand your main project have the same value for UCRT.
Of course it's simpler to change your main project setting to match libprotobuf's one, but it's recommended to use the dynamic runtime version (things can get messy in larger projects that have .dlls involved) even if this requires to recompile libprotobuf(well, if changing that option generates errors that make libprotobufvery hard to build, and your project is going to stay this simple, you can use the static UCRT).

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

Note: Not to mistake UCRTtype (static / dynamic) with the way libprotobufis being built (static at this point, but I'm sure that it can be built as dynamic too).

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





Update #0

更新#0

Adding some additional info on the above note, as some comments requested it, and it might be useful to other users.

在上面的注释中添加一些附加信息,因为一些评论要求它,它可能对其他用户有用。

There are 2 aspects about a library (including libprotobuf), that are totally unrelated:

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

  1. Library type(the way it is being built): dynamic/ static
  2. UCRTtype(the way it uses UCRT): again, dynamic/ static
  1. 库类型(构建方式):动态/静态
  2. UCRT类型(它使用UCRT的方式):再次,动态/静态

So, there are 4 perfectly valid combinations:

因此,有 4 种完全有效的组合:

  1. Dynamic library using dynamic UCRT
  2. Dynamic library using static UCRT
  3. Static library using dynamic UCRT
  4. Static library using static UCRT
  1. 使用动态UCRT 的动态库
  2. 使用静态UCRT 的动态库
  3. 使用动态UCRT 的静态库
  4. 使用静态UCRT 的静态库

For libprotobuf, each of the aspects is controlled by a boolean cmakeoption:

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

  1. Library type: protobuf_BUILD_SHARED_LIBS
  2. UCRTtype: protobuf_MSVC_STATIC_RUNTIME
  1. 库类型:protobuf_BUILD_SHARED_LIBS
  2. UCRT类型:protobuf_MSVC_STATIC_RUNTIME

The 2 flags can be set by either:

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

  • cmake-gui
  • cmake cmdline(passing them as arguments - e.g.: -Dprotobuf_BUILD_SHARED_LIBS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF)
  • cmake-gui
  • cmake的CMDLINE(将它们作为参数-比如:-Dprotobuf_BUILD_SHARED_LIBS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF

The above 4 combinations are thus possible(at least in v3.5), but #2.is disabled by default(specifying -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_MSVC_STATIC_RUNTIME=ONwill build a .dllwhich will link to the dynamicUCRT), in order to avoid possible runtime problems, and enabling it requires manual intervention.

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

For more details regarding build instructions (via cmake), check: [GitHub]: protocolbuffers/protobuf - (master) protobuf/cmake/README.md.

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





Footnotes

脚注

  • #1: The .libfile will only be created if the library exports symbols, as it wouldn't make sense otherwise (nothing needed at link time, and the .dllwill be created, but pretty much unusable)

  • #2: For newer VStudioversions (starting with v2015), the msvcr(t)part has been replaced by vcruntime(or at least this is the entrypoint, as it was split in smaller logical pieces (check the URLat the beginning))

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

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