본문 바로가기

Unreal Engine

[언리얼엔진] Protobuf 세팅 방법

Protobuf(Protocol Buffer)는 구글에서 개발한 데이터 직렬화 라이브러리입니다. 언어와 독립적이고, 다양한 언어를 지원하며 통신이나 데이터 저장에 사용하기 좋기 때문에 게임 쪽에서는 굉장히 많이 사용하는 편입니다.

 

다만 언리얼 엔진에서 Protobuf를 사용하는 예시는 많고 cmake 예시도 많지만, 세팅하는 방법은 많이 없어 이에 대한 기록을 합니다.

 

구글 프로토콜 버퍼 사용하기(with visual studio, cmake)

지난 포스팅에서 구글 프로토콜 버퍼에 대해서 간략히 알아보았습니다. 직접 구글 프로토콜 버퍼를 사용해보기 위해서 발품 팔았지만, 정보가 생각보다 쉽게 나오지 않아서 설치하면서 얻은 경

minusi.tistory.com

 


Protobuf의 경우 저는 버전을 3.21.12를 사용했습니다.

이유는 저 버전 이후로 protobuf에 abseil이라는 라이브러리가 도입됩니다. 문제는 이 라이브러리로 인해서 Unreal에 세팅하기도 굉장히 번거로워졌을 뿐더러, 직접 하나하나 세팅해야되는 Unreal ThirdParty 라이브러리로써는 너무 고려해야 될 부분이 많아졌습니다. 그렇기 때문에 문제의 라이브러리가 도입되기 직전인 버전으로 세팅합니다. 

(그리고 직렬화 라이브러리 특성 상, 그리고 TCP 바이너리 통신을 할 경우에는 버전이 크게 상관이 없습니다.)

 

이제 Protobuf를 빌드합시다.

protobuf 솔루션

protobuf의 경우 솔루션 파일이 다음과 같이 구성되어 있습니다.

원래대로라면 그냥 바로 ALL_BUILD를 실행하면 되지만, 문제는 cmake로 만든 솔루션의 경우 빌드 시 런타임 라이브러리 설정이 /MT로 되어있습니다. 

문제는 언리얼의 경우 라이브러리를 /MD로 세팅하지 않으면 다음과 같은 에러가 수백개가 발생합니다.

libprotobuf.lib(parse_context.obj): Error LNK2038 : mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease' in Module.TraceLog.cpp.obj

 

즉 빌드 시에 /MD로 빌드될 수 있도록 세팅을 수정해줘야 합니다.

Multi-threaded(/MT)를 Multithreaded DLL(/MD)로 수정합니다.

 

빌드가 완료되면 이제 include 파일과 lib를 언리얼 프로젝트에 세팅합니다. 

저의 경우는 다음과 같이 디렉토리 구조를 세팅을 했습니다.

Source/
  YourProjectName/
    Private/
      Protocol/
        Test.pb.cc
    Public/
      Protocol/
        Test.pb.h
    YourProjectName.build.cs
  ThirdParty/
    Protobuf/
      include/
        google/protobuf/...
      lib/
        libprotobuf.lib

 

이렇게 빌드한 뒤 Unreal의 빌드 세팅을 다음과 같이 수정합니다.

public class TestFPSProject : ModuleRules
{
	public YourProjectName(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		PublicIncludePaths.AddRange(new string[] {
			Path.Combine(ModuleDirectory, "Public"),
			Path.Combine(ModuleDirectory, "Public/Protocol"),
			Path.Combine(ModuleDirectory, "../ThirdParty/Protobuf/include")
		});

		PrivateIncludePaths.AddRange(new string[] {
			Path.Combine(ModuleDirectory, "Private"),
			Path.Combine(ModuleDirectory, "Private/Protocol")
		});

		PublicAdditionalLibraries.Add(Path.Combine(ModuleDirectory, "../ThirdParty/Protobuf/lib/libprotobuf.lib"));

		PublicDependencyModuleNames.AddRange(new string[] {
			"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "Sockets", "Networking"
		});

        // 없으면 Error C4668 : 'GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
		PublicDefinitions.Add("GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE=0");

		// Protobuf를 사용하는 컴파일 유닛에 필요
		bEnableExceptions = true; // Protobuf 내부에서 예외 사용
	}
}

 

 

이렇게 세팅하고 난 뒤 빌드를 하면 성공하는 점을 확인할 수 있었습니다.