나만의 작은 도서관

[언리얼] Unreal Header Tool(UHT) 본문

Unreal Engine

[언리얼] Unreal Header Tool(UHT)

pledge24 2025. 7. 24. 22:32

Unreal Header Tool(UHT)란?

  • Unreal Header Tool(이하 UHT)이란 C++ 소스 코드들을 빌드하기 전에 언리얼 리플렉션 시스템에 필요한 정보들을 읽는 작업을 하는 툴(Tool)로, 언리얼 프로젝트와 연동된 MSVC에서 빌드 시 자동으로 실행된다. (라이브 코딩 비활성화 기준)

UHT 실행 과정

  1. 헤더 파일 스캔: UBT(Unreal Build Tool)가 소스 파일 중 리플렉션 키워드(ex. UCLASS, EditAnywhere)가 들어있는 헤더 파일(. h)을 탐색
    1. UBT가 헤더 파일에서 리플렉션 키워드를 발견했다면 UHT 호출
  2. 파싱 및 분석: UHT는 해당 헤더 파일(.h)을 파싱 하여 리플렉션 데이터(클래스, 구조체, 함수, 메타데이터)를 추출 및 수집
  3. 코드 생성: 각 헤더 파일에 대응하는 “xxx.generated.h”, “xxx.gen.cpp”를 생성
    1. 이때 생성된 코드는 “런타임”에 UClass, Ustruct, UFunction 등의 객체로 변환된다.
    2. ⇒ 이를 통해 블루프린트 시스템, 직렬화(Serialization), 가비지 컬렉션이 작동한다.
  4. 컴파일러 빌드 시작: UHT가 만든 코드와 함께 소스 코드가 빌드된다.

+) 참고로 UHT가 실행될때마다 Intermediate 폴더도 갱신된다.

 

 

UHT가 생성한 정적 함수 StaticXXX()

  • UHT가 생성한 xxx.generated.h 파일에는 정적 함수인 StaticXXX() 시리즈가 있다. 이 시리즈들을 통해 런타임 리플렉션 정보에 접근할 수 있다.
// AMyActor.generated.h에서 생성되는 코드 예시
class AMyActor {
public:
    static UClass* StaticClass() {
        static UClass* StaticClassPtr = nullptr;
        if (!StaticClassPtr) {
            StaticClassPtr = UObject::GetStaticClass(/* ... */);
        }
        return StaticClassPtr;
    }
};

 

 

예시 1. StaticClass()

  • UCLASS 매크로가 적용된 모든 클래스에 대해 자동으로 생성되는 정적 함수.
  • 반환값으로 해당 클래스의 UClass* 객체를 반환한다.
    • UClass는 클래스의 메타데이터(metadata)를 담고 있는 리플렉션 객체
// 활용 1. "AMyActor" 클래스의 UClass 정보를 가져온다.
UClass* MyActorClass = AMyActor::StaticClass();

// 활용 2. 새로운 "AMyActor" 객체를 생성할때 사용한다.
AActor* NewActor = GetWorld()->SpawnActor<AActor>(AMyActor::StaticClass());

// 활용 3. 특정 객체가 "AMyActor" 타입인지 확인할 때 사용한다.
if(SomeObject->GetClass() == AMyActor::StaticClass()){

}

