自学内容网 自学内容网

UE5集成gRPC

最近有项目需要在UE5里做RPC,对比了thrift、gRPC、rcplib等开源rpc框架,由于习惯使用protobuf,故选择了gRPC。然而,Google出品也是一言难尽啊,最起码编译太繁琐了。

本次使用的gRPC版本为1.62.1,UE5.2,以插件的形式集成,支持DebugGame/DebugGame Editor/Development/Development Editor/Shipping(目前只测试这几个)。

插件免费,下载地址:【免费】UE5gRPC1.62.1插件资源-CSDN文库

测试案例下载地址:【免费】UE5gRPC插件测试案例资源-CSDN文库

0、目的

        本来已经有人在git上做了比较好的插件,但是,我们搞C++的,总想着都是开源的东西,最好自己也来封装一个可以把控的东东,用起来放心,有什么功能需要扩展也可以自己接着肝。

        了解一下如何一步一步封装起来的过程也是值得期待的事情,在能力范围内,最大的自由度总是带来无限的快感 ^_^

1、所谓坑位

  •  gRPC依赖的库zlib与boringssl-with-bazel(boringssl-with-bazel包括crypto、ssl,这2人起主要冲突)与UE5相关库的名字重定义冲突。
  •  gRPC编译动态库极其困难,1.62.1版本编译动态库会出现upb相关的符号丢失问题。

2、尝试解决

  • UE5的编译器选项AdditionalLinkerOptions,本来想模拟C++链接器的“/FORCE:MUTIPLE”,结果不起作用;
  • 将gRPC换成动态库,想着UE里的冲突库是静态库,可能动态加载Grpc可行,但是动态库就需要显示加载,很麻烦,而且gRPC编译动态库upb库符号导出会出问题。最终,将crypto、ssl以及zlib换成动态库尝试(毕竟就这几个报错集成不到UE里),结果动态库的导出文件.lib与对应的静态库.lib还是冲突。【后来反思了一下,这种想法是博主编译链接知识太菜了】
  • 初始想法是哪个库冲突就唯一化哪个库。一个办法就是将UE的库升级到gRPC官方推荐的boringssl-with-bazel;另一个方法就是将Grpc依赖的库zlib与boringssl-with-bazel换成UE引擎的ThirdParty的同名库。

最终,最后一种想法的最后一种方法尝试成功。

3、Cmake配置

CMAKE组里:CMAKE_INSTALL_PREFIX    D:/grpc

ABSL里的CXX_STD勾选上

配置UE5的OPENSSL+ZLIB

4、库编译

选择Release,右键ALL_BUILD生成(采用VS2019)

右键INSTALL生成

生成的gRPC库文件

5、插件目录结构

其中,libgrpc1.62.1是grpc库,LibGrpc是插件源码目录。

其中,helloworld.grpc.pb.cc和helloworld.grpc.pb.h,helloworld.pb.cc和helloworld.pb.h是proto文件生成的。

cmd里的指令如下,输出目录改成自定义的,其中用到的exe程序均在生成的库目录的 grpc/bin 下。不同语言之间要用到的RPC工具博主也生成了,都在bin里面,对应的指令大家自己百度一下即可,由于博主的客户端也是Cpp的,就共用了。

protoc.exe --grpc_out=输出目录 --plugin=protoc-gen-grpc=D:\grpc\bin\grpc_cpp_plugin.exe helloworld.proto

protoc.exe --cpp_out=输出目录helloworld.proto

6、LibGrpc.Build.cs

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System.IO;

public class LibGrpc : ModuleRules
{
public LibGrpc(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
bEnableUndefinedIdentifierWarnings = false;

PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);

PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);

PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);

PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);

DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);

//set grpc library for Windows
string GrpcPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../libgrpc1.62.1/"));
//include the grpc header files
string IncludePath = GrpcPath + "include/";
PublicSystemIncludePaths.AddRange(new string[] { IncludePath });

//use engine library
AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenSSL");
AddEngineThirdPartyPrivateStaticDependencies(Target, "zlib");
if (Target.Platform == UnrealTargetPlatform.Win64)
        {
//add the grpc libs
string LibPath = GrpcPath + "lib/Win64/";
foreach (string file in Directory.GetFiles(LibPath))
{
PublicAdditionalLibraries.Add(file);
}
}
else if (Target.Platform == UnrealTargetPlatform.Linux){
System.Console.WriteLine("Not currently supported on Linux");
}
else // unsupported platform
{
System.Console.WriteLine("Only supported on Windows");
}
}
}

7、插件测试

采用Grpc自带的示例测试,helloworld.proto。

helloworld.grpc.pb.cc、helloworld.grpc.pb.h、helloworld.pb.cc和helloworld.pb.h是协议自生成的文档,greeter_server.cc可以封装到UE的内部组织里,比如将其逻辑写在FRunnable的子类里,然后暴露给BlueprintFunctionLibrary让蓝图调用。

使用之前需要测试全面,至少包括:DebugGame/DebugGame Editor/Development/Development Editor/Shipping,测试一下插件编译是否成功。

至此,UE5的gRPC插件封装完成,祝大家使用愉快,编译一次丝滑通过。

有问题随时联系我,共同踩坑,共同进步!


原文地址:https://blog.csdn.net/A_Pointer/article/details/137975562

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!