在MS Visual C上链接到protobuf 3时出错
Errors when linking to protobuf 3 on MS Visual C
在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++)运行时库(VCRTLib或UCRT-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]上找到一个例子:何时使用动态库与静态库。
正如你所猜测的,CRT或C运行时库(包含使C代码能够运行的底层系统,例如内存管理函数:malloc、free)也不例外-它相当于Nix的libc.a稍微复杂一点:
-
静态CRT驻留在libcmt.lib中
-
动态CRT驻留在msvcrt.lib中;点";至msvcr###.dll(2)(VStudio2013的msvcr120.dll)
备注:
-
A">d";在库名称的末尾(msvcrd.lib),意味着它是用调试符号(也更大、更慢)构建的
-
C++ 运行库处于确切的情况下;这些名称有一个额外的p:libcpmt.lib、msvcprt.lib、msvcp120.dll
-
有关更多详细信息,请查看[MS.Docs]:CRT Library Features
现在,UCRT部分不像任何其他库一样包含在项目中(项目属性-链接器-输入-附加依赖项),但因为它们的性质(静态或动态)在编译时是必需的,所以它们是从[MS.Docs]:/MD、/MT、/LD(使用运行时库)进行配置的,其中有4个可用选项:
-
多线程(/MT)
-
多线程调试(/MTd)
-
多线程DLL(/MD)
-
多线程调试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),它们是完全无关的:
-
库类型(构建方式):dynamic/static
-
UCRT类型(使用UCRT的方式):再次,dynamic/static
因此,有4完全有效的组合:
-
使用动态UCRT的动态库
-
使用静态UCRT的动态库
-
使用动态UCRT的静态库
-
使用StaticUCRT的静态库
对于LibProtoBuf,每个方面都由布尔CMake选项控制:
- 库类型:protobuf_BUILD_SHARED_LIBS
- 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)
- 理解boost::asio-async_read在无需读取内容时的行为
- 当回溯以零开始时,如何调试崩溃
- 为"adjacent"变量赋值时出现问题
- CMake-按正确顺序将项目与C运行时对象文件链接
- CMake 在编译 Google 的 protobuf 示例时找不到 protobuf
- 防止 GNU Make 在每次构建时生成 protobuf 代码
- 使用 cmake 安装 protobuf 时出现问题
- 不使用系统Protobuf库时的"Protobuf compiler version doesn't match library version 3.6.1"
- 用第三方框架编译时Tensorflow Protobuf冲突
- 插入protobuf时SQLite无法识别的令牌错误:要处理哪些令牌以及如何处理?
- Google Protobuf 3:使用 CMAKE 构建时未定义的引用错误
- 使用Opencv和Tensorflow c++时发生Protobuf版本冲突
- Google protobuf在解析字符串数据时在Android中崩溃
- 在MS Visual C上链接到protobuf 3时出错
- 如何在解析文本格式的 protobuf 消息时忽略错误的字段
- 打印Protobuf消息时省略字段
- 在InternalSerializeWithCachedSizesToArray时,protobuf Serialize
- 编译Tensorflow时出现Protobuf错误
- 在 Java 中读取 protobuf 消息时的异常
- 在使用 ZMQ 和 protobuf 时接收 0 大小的消息