본문으로 건너뛰기
Unreal Engine 모듈 · 플러그인 개발LESSON 04

.Build.cs의 역할과 모듈 의존성 선언

난이도심화
예상 시간85분
선수지식3강의 Target·Module 구조

4강. .Build.cs의 역할과 모듈 의존성 선언

1. 이번 강의에서 해결할 문제​

헤더를 찾지 못할 때마다 모든 모듈을 PublicDependencyModuleNames에 추가하면 당장은 빌드되지만 소비 모듈까지 Include·Link 환경이 전파됩니다. 반대로 Public 헤더가 다른 모듈의 값 타입을 노출하면서 의존성을 Private에만 두면 소비자가 그 헤더를 Include할 때 실패합니다.

2. 학습 목표​

3. 핵심 개념​

PublicDependencyModuleNames는 이 모듈의 Public 소스가 요구하는 모듈입니다. 소비 모듈이 Public 헤더를 사용할 때 필요한 Include·Link 환경이 전파됩니다. PrivateDependencyModuleNames는 Private 헤더와 CPP 구현에서만 필요한 모듈입니다. 가능한 의존성을 Private으로 유지하면 변경 전파와 컴파일 비용을 줄일 수 있습니다.

Public Header에 FGameplayTag 값을 멤버로 노출하면 GameplayTags는 Public 의존성입니다. CPP에서만 DrawDebugLine을 호출하면 Engine 의존성의 사용은 Private 영역입니다. 포인터나 참조로만 사용하는 클래스는 Forward Declaration으로 Public Header Include를 제거할 수 있습니다.

빌드 계약 용어와 실행 주체​

용어무엇인가누가·언제 사용하나
ModuleRules한 모듈의 컴파일·링크 규칙을 계산하는 C# 클래스Unreal Build Tool이 Target 빌드 그래프를 만들 때 실행합니다.
Producer ModulePublic API를 제공하는 모듈ReusableInteraction이 헤더와 Symbol을 제공합니다.
Consumer ModuleProducer의 Public 헤더를 Include하는 모듈게임 모듈 또는 다른 플러그인 모듈입니다.
Public 의존성Producer 공개 계약을 해석하는 데 필요한 다른 모듈Consumer 컴파일 환경에도 전파됩니다.
Private 의존성Producer 구현 안에서만 필요한 모듈Producer의 Private Header·CPP 컴파일에만 사용합니다.

Build.cs의 Public과 C++ 클래스의 public:은 서로 다른 축입니다. C++ 접근 지정자는 클래스 멤버 접근 권한이고, Build.cs Public은 모듈 소비자에게 전파할 빌드 환경을 뜻합니다.

UBT가 Target과 Build.cs 평가
→ Module 의존성 그래프 구성
→ 모듈별 include·define·library 환경 생성
→ Producer 컴파일·링크
→ Consumer가 Producer Public Header 컴파일
→ 최종 Editor 또는 Game Target 링크

Producer 하나만 빌드해서 성공했다고 Public 계약이 완성된 것은 아닙니다. Consumer가 실제 Public 헤더를 Include하는 Target까지 빌드해야 누락된 전이 의존성을 찾을 수 있습니다.

4. 단계별 실습​

ReusableInteraction.Build.cs
using UnrealBuildTool;

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

PublicDependencyModuleNames.AddRange(new[]
{
"Core",
"CoreUObject",
"Engine"
});

PrivateDependencyModuleNames.AddRange(new[]
{
"DeveloperSettings"
});
}
}
DataGuardEditor.Build.cs
using UnrealBuildTool;

public class DataGuardEditor : ModuleRules
{
public DataGuardEditor(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PrivateDependencyModuleNames.AddRange(new[]
{
"Core", "CoreUObject", "Engine",
"UnrealEd", "DataValidation", "AssetRegistry",
"ToolMenus", "Slate", "SlateCore", "PropertyEditor"
});
}
}

DataGuard는 외부 모듈이 Include할 Public 계약을 만들지 않으므로 Editor 의존성을 모두 Private으로 유지할 수 있습니다. ReusableInteraction의 공개 UCLASS·UINTERFACE가 UObject와 Actor 타입을 노출하므로 CoreUObject·Engine은 Public입니다. 실제 공개 Header를 줄이면 일부를 Private으로 옮길 수 있습니다.

Build.cs에서 각 줄을 판단하는 방법​

  1. ModuleRules 생성자는 게임 실행 중 호출되는 함수가 아니라 UBT가 빌드 구성을 계산할 때 실행하는 규칙입니다.
  2. Core, CoreUObject, Engine을 관습적으로 복사하지 말고 Public Header와 CPP에서 실제 사용하는 타입을 역추적합니다.
  3. DeveloperSettings를 ReusableInteraction의 CPP에서만 사용한다면 Private입니다. Public Header에 UDeveloperSettings 하위 타입을 직접 공개하면 계약을 다시 검토해야 합니다.
  4. UnrealEd, ToolMenus, PropertyEditor는 Editor 전용 모듈입니다. Runtime 모듈에 넣지 않고 DataGuardEditor의 Private 구현 안에서 끝냅니다.
  5. 의존성을 옮긴 뒤에는 Unity Build가 우연히 제공한 include에 기대지 않는지 깨끗한 빌드 또는 non-unity 진단도 고려합니다.

