1

I am trying to import a third party library for UE4 and use it in an actor. The UE4 documentation recommends creating a plugin to accomplish this and provides an auto generated template which i am trying to test currently.

I have created a blank C++ UE4 Project with a new third party custom plugin and an actor class in which to use the plugin/library.

This is my build.cs file for the main project:


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

using UnrealBuildTool;

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

        PrivateDependencyModuleNames.AddRange(new string[] { "CustomTestPlugin" });
        PublicIncludePaths.AddRange(new string[] { "../Plugins/CustomTestPlugin/Source/CustomTestPlugin/Public" });
        // Uncomment if you are using Slate UI
        // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });

        // Uncomment if you are using online features
        // PrivateDependencyModuleNames.Add("OnlineSubsystem");

        // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
    }
}

and have included the plugin in the actor cpp file using

#include "CustomTestPlugin.h"

as well as instantiating it in the same file:

    FCustomTestPluginModule pluggin = FCustomTestPluginModule::FCustomTestPluginModule();

when I compile without the above it builds fine but when i declare the pluggin variable it gives the following error:

TestActor.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl FCustomTestPluginModule::StartupModule(void)" (?StartupModule@FCustomTestPluginModule@@UEAAXXZ)

CustomTestPlugin.h is as follows:

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

#pragma once

#include "Modules/ModuleManager.h"

class FCustomTestPluginModule : public IModuleInterface
{
public:

    /** IModuleInterface implementation */
    //FCustomTestPluginModule();
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;

private:
    /** Handle to the test dll we will load */
    void*   ExampleLibraryHandle;
};

and the cpp file:

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

#include "CustomTestPlugin.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#include "CustomTestPluginLibrary/ExampleLibrary.h"

#define LOCTEXT_NAMESPACE "FCustomTestPluginModule"


//FCustomTestPluginModule::FCustomTestPluginModule() {
//  UE_LOG(LogTemp, Warning, TEXT("CustomPluConstructed"));
//}

void FCustomTestPluginModule::StartupModule()
{
    // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module

    // Get the base directory of this plugin
    FString BaseDir = IPluginManager::Get().FindPlugin("CustomTestPlugin")->GetBaseDir();

    // Add on the relative location of the third party dll and load it
    FString LibraryPath;
#if PLATFORM_WINDOWS
    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/CustomTestPluginLibrary/Win64/ExampleLibrary.dll"));
#elif PLATFORM_MAC
    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/CustomTestPluginLibrary/Mac/Release/libExampleLibrary.dylib"));
#elif PLATFORM_LINUX
    LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/CustomTestPluginLibrary/Linux/x86_64-unknown-linux-gnu/libExampleLibrary.so"));
#endif // PLATFORM_WINDOWS

    ExampleLibraryHandle = !LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;

    if (ExampleLibraryHandle)
    {
        // Call the test function in the third party library that opens a message box
        ExampleLibraryFunction();
    }
    else
    {
        FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load example third party library"));
    }
}

void FCustomTestPluginModule::ShutdownModule()
{
    // This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
    // we call this function before unloading the module.

    // Free the dll handle
    FPlatformProcess::FreeDllHandle(ExampleLibraryHandle);
    ExampleLibraryHandle = nullptr;
}

#undef LOCTEXT_NAMESPACE
    
IMPLEMENT_MODULE(FCustomTestPluginModule, CustomTestPlugin)


any help in resolving this would be greatly appreciated thanks!

Tzanker
  • 93
  • 1
  • 6
  • 2
    How did you link all that? – πάντα ῥεῖ Jan 14 '22 at 00:30
  • Maybe need to add the plugin in projectDefaults.ini – Jay Jan 14 '22 at 00:55
  • 1
    Does this answer your question? [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Ken White Jan 14 '22 at 01:10
  • 1
    You're not supposed to ever manually instantiate your module. If you need a reference to it you do so through `FModuleManager` – Rotem Jan 14 '22 at 16:54
  • Awesome I'll give that a look! do you have @Rotem do you have any good sources for using this? the UE4 Documentation isn't fantastic. – Tzanker Jan 14 '22 at 18:03
  • 1
    This course might be helpful https://www.unrealengine.com/en-US/onlinelearning-courses/best-practices-for-creating-and-using-plugins – Rotem Jan 14 '22 at 18:37
  • 1
    There are very few reasons for needing to get a reference to your module. Maybe if you explain what you're trying to achieve I can tell you what the typical workflow would be for that. – Rotem Jan 14 '22 at 18:37
  • That would be awesome! My overarching goal is to just do a little web scraping in the background. To do that I'd like to use the libraries libCPR and gumbo. I don't have a good grasp on how to implement them in UE4 or if that's something even worth trying. Thanks a ton @Rotem! – Tzanker Jan 14 '22 at 18:59
  • sorry and just to be a bit clearer my plan is to use the library functions inside an actor, the reason i chose to do this with plugins was due to a [recommendation](https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/BuildTools/UnrealBuildTool/ThirdPartyLibraries/) i found in the documentation telling me to use plugins for third party libraries. – Tzanker Jan 14 '22 at 19:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241073/discussion-between-tzanker-and-rotem). – Tzanker Jan 14 '22 at 19:21

1 Answers1

1

You should not need to instantiate your module manually. The module is loaded and instantiated by the engine at startup if it is referenced in your project.

If for some reason you need to get a reference to your module's singleton, you can use

FModuleManager::LoadModuleChecked<FYourModuleType>("YourModule");
Rotem
  • 21,452
  • 6
  • 62
  • 109