영상을 불러오지 못했습니다

UE4 다른 모듈의 UInterface 캐스팅에서 LNK1120이 발생할 때

844 단어
4 분
UE4 다른 모듈의 UInterface 캐스팅에서 LNK1120이 발생할 때

이 글은 2021년 7월, Unreal Engine 4.26.2에서 겪은 문제를 당시 엔진 구조를 기준으로 다시 검토해 옮긴 기록이다. 이후 엔진 버전의 동작을 소급해서 적용하지 않았다.

Rider의 Unreal 클래스 생성 기능으로 UInterface를 만든 뒤, 그 인터페이스를 다른 게임 모듈에서 사용했다. 헤더 include와 컴파일은 정상이었지만 링크 단계에서 다음 오류가 발생했다.

unresolved external symbol
"private: static class UClass * __cdecl UDefaultAI::GetPrivateStaticClass(void)"
referenced in function ...
LNK1120: 1 unresolved externals

Build.cs의 모듈 의존성은 이미 설정되어 있었다. 의존 모듈을 찾지 못한 것이 아니라, UDefaultAI가 들어 있는 DLL에서 reflection용 심볼을 외부로 내보내지 않은 탓이었다.

문제가 된 선언#

UInterface를 만들면 실제로는 두 C++ 타입이 생긴다.

  • UDefaultAI: Unreal reflection에 등록되는 UObject 쪽 타입
  • IDefaultAI: 게임플레이 인터페이스를 선언하는 native C++ 타입

문제가 된 코드는 모듈 API 매크로가 IDefaultAI에만 붙어 있었다.

#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "DefaultAI.generated.h"
UINTERFACE()
class UDefaultAI : public UInterface
{
GENERATED_BODY()
};
class AI_API IDefaultAI
{
GENERATED_BODY()
public:
virtual class AAIController* GetAIController() const = 0;
};

다른 모듈에서 Cast<IDefaultAI>(Object) 같은 reflection 기반 경로를 사용하려면 UDefaultAI::StaticClass()와 그 내부의 GetPrivateStaticClass() 심볼도 필요하다. 그러나 UDefaultAI에는 AI_API가 없었고, modular build의 다른 DLL은 해당 심볼을 가져올 수 없었다.

두 타입 모두 export한다#

UDefaultAIIDefaultAI 양쪽에 인터페이스가 정의된 모듈의 API 매크로를 붙인다.

#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "DefaultAI.generated.h"
UINTERFACE()
class AI_API UDefaultAI : public UInterface
{
GENERATED_BODY()
};
class AI_API IDefaultAI
{
GENERATED_BODY()
public:
virtual class AAIController* GetAIController() const = 0;
};

당시 UE4의 모듈 API 매크로는 modular build의 빌드 대상에 따라 바뀌었다.

  • 타입을 정의하는 모듈을 빌드할 때: __declspec(dllexport)
  • 타입을 사용하는 모듈을 빌드할 때: __declspec(dllimport)
  • monolithic build일 때: 빈 매크로

이 때문에 오류는 Editor와 같은 DLL 구성에서만 드러나고, monolithic target에서는 우연히 통과할 수 있다. 특정 빌드에서 통과했다는 사실만으로 export 선언이 올바르다고 판단하면 안 된다.

Build.cs 의존성도 별도로 필요하다#

API 매크로와 모듈 의존성은 서로 대체 관계가 아니다.

PublicDependencyModuleNames.AddRange(new[]
{
"Core",
"CoreUObject",
"Engine",
"AI",
});
  • Build.cs는 어떤 모듈의 include·link 환경을 사용할지 정한다.
  • AI_API는 그 DLL에서 어떤 클래스와 함수를 외부에 공개할지 정한다.

헤더 경로가 보이는데 GetPrivateStaticClass, vtable 또는 함수 구현에서 unresolved external이 발생한다면 아래 순서로 확인한다.

  1. 사용하는 모듈의 Build.cs에 정의 모듈이 들어 있는가?
  2. 외부에서 쓰는 클래스·함수에 *_API 매크로가 있는가?
  3. UInterface라면 U... 타입과 I... 타입을 모두 확인했는가?
  4. 선언과 구현의 함수 signature가 정확히 같은가?
  5. Editor DLL build와 packaged monolithic build의 차이에 가려진 문제는 아닌가?

이 사례에서는 3번이 원인이었다. 자동 생성된 코드라도 모듈 경계를 넘는 타입이라면 export 범위를 직접 검토해야 한다.

참고 자료#

글 공유하기

이 글이 도움이 되셨다면 다른 사람과 공유해 주세요!

UE4 다른 모듈의 UInterface 캐스팅에서 LNK1120이 발생할 때
https://velog.io/@hon454/캐스팅-시-LNK1120-에러-발생
작성자
Jihoon Jeon
게시일
2021-07-19
라이선스
CC BY-NC-SA 4.0

댓글

Profile Image of the Author
Jihoon Jeon
안녕하세요! 서브컬처와 자전거를 사랑하는 개발자 전지훈입니다.
공지사항
제 블로그에 오신 것을 환영합니다! 예시 공지입니다.
카테고리
태그
최신 일상
사이트 통계
게시글
46
카테고리
10
태그
139
총 단어 수
103,271
운영 일수
0
최근 활동
0일 전
사이트 정보
빌드 플랫폼
GitHub Actions
블로그 버전
Firefly v6.16.3
라이선스
CC BY-NC-SA 4.0