UE4随笔:接入 Google Protobuf 库
接入 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.lib 和 libprotoc.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文件,内容如下图所示 :
http://pic4.zhimg.com/v2-c990955d4911b66f25e0576102a9eaaf_r.jpg
② 利用生成的工具 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文件内的静态变量 schemas 和 file_default_instances 会报【C2374】重定义的错误,目前原因未知,只有当源文件超过一定数量才可能触发这两个报错,令人费解!解决方案:因为protoc.exe只能针对单个proto文件执行源文件生成,所以一般都会通过一个python脚本来批量执行protoc.exe,在python脚本中,执行完生成命令后读取源文件内容,注释 PROTOBUF_PRAGMA_INIT_SEG,同时给 schemas 和 file_default_instances 添加proto文件名称的后缀,以此来规避报错。
【UE4随笔】
点击进入:B站个人主页
点击进入:知乎个人主页
点击进入:公众号话题
微信公众号搜索:灵知子 求linux和移动版本 我不会啊,只在Windows下操作过[捂脸]
页:
[1]