In this tutorial, my goal is to create a plugin that works with external third-party library (using dll). Besides, I want to make sure that this plugin will still work well when packaging an executable and fixing some path issues.
NOTES: All tested in Unreal 5.0.3
Step 1: Creating a Third-party Library.
I will create this third party library on my own.
At first, I create a blank template C++ UE project.

Then I create a new basic level and set it up a main map.

I make a directory called External/MyMathLib
. In this directory, I will create a Visual Studio 2022 project to build DLL file using premake5. You can also use CMake or Visual Studio to create this DLL file.

This library is fairly simple, only for debugging.
MyMathLib.h
:
#pragma once #if defined(DIST_DLL) #define HYL_DLL __declspec(dllexport) #else #define HYL_DLL #endif class HYL_DLL MyMathLib { public: static float Add(float a, float b); };
MyMathLib.cpp
:
#include "MyMathLib.h" float MyMathLib::Add(float a, float b) { return a + b; }
All right. After building, I can get MyMathLib.lib
and MyMathLib.dll
for unreal.

Step 2: Creating a Plugin that Use This Third-party Library
Create a blank plugin called MyMath:

In the Plugins/MyMath/Source
folder, create a folder called ThirdParty/MyMathLib
. Copy the include
and lib
folders we have built before. Then create a file called MyMathLib.Build.cs
.

MyMathLib.Build.cs
:
using System; using System.IO; using UnrealBuildTool; public class MyMathLib : ModuleRules { public MyMathLib(ReadOnlyTargetRules Target) : base(Target) { Type = ModuleType.External; PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "include")); PublicAdditionalLibraries.Add(Path.Combine(ModuleDirectory, "lib", "MyMathLib.lib")); } }
Copy the MyMathLib.dll
file to the plugin MyMath
‘s binaries folder:

Create a new C++ Actor class called MyMathDemoActor
in the MyMath
plugin. This class will use the third-party library’s function.

Then drag this Actor class into the scene to make it function.

In the MyMath.Build.cs
file, add its private dependency to call MyMathLib’s function:
PrivateDependencyModuleNames.AddRange( new string[] { "CoreUObject", "Engine", "Slate", "SlateCore", // ... add private dependencies that you statically link with here ... "MyMathLib" } );
After updating the visual studio project files, we can include and use MyMathLib like this in the MyMathDemoActor.cpp
file:
// Fill out your copyright notice in the Description page of Project Settings. #include "MyMathDemoActor.h" #include "MyMathLib.h" // Sets default values AMyMathDemoActor::AMyMathDemoActor() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; } // Called when the game starts or when spawned void AMyMathDemoActor::BeginPlay() { Super::BeginPlay(); float Sum = MyMathLib::Add(1.0, 2.0); if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Green, TEXT("Sum: ") + FString::SanitizeFloat(Sum)); } // Called every frame void AMyMathDemoActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); }
After lauching the editor, and hit play, we can see this debug message. It works.

Step 3: Packaging with a Third-party library
But what if we were packaging a game? Can we succeed?
When packaging a game, there are two methods: How To Build Package And Export Your Game – Unreal Engine Tutorial and How to Package Games/Projects with UNREAL FRONTEND.
I like the latter one. The only difference here is that I need to show the debug message, so I set the build configuration to be DebugGame. See the notes below.
NOTE: How to Print Message in Packaging Build
Project Settings->Packaging->Project->Build Configuration->DebugGame
Then, if use Project Launcher to package, build configuration must also be DebugGame in custom lauch profiles.
After doing that, I can use both GEngine->AddOnScreenDebugMessage
and UE_LOG
to show debug messages.
Automatically Copying DLLs: a Better Way
Packaging will succeed, but unfortunately the packaged execuable can’t run.
It says it can’t find the MyMathLib.dll file. You can copy it to the executable location, but It’s kind of annoying.
I have found a better to solve this issue. In the MyMathLib.Build.cs file, add this line:
RuntimeDependencies.Add("$(BinaryOutputDir)/MyMathLib.dll", Path.Combine(ModuleDirectory, "lib", "MyMathLib.dll"));
This will automatically copy dll file to the BinaryOutDir directory. It will work both in editor and packaging.
Bonus: Packaging with a Plugin that Contains an External Files
Sometimes, there is a need to write a plugin that has its own non-asset external files to read(like a TXT file). So how to manage it and how to package?
I have one solution here. Take Third-Party Libraries as a reference.
Find the plugin’s Build.cs file, for this example MyMath.Build.cs. Add this line:
// you can also use StagedFileType.NonUFS, keeping it as part of the loose filesystem. RuntimeDependencies.Add(Path.Combine(PluginDirectory, "Extras/..."), StagedFileType.UFS);
NOTES: for some binary format, StagedFileType.UFS
seems not to work, you can change to use StagedFileType.NonUFS
.
Then in the plugin folder, create this folder and add a TXT file.

hello.txt
:
hello MyMath!
Then add some testing code to MyMathDemoActor.cpp
:
static void PrintTextFile(const FString& Path) { // We will use this FileManager to deal with the file. IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile(); FString FileContent; // Always first check if the file that you want to manipulate exist. if (FileManager.FileExists(*Path)) { // We use the LoadFileToString to load the file into if (FFileHelper::LoadFileToString(FileContent, *Path, FFileHelper::EHashOptions::None)) { if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Green, FileContent); } else { if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Red, TEXT("FileManipulation: Did not load text from file.")); } } else { if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Red, TEXT("FileManipulation: ERROR: Can not read the file because it was not found.")); } } // Called when the game starts or when spawned void AMyMathDemoActor::BeginPlay() { // some code... const FString Path = FPaths::Combine(FPaths::ProjectPluginsDir(), TEXT("MyMath/Extras/hello.txt")); if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Yellow, TEXT("Path: ") + Path); PrintTextFile(Path); }
After that, this plugin seems to work well both in editor and packaging build.

That’s all. For the whole project source code, please visit this Github repository.
References
- How To Build Package And Export Your Game – Unreal Engine Tutorial
- How to Package Games/Projects with UNREAL FRONTEND
- Unreal Engine How To Debug Packaged Projects
- Debugging a Packaged Build
- Debugging How To Debug Packaged Games
- UE Documentation: Packaging Projects
- Packaged Game Paths, Obtain Directories Based on Executable Location
- Adding custom third-party library to plugin from scratch
- Plugins
- Third-Party Libraries
- Packaging game – custom files
- Package non-asset file and load them at runtime