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

Errors when linking to protobuf 3 on MS Visual C

本文关键字:protobuf 3时 出错 链接 MS Visual      更新时间:2023-10-16

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

我从github克隆了协议缓冲库,在上面运行了CMake gui(我把所有东西都保留为默认值,所以它是静态版本),只构建了libprotobuf(其他项目由于某种原因失败了,cmd.exe错误,可能与测试有关,但libprotobu夫构建得很好)。

我的项目使用在mapbox vector tiles规范的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.0vcincludexutility

我尝试在额外的命令行参数中使用-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:eiogit3misc-projsmaploadmaploadlibprotobufd.lib(common.obj)

您的项目和LibProtoBuf项目使用VStudio C(和C++)运行时库(VCRTLibUCRT-check[SO]:如何规避Windows通用CRT标头对vcruntime.h的依赖(@CristiFati的答案))的方式不匹配。让我详细介绍一下:

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

  • 直接:将该代码包含在VC应用程序类型的项目中,该项目将生成.exe

  • 间接地:将代码包含在VC库类型的项目中,该项目将生成一个Library,该库只能在从另一个.exe(调用该库)调用时运行。库可以是:

    • 静态:所有C(C++)代码都将编译并存储在.lib文件中。在另一个项目(无论是应用程序还是库)中使用该库时,您都需要该文件,时间为链接。请注意,.lib中所有需要的代码都将是";复制的";进入其他项目

    • 动态:您现在将有两个文件:一个.dll文件,它将包含编译(和链接)的代码,以及一个.lib(1)文件;指针";(如果愿意的话)到.dll文件中的代码。在另一个项目中使用该库时,您还需要链接时的.lib文件,但现在它不包含代码,因此不会复制到其他库中(其他库会更小),但在运行时间,其他库将需要.dll的文件

您可以查看[SO]:LNK2005 CLR Windows窗体中的错误(@CristiFati的回答),了解C(C++)代码如何转换为可执行格式的详细信息。此外,Google上有很多关于静态库和动态库之间差异的文章,何时使用其中一个,可以在[SO]上找到一个例子:何时使用动态库与静态库。

正如你所猜测的,CRTC运行时库(包含使C代码能够运行的底层系统,例如内存管理函数:mallocfree)也不例外-它相当于Nixlibc.a稍微复杂一点:

  • 静态CRT驻留在libcmt.lib

  • 动态CRT驻留在msvcrt.lib中;点";至msvcr###.dll(2)(VStudio2013msvcr120.dll)

备注

  • A">d";在库名称的末尾(msvcrd.lib),意味着它是用调试符号(也更大、更慢)构建的

  • C++ 运行库处于确切的情况下;这些名称有一个额外的plibcpmt.libmsvcprt.libmsvcp120.dll

  • 有关更多详细信息,请查看[MS.Docs]:CRT Library Features

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

  1. 多线程(/MT)

  2. 多线程调试(/MTd)

  3. 多线程DLL(/MD)

  4. 多线程调试DLL(/MDd)

显然,那些包含";调试"当为调试配置构建时,而为Release构建其他配置时;关键是具有DLL的那些使用动态运行时版本,而其他的则使用static版本。

回到您的错误:链接器抱怨main.obj(项目的一部分)具有MDd_DynamicDebug[链接到动态调试版本],而common.obj[/em>(LibProtoBuf项目的一个部分)具有MTd_StaticDebug[链接到静态调试dll)中链接2个运行时,这是不可能的。

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

注意:不要将UCRT类型(静态/动态)与构建LibProtoBuf的方式混为一谈(目前是静态的,但我相信它也可以构建为动态的)。



更新#0

根据一些评论的要求,在上面的注释中添加一些额外的信息,这可能对其他用户有用。

库有两个方面(包括LibProtoBuf),它们是完全无关的

  1. 库类型(构建方式):dynamic/static

  2. UCRT类型(使用UCRT的方式):再次,dynamic/static

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

  1. 使用动态UCRT的动态库

  2. 使用静态UCRT的动态库

  3. 使用动态UCRT的静态库

  4. 使用StaticUCRT的静态库

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

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

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

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

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



脚注

  • #1 :只有当库导出符号时,才会创建.lib文件,否则就没有意义了(链接时不需要任何东西,并且会创建.dll,但几乎不可用)

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