找回密码
 立即注册
查看: 234|回复: 2

UE4随笔:接入 Google Protobuf 库

[复制链接]
发表于 2022-8-25 06:48 | 显示全部楼层 |阅读模式
接入 Google Protobuf 库
各工具版本:
① 引擎版本:UE4.27.2
② Protobuf版本:v3.20.1
③ CMake版本:3.23.1
VisualStudio 2019

步骤:
解压下载好的 protobuf-cpp-3.20.1 压缩包,进入到其中的 cmake 文件夹,在该文件夹内创建一个名称为 out 的文件夹;
打开CMake,配置好cmake目录解决方案目录,按照下图所示步骤完成配置:


生成之后,一定要取消 protobuf_MSVC_STATIC_RUNTIME 的勾选,否则UE4项目无法编译通过,会有报错:【 LNK2038 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”(SharedPCH.Engine.NonOptimized.ShadowErrors.h.obj 中) 】,CMake配置如下图所示,取消勾选后必须重新Configure,然后再Generate生成解决方案


因为在UE4项目中,项目配置属性的代码生成的运行库默认为 多线程DLL(/MD),在头文件 yvals.h 中生效的配置为 MD_DynamicRelease,如下图所示:


而在CMake生成的Protobuf解决方案中,Release解决方案配置导出的lib文件为 MT_StaticRelease,故而导致UE4项目编译不过。
在CMake点击 Generate 生成解决方案后,打开项目(protobuf.sln),解决方案配置必须选Release,选中如下图所示:


双击 out 目录下的 extract_includes.bat 脚本,它会在当前目录生成一个 include 文件夹,作为导入UE4项目的Protobuf库的头文件群,同时,上一个步骤会在 out 目录下生成一个 Release 文件夹,其中包含两个lib文件 libprotobuf.liblibprotoc.lib,还有一个工具 protoc.exe 用于将 .proto 文件生成 .h 和 .cc 源文件,至此,就得到了需要复制到UE4项目中的 include 文件夹和两个lib文件;
在UE4项目的 Source 目录下新建目录 ThirdParty/Protobuf 作为第三方库导入(看项目需要,放Plugins下作为插件亦可),将上一步中生成的 include 文件夹复制于此,并新建一个lib文件夹保存 libprotobuf.lib 和 libprotoc.lib,最后新建一个 Protobuf.Build.cs 作为引入的Protobuf库的配置文件,整体如下图所示:


⑥ Protobuf.Build.cs 文件内容如下所示:


最后,需要在项目的 ProjectName.Build.cs 文件内,在 PublicDependencyModuleNames 中添加 Protobuf 配置,然后编译即可。

生成源文件示例:
① 创建一个简单的proto文件,内容如下图所示 [Protobuf官网文档]


② 利用生成的工具 protoc.exe,在CMD中执行命令:
// 注意:protoc.exe只能针对单个.proto文件生成对应.h和.cc源文件,一般会用bat或python批量生成
.\protoc.exe --proto_path=proto文件的目录 --cpp_out=生成的源文件目录 proto文件名称
// 使用示例:
.\protoc.exe --proto_path=. --cpp_out=. Student.proto
执行完成后会在 --cpp_out 配置的目录下生成 .h.cc 文件。因为 protoc.exe 每次只能处理一个proto文件,所以可以写一个 python 脚本递归遍历proto文件夹,并在源文件目录中对应的目录结构下逐一生成源文件,还可以顺便将 .cc 源文件重命名为 .cpp 源文件。
③ 在UE4中的使用简单示例:


关于在C++中使用Protobuf的嵌套类型:Protobuf内部有内存管理机制不能使用智能指针给嵌套对象赋值,使用new将申请好的内存通过 set_allocated_XXX() 接口给嵌套的对象赋值,Protobuf内部会负责析构这部分内存,需要特别注意的是,该接口会delete之前已经申请的内存。
建议使用Protobuf框架提供的 mutable_XXX() 接口,该接口会返回之前已经申请好的内存指针,如果之前没有申请,则执行申请后返回分配好的内存指针,而针对嵌套的对象数组,可以使用Protobuf框架提供的 add_XXX(),同样也是按需返回内存的指针,且Protobuf内部会管理这些申请的内存。

补充:
① 编译报错:error C4668: 没有将“GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE”定义为预处理器宏,用“0”替换“#if/#elif,解决方案:在Protobuf头文件 include/google/protobuf/inlined_string_field.h 中插入 #pragma warning(disable:4668)
② 在UE4中,当源文件超过一定数量,proto的cpp内 PROTOBUF_PRAGMA_INIT_SEG 宏定义会报【C2356: 初始化段在翻译单元期间不能更改】,同时cpp文件内的静态变量 schemasfile_default_instances 会报【C2374】重定义的错误,目前原因未知,只有当源文件超过一定数量才可能触发这两个报错,令人费解!解决方案:因为protoc.exe只能针对单个proto文件执行源文件生成,所以一般都会通过一个python脚本来批量执行protoc.exe,在python脚本中,执行完生成命令后读取源文件内容,注释 PROTOBUF_PRAGMA_INIT_SEG,同时给 schemas file_default_instances 添加proto文件名称的后缀,以此来规避报错。
【UE4随笔】

点击进入:B站个人主页
点击进入:知乎个人主页
点击进入:公众号话题
微信公众号搜索:灵知子

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2022-8-25 06:51 | 显示全部楼层
求linux和移动版本
发表于 2022-8-25 06:54 | 显示全部楼层
我不会啊,只在Windows下操作过[捂脸]
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-25 07:09 , Processed in 0.090253 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表