최소 재현: Public 값 타입이 의존성을 전파하는 경우​

ReusableInteraction의 공개 헤더가 GameplayTag 값을 소유한다고 가정합니다.

Public/InteractionRule.h
#pragma once

#include "GameplayTagContainer.h"

struct FInteractionRule
{
FGameplayTag RequiredTag;
};

이 헤더를 Consumer가 Include하려면 ReusableInteraction의 Public 의존성에 GameplayTags가 필요합니다.

ReusableInteraction.Build.cs · Public 추가
PublicDependencyModuleNames.AddRange(new[]
{
"Core",
"CoreUObject",
"Engine",
"GameplayTags"
});

GameplayTag 사용을 CPP 구현 내부로 감추고 Public Header에서 타입을 더 이상 노출하지 않는다면 GameplayTags를 Private으로 내릴 수 있습니다. 단순히 빌드가 된다는 이유가 아니라 공개 계약의 타입 노출이 사라졌는지 먼저 확인합니다.

5. 코드가 동작하는 이유​

UBT는 ModuleRules를 실행해 모듈 그래프와 컴파일 환경을 만듭니다. Public 의존성은 소비 모듈에 전파되고 Private 의존성은 구현 내부에서 끝납니다. 소스 코드의 C++ public: 접근 지정자와 Build.cs의 Public 의존성은 다른 개념입니다.

6. 자주 하는 실수와 해결법​

7. 직접 실습​

실습 목표​

의존성 하나를 실제 Header·CPP 사용 지점까지 추적하고, Public과 Private을 바꾼 뒤 Producer와 Consumer 빌드 결과로 계약을 검증합니다.

시작 전 상태​

현재 ReusableInteraction과 DataGuardEditor가 Development Editor Target에서 빌드되는지 확인하고 결과 로그를 보관합니다. Build.cs와 공개 헤더를 Git으로 되돌릴 수 있어야 합니다.

1단계: 따라 하기​

두 Build.cs의 각 모듈 이름 옆에 이를 요구하는 실제 Header 또는 CPP 파일을 기록합니다. 근거 파일을 찾지 못한 의존성은 바로 삭제하지 말고 검색 범위와 동적 로드 여부를 추가 확인합니다.

2단계: 값 바꿔 보기​

위 InteractionRule.h를 Public에 두고 GameplayTags를 Private에만 추가한 경우 Producer와 Consumer 중 어느 빌드에서 실패하는지 기록합니다. 그다음 Public으로 옮겨 두 Target이 모두 성공하는지 확인합니다. 정확한 오류 문구는 엔진 버전과 빌드 캐시에 따라 헤더 또는 링크 오류로 나타날 수 있습니다.

3단계: 직접 적용​

Public Header에서 포인터·참조로만 쓰는 클래스 하나를 Forward Declaration으로 바꾸고 include를 CPP로 옮깁니다. 해당 타입의 모듈을 Private으로 내릴 수 있는지 공개 계약을 검토한 뒤 Producer와 Consumer를 모두 빌드합니다.

4단계: 스스로 확인​

막혔을 때​

증상원인 후보확인과 해결
Header not found모듈 의존성 누락 또는 잘못된 includeAPI 문서의 Header·Module과 실제 엔진 헤더 위치를 확인합니다.
Producer는 성공, Consumer는 실패Public Header 타입의 전이 의존성 누락값 타입을 노출하는 모듈을 Public에 두거나 계약을 감춥니다.
Runtime 패키징에서 UnrealEd Symbol 오류Editor 모듈이 Runtime에 혼입Editor 코드를 별도 Editor 모듈로 이동하고 Runtime 의존성을 제거합니다.
의존성 제거 뒤 가끔만 성공Unity Build 또는 PCH의 우연한 include깨끗한 빌드와 명시적 include로 재현합니다.

8. 이해 점검 질문 3개​

9. 핵심 요약​

다음 강의 연결​

다음 강의: Public·Private 폴더와 헤더 공개 범위에서는 Build.cs 의존성 분류의 원인이 되는 실제 Header 배치와 최소 공개 API를 설계합니다.

MINI QUIZ

.Build.cs의 역할과 모듈 의존성 선언 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“.Build.cs의 역할과 모듈 의존성 선언” 실습 결과를 확인할 때 적용해야 할 설명은 무엇인가요?
  2. 문제 2“.Build.cs의 역할과 모듈 의존성 선언”의 작업 기준으로 ‘IncludePaths를 수동으로 무제한 추가’을 진단하거나 바로잡은 선택은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

4강. .Build.cs의 역할과 모듈 의존성 선언 미완료 상태