Nephrite21

Unreal Generated.h 파일 뜯어보기 본문

언리얼

Unreal Generated.h 파일 뜯어보기

Nephrite21 2026. 1. 20. 10:39

 

Unreal C++ 프로젝트 생성시 항상 생기는 Generated.h가 무슨 파일인지 알아보기 위해 작성.

 

언리얼 공식문서상에 Generated.h 관련 자료가 없어서 직접 엔진 코드를 보며 이해하기로 했다.

TestProject를 생성하고, TestActor를 C++클래스로 생성하여 TestActor.Generated.h를 확인해보겠다.

Unreal C++프로젝트 생성 화면
클래스 생성. 이후는 임의로 진행.

클래스를 생성하고 나면 상단에 3개의 헤더가 자동으로 include 되어있는 것을 볼 수 있다.

이후 에디터를 닫고 빌드를 한 뒤 다시 시작하게되면 TestActor.generated.h를 열 수 있다.

// Copyright Epic Games, Inc. All Rights Reserved.
/*===========================================================================
	Generated code exported from UnrealHeaderTool.
	DO NOT modify this manually! Edit the corresponding .h files instead!
===========================================================================*/

// IWYU pragma: private, include "TestActor.h"
#include "UObject/ObjectMacros.h"
#include "UObject/ScriptMacros.h"

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef TESTPROJECT_TestActor_generated_h
#error "TestActor.generated.h already included, missing '#pragma once' in TestActor.h"
#endif
#define TESTPROJECT_TestActor_generated_h

#define FID_***프로젝트경로***_Test_TestProject_Source_TestProject_Public_TestActor_h_12_SPARSE_DATA
#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_SPARSE_DATA_PROPERTY_ACCESSORS
#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_EDITOR_ONLY_SPARSE_DATA_PROPERTY_ACCESSORS
#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_RPC_WRAPPERS_NO_PURE_DECLS
#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_ACCESSORS
#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_INCLASS_NO_PURE_DECLS \
private: \
	static void StaticRegisterNativesATestActor(); \
	friend struct Z_Construct_UClass_ATestActor_Statics; \
public: \
	DECLARE_CLASS(ATestActor, AActor, COMPILED_IN_FLAGS(0 | CLASS_Config), CASTCLASS_None, TEXT("/Script/TestProject"), NO_API) \
	DECLARE_SERIALIZER(ATestActor)


#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_ENHANCED_CONSTRUCTORS \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	NO_API ATestActor(ATestActor&&); \
	NO_API ATestActor(const ATestActor&); \
public: \
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ATestActor); \
	DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ATestActor); \
	DEFINE_DEFAULT_CONSTRUCTOR_CALL(ATestActor) \
	NO_API virtual ~ATestActor();


#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_9_PROLOG
#define FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_SPARSE_DATA \
	FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_SPARSE_DATA_PROPERTY_ACCESSORS \
	FID_***프로젝트경로***_Test_TestProject_Source_TestProject_Public_TestActor_h_12_EDITOR_ONLY_SPARSE_DATA_PROPERTY_ACCESSORS \
	FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_RPC_WRAPPERS_NO_PURE_DECLS \
	FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_ACCESSORS \
	FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_INCLASS_NO_PURE_DECLS \
	FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h_12_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


template<> TESTPROJECT_API UClass* StaticClass<class ATestActor>();

#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID FID_***프로젝트경로***_TestProject_Source_TestProject_Public_TestActor_h


PRAGMA_ENABLE_DEPRECATION_WARNINGS

이렇게 생성 된 클래스 내부에는 다음과 같은 매크로가 존재한다.

  1. Sparse_data, Sparse_data_accessors 등의 define
  2. Inclass_No_Pure_Decl
  3. enhanced_constructors
  4. Prolog와 Generated body
  5. StaticClass 템플릿 함수
  6. Current_file_id

먼저 1번의 비어있는 매크로들은 추후 클래스에서 기능이 추가되거나 정의되는 경우 내부에 내용이 추가되어서 정의될 수 있다. 

2번은 기본 생성자를 private로 감싸서 외부에서 사용할 수 없도록 막고 friend로 Z_Construct_UClass_ATestActor_Statics를 정의하여  추후 TestActor.gen.cpp 에서 정의되는 데이터를 사용할 예정임을 알린다.

3번은 move 와 copy constructor를 private로 비활성화하여 사용하지 못하게 만들고, 대신 엔진에서 제공하는 constructor를 활용하게끔 만들어두었다. 

4번에서 Generated body를 정의하는데, 이는 추후에 다시 포스트로 작성하겠다.

5번에서는 TestActor템플릿으로 StaticClass를 call 했을 때 UClass*를 반환하는 정의를 만들었다. 이 내용은 대응되는 gen.cpp에서

template<> TESTPROJECT_API UClass* StaticClass<ATestActor>()
	{
		return ATestActor::StaticClass();
	}

형태로 구현되어있고, 이를 통해 기존 C++에서 런타임 도중에 현재 클래스 정보를 직접 얻을 수 없는 것과 대비해 StaticClass 함수 호출으로 클래스 정보를 반환 받을 수 있다. 

예를 들어 Runtime 중에 Actor*타입의 포인터를 사용자 임의의 입력을 통해 할당했을 때 보통의 C++에서는 해당 액터의 메소드를 가상함수나 형변환 통하지 않고서는 사용하기 힘들다.

하지만 언리얼에서는 StaticClass나 GetClass를 통해서 바로 자식 클래스를 얻을 수도, 메소드를 호출할 수도 있게된다. Static Class에 관해서는 추후 포스팅.  

6번 Current File id를 재정의 하고있는데, 이는 GENERATED_BODY() 매크로에서 다음과 같이 사용한다

#define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY);

 

이 매크로는 위에있는 매크로와 결합하여

#define BODY_MACRO_COMBINE_INNER(A,B,C,D) A##B##C##D
#define BODY_MACRO_COMBINE(A,B,C,D) BODY_MACRO_COMBINE_INNER(A,B,C,D)

_CURRENT_FILE_ID_(__LINE__매크로 : 매크로가 정의된 줄 위치. 정수값)_GENERATED_BODY로 확장되게 된다.

이러면 결국 아까전에 정의했던 매크로인

FID_***프로젝트 경로***_TestProject_Source_TestProject_Public_TestActor_h_12_GENERATED_BODY

로 확장되게 되고, GENERATED_BODY()를 사용하게 되면  저 매크로가 정의된대로 사용되어 body를 생성하게 된다.

복잡하게 이렇게 하는 이유는 코드단에서는 GENERATED_BODY만 호출하면 그 파일에 맞는 매크로를 알아서 정의해주기 위해서이다.

다시말해 generated.h 파일은 절대경로를 활용해서 절대 겹칠 일이 없는 매크로를 정의하고, 그 매크로를 통해 클래스의 내부를 정의하는 헤더 파일 인 것이다.

 

이를통해 generated.h가 왜 include 맨 마지막에 들어가야하는지는  대충은 이해할 수 있었다. 하지만 Unreal Header Tool에 대한 이해가 없으면 매크로 전처리가 어떻게 되는지 알 수 없기 때문에 추후에 이 내용과 UProperty ufunction uclass ustruct 같은 매크로또한 포스팅 해보도록 하겠다.