Unable to reference interface defined in a module (LNK2019 unresolved external symbol)

Hi all! I’m having some trouble getting custom modules working, for reference I’m using UE 5.2, jetbrains rider, vs 2019.

I’ve been trying to structure my code using modules but it seems to break whenever I try to import anything into my core game module with an unresolved external symbol error:

LNK2019: unresolved external symbol "private: static class UClass * __cdecl UInteractable::GetPrivateStaticClass(void)" (?GetPrivateStaticClass@UInteractable@@CAPEAVUClass@@XZ) referenced in function "private: void __cdecl AMainGamePlayerController::ClearLookAtTarget(void)" (?ClearLookAtTarget@AMainGamePlayerController@@AEAAXXZ)

My relevant directory structure is as follows:

Source/
  MainGame/
    Controllers/
      Player/
        MainGamePlayerController.h
        MainGamePlayerController.cpp
    
  InteractionModule/
    Public/
      Core/
        InteractionModule.h
        InteractionModule.cpp
      Interfaces/
        Interactable.h
        Interactable.cpp

and the relevant files look like this:

MainGame.Build.cs

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class MainGame : ModuleRules
{
	public MainGame(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
		
		PrivateDependencyModuleNames.AddRange(new string[] {"InteractionModule"});
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" });
	}
}

MainGame.uproject

{
	"FileVersion": 3,
	"EngineAssociation": "5.2",
	"Category": "",
	"Description": "",
	"Modules": [
		{
			"Name": "MainGame",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"Engine"
			]
		},
		{
			"Name": "InteractionModule",
			"Type": "Runtime"
		}
	],
	"Plugins": [
		{
			"Name": "ModelingToolsEditorMode",
			"Enabled": true,
			"TargetAllowList": [
				"Editor"
			]
		}
	]
}

InteractionModule.Build.cs

using UnrealBuildTool;

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

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

        PrivateDependencyModuleNames.AddRange(
            new string[]
            {
                "CoreUObject",
                "Engine",
                "Slate",
                "SlateCore"
            }
        );
    }
}

InteractionModule.h

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class FInteractionModule : public IModuleInterface
{
public:
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;
};

Interactable.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Interactable.generated.h"

// This class does not need to be modified.
UINTERFACE(BlueprintType)
class UInteractable : public UInterface
{
	GENERATED_BODY()
};

/**
 * Common interface for objects which can be interacted with
 */
class INTERACTIONMODULE_API IInteractable
{
	GENERATED_BODY()

public:
	/*
	 */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interaction")
	bool CanInteract();

	/*
	 */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interaction")
	bool ShouldInteract();

	/*
	 */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Highlight")
	bool IsHighlightable();
	
	/*
	 */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interaction")
	void Interact();
	
	/*
	 */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Highlight")
	void Highlight();

	/*
	 */
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Highlight")
	void UnHighlight();
};

MainGamePlayerController.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MainGamePlayerController.h"

#include "InteractionModule/Public/Interfaces/Interactable.h"
#include "Kismet/KismetMathLibrary.h"

AMainGamePlayerController::AMainGamePlayerController()
{
	LookAtQueryParams.AddIgnoredActor(GetPawn());
	LookAtQueryParams.bTraceComplex = false;
}

void AMainGamePlayerController::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	UpdateLookAtTarget();
}


#pragma region perception

void AMainGamePlayerController::UpdateLookAtTarget()
{
	FHitResult HitResult;
	BuildLookAtTrace(HitResult);

	if (HitResult.IsValidBlockingHit())
	{
		const auto Target = HitResult.GetActor();
		if (IsValid(Target))
		{
			SetLookAtTarget(*Target);
		}
		else
		{
			ClearLookAtTarget();
		}
	}
	else
	{
		ClearLookAtTarget();
	}
}

void AMainGamePlayerController::BuildLookAtTrace(FHitResult& OutHitResult) const
{
	FVector OriginLocation;
	FRotator OriginRotation;
	
	GetPlayerViewPoint(OriginLocation, OriginRotation);

	const FVector EndLocation = UKismetMathLibrary::GetForwardVector(OriginRotation) * MaxLookAtDistance + OriginLocation;
	
	ActorLineTraceSingle(OutHitResult, OriginLocation, EndLocation, ECC_Visibility, LookAtQueryParams);
}

void AMainGamePlayerController::SetLookAtTarget(AActor& NewLookAtTarget)
{
	if (&NewLookAtTarget != LastLookedAtTarget.Get())
	{
		ClearLookAtTarget();
		TryLookAtInteractable(NewLookAtTarget);
		LastLookedAtTarget = &NewLookAtTarget;
	}
}

void AMainGamePlayerController::ClearLookAtTarget()
{
	TryLookAwayFromInteractable();
	LastLookedAtTarget = nullptr;
}

void AMainGamePlayerController::TryLookAtInteractable(AActor& LookAtTarget) const
{
	const auto Interactable = Cast<IInteractable, AActor>(&LookAtTarget);
	if (Interactable != nullptr && Interactable->IsHighlightable())
	{
		Interactable->Highlight();
	}
}

void AMainGamePlayerController::TryLookAwayFromInteractable() const
{
	const auto Interactable = Cast<IInteractable, AActor>(LastLookedAtTarget.Get());
	if (Interactable != nullptr && Interactable->IsHighlightable())
	{
		Interactable->UnHighlight();
	}
}

#pragma endregion perception

I’ve done the usual regeneration of project files a bazillion times it feels but no matter what I try this error remains… I can see the module being built with the solution, so it seems to be getting included correctly, so I suspect maybe my import is incorrect? Any help would be enormously appreciated as this has been giving me the run around for a few days now

1 Like

In case anyone runs into the in the future, I changed a couple of things and it now builds and works!

  1. add the MinimalAPI specifier to the UINTERFACE specifier
  2. rejig all the files to be in the unreal expected directory structure, ie.
Source/
  MainGame/
    Public/
      Controllers/
        Player/
          MainGamePlayerController.h
    Private/
      Controllers/
        Player/
          MainGamePlayerController.cpp
    
  InteractionModule/
    Public/
      Core/
        InteractionModule.cpp
      Interfaces/
        Interactable.cpp
    Private/
      Core/
        InteractionModule.cpp
      Interfaces/
        Interactable.cpp

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.