Unresolved external symbol error with Module

Hello everyone,

I have one unresolved external error.

`

Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol “public: __cdecl World::~World(void)” (??1World@@QEAA@XZ) referenced in function “protected: virtual void __cdecl ACreoComposition::BeginPlay(void)” (?BeginPlay@ACreoComposition@@MEAAXXZ) MyGame C:\Users\Austin\Documents\GitHub\MyGame\Intermediate\ProjectFiles\MyGameComposition.cpp.obj 1 `

I have a class called World (not a uclass) that exists in a separate module called MyModule.

Source/AEF/Public/World.h

#pragma once

#include "Engine.h"

	//class Entity;

	class World {

	public:
		World(int a) {  }
		~World();

		//Entity createEntity(AActor* actor);
		//void releaseEntity(Entity&);
		//Entity Get(uint32 eid);

	private:
		//UObject* uworld;

		//struct EntityAttribute {
		//	uint32 eid;

		//};
	};

The constructor resolves but the destructor will not resolve. If I define the destructor inside of the header file then no errors are thrown. From what I can tell anything that is implemented in the World.cpp file will throw a unresolved external error. For example, if I define ~World(); as ~World() { } then there are no errors and it compiles fine.

My guess is that something is wrong with the build.cs file.

Source/AEF/AEF.Build.cs

using UnrealBuildTool;
using System.IO;

/// <summary>
/// Build module rules.
/// </summary>
public class AEF : ModuleRules {
   
    public AEF(ReadOnlyTargetRules target) : base(target)
    {
        // Public module names that this module uses.
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

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

        // The path for the header files
        PublicIncludePaths.AddRange(new string[] {"AEF/Public"});
        
        // The path for the source files
        PrivateIncludePaths.AddRange(new string[] {"AEF/Private"});

        LoadLua(target);
   }

    private bool LoadLua(ReadOnlyTargetRules target)
    {
        bool isLibSupported = false;

        if(target.Platform == UnrealTargetPlatform.Win64 || target.Platform == UnrealTargetPlatform.Win32)
        {
            isLibSupported = true;

            string libPath = Path.GetFullPath(Path.Combine(ModuleDirectory));

            switch(target.Platform)
            {
                case UnrealTargetPlatform.Win64:
                    PublicAdditionalLibraries.Add(libPath + "\\ThirdParty\\lua-5.3.3\\libraries\\win64\\lua53.lib");
                    break;
                case UnrealTargetPlatform.Win32:
                    PublicAdditionalLibraries.Add(libPath + "\\ThirdParty\\lua-5.3.3\\libraries\\win32\\lua53.lib");
                    break;
            }

            PublicIncludePaths.Add("AEF/ThirdParty/lua-5.3.3/include");
        }

        Definitions.Add(string.Format("WITH_LUA_BINDING={0}", isLibSupported ? 1 : 0));

        return isLibSupported;
    }
}

MyGame.Build.cs

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

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

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

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

And here is a segment of MyGame.uproject

{
			"Name": "MyGame",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
        "Engine",
        "AEF"
			]
},
{
			"Name": "AEF",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"Engine"
			]
		}

I didn’t realize that you need to mark non uclass’s with AEF_API.

To fix this issue I went to World.h and changed class world { ... } to class AEF_API World { ... }.

I found this answer helpful.

I still do not understand what AEF_API does or why it is required so some insight into that would be helpful. I also tested putting this class into a namespace called “aef” and it still worked. So I guess any class that is going to have its methods called from the game module will need the AEF_API for it to work properly.

ModuleName_API controls whatever to place extern in this spot, extern turns decleration to a reference to outside module (dll), this is not needed if compilers build current module so it needs to be extern need to be removed in specific cases, that why macro is used. In more simple sense ModuleName_API actually makes class accessible to other modules, if you don’t place that you will have linker errors while trying to access it from outside.