// 활용 4. 특정 객체가 "AMyAcotr" 또는 그 자식 클래스인지 확인할 때 사용한다.
if(SomeObject->IsA(AMyActor::StaticClass()){

}

 

 

예시 2. StaticStruct()

  • USTRUCT 매크로가 적용된 모든 구조체에 대해 자동으로 생성되는 정적 함수
  • 반환값으로 해당 구조체의 UStruct* 객체를 반환한다.
    • UStruct는 구조체의 메타데이터(metadata)를 담고 있는 리플렉션 객체
// 구조체를 USTRUCT로 지정
USTRUCT(BlueprintType)
struct FMyStruct {
    GENERATED_BODY()
    
    UPROPERTY(BlueprintReadWrite)
    int32 Value;
};

// 활용 1. "FMyStruct" 구조체의 UStruct 정보를 가져온다.
UStruct* MyStructType = FMyStruct::StaticStruct();
// "FMyStruct" 구조체 속성(멤버 변수)을 가져온다.
UProperty* ValueProperty = MyStructType->FindPropertyByName("Value");

 

 

왜 UFUNCTION, UPROPERTY와 같은 리플렉션 매크로 함수를 붙이는가?

  1. 해당 요소(함수나 변수 등)를 에디터에 노출시키기 위해서
  2. 해당 요소를 블루프린트에서 사용하기 위해서
  3. 해당 요소를 런타임에 타입 정보를 알고 싶어서
  4. 해당 요소를 GC(Garbage Collection)에 추가하고 싶어서
  5. 해당 요소를 네트워크 동기화 처리를 맡기고 싶어서

 

리플렉션 매크로 함수의 지정자(Specifiers)

  • UFUNCTION, UPROPERTY와 같은 리플렉션 매크로 함수들에 지정자를 추가할 수 있다. 개발자는 지정자를 추가함으로써 여러 고급 기능들을 활용할 수 있게 된다.

 

클래스(UCLASS) 지정자 예시

지정자 이름 설명
BlueprintType 이 클래스를 “블루프린트에서 변수로 사용할 수 있는 타입”으로 지정한다.
Blueprintable 이 클래스를 “블루프린트에서 생성할 수 있는 기반 클래스”로 지정한다.
Abstract 클래스를 “추상 베이스 클래스”로 선언. 사용자가 해당 클래스 액터를 월드에 추가하지 못하도록 한다.

 

 

속성(UPROPERTY) 지정자 예시

  • UPROPERTY로 설정한 변수는 언리얼 에디터의 디테일 패널에 노출 여부를 결정할 수 있다. (유니티의 [SerializeField]랑 비슷한 듯?)
지정자 이름 설명
EditAnywhere 이 프로퍼티를 아키타입이나 인스턴스 양쪽의 프로퍼티 창에서 편집할 수 있도록 한다.
BlueprintReadOnly 이 프로퍼티를 블루프린트에서 읽을 수 있도록 한다.
BlueprintReadWrite 이 프로퍼티를 블루프린트에서 읽거나 쓸 수 있도록 한다.
Replicated 이 프로퍼티가 네트워크를 통해 리플리케이트 되도록 한다.
SaveGame 프로퍼티 레벨에서 체크포인트/저장 시스템용 필드를 명시적으로 포함시키도록 한다.

 

 

함수(UFUNCTION) 지정자 예시

  • UFUNCTION으로 설정한 함수는 블루프린트에서 호출 가능 여부를 결정할 수 있다.
지정자 이름 설명
BlueprintCallable 이 함수를 블루프린트에서 “호출 가능”하도록 한다.
BlueprintImplementableEvent 이 함수를 블루프린트에서 구현하는 이벤트로 지정한다.
CallInEditor 이 함수를 에디터에서도 실행 가능하도록 한다.
Server/Client 이 함수를 네트워크 RPC 함수로 지정한다.

 

 

기타 지정자

지정자 이름 설명
Category 드롭다운 리스트의 토글 목록을 추가한다.(ex. Category = “Login” → Login 토글 목록이 생김)

 

언리얼에서 메타데이터(metadata)란?

  • 언리얼 엔진에서 메타데이터(metadata)는 에디터에만 존재하는 데이터로, 클래스, 구조체, 함수, 프로퍼티에 대한 추가적인 정보들을 의미한다.
  • 즉, 메타데이터는 코드 자체의 동작과는 별개이며, 에디터나 런타임 시스템이 해당 요소를 어떻게 다뤄야 하는지 결정하는 정보들이다.
  • 메타데이터는 리플렉션 키워드 매크로의 지정자(Specifiers)로 추가할 수 있으며, 추가하는 방법은 아래와 같이 “meta”라는 단어와 그 뒤에 지정자 목록과 필요한 값을 적어주면 된다.
UFUNCTION(BlueprintCallable, Category="MyGame|Combat",
          meta=(DisplayName="Deal Damage", ToolTip="Applies damage to target",
                Keywords="damage hurt attack"))
void DealDamage(float DamageAmount);

 

 

실제 사용 예시

UCLASS(BlueprintType, Blueprintable)  // <- 지정자들
class MYGAME_API AMyActor : public AActor
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Movement",  // <- 지정자들
              meta=(DisplayName="Max Speed",                          // <- 메타데이터 시작
                    ToolTip="Maximum movement speed in units per second",
                    UIMin="0.0", UIMax="1000.0",
                    ClampMin="0.0"))                                  // <- 메타데이터 끝
    float MaxSpeed = 600.0f;

    UFUNCTION(BlueprintCallable, Category="Movement")  // <- 지정자들
    void SetSpeed(float NewSpeed);
};

 

런타임 접근 방법

 

지정자 정보: UClass의 플래그나 프로퍼티 플래그로 접근

// EditAnywhere 지정자 확인
bool bCanEdit = Property->HasAnyPropertyFlags(CPF_Edit);

 

메타데이터: GetMetaData() 함수로 접근

// DisplayName 메타데이터 확인
FString DisplayName = Property->GetMetaData("DisplayName");