2018-09-21T18:17:15
Hai!
So Unreal has its own build system creatively titled UnrealBuildTool (or UBT for short). Taming UBT iiiisn't exactly the most fun thing to do, considering the severe lack of documentation on it (I've barely scratched the surface); so in this post I'll show you how I managed to add Assimp, a 3D model loading library, into Rolled Out! (Although the same advice should work for any library).
As a quick side note, I'm using UE 4.19, just in case stuff changes in future versions of the engine.
Project/
└───Source/
├───Project/
└───ThirdParty/
└───libassimp/
├───include/
├───lib/
├───libassimp.Build.cs
└───libassimp.cpp
(Note that the lib
prefix is not always required - I can't remember exactly why I put it there in the first place, but it's probably because it conflicted when I was implementing the game module later on in this post)
First of all, we need to obtain static (.lib files on Windows, .a on macOS/Linux) versions of the library we want to include into our project, as well as their headers. I chose to write some build scripts to compile Assimp from source and copy them into the libassimp
directory, however just placing pre-built versions in there and committing it to source control should be fine. Do note that if you're compiling this for macOS or Linux, your external library will need to link against Clang's C++ standard library (As UE4 uses Clang to build on those platforms) - this can be done by passing -stdlib=libc++
to your C++ compiler. When I tried against gcc's standard library, it worked until I tried to package the game, where I received all sorts of linker errors.
Edit from the future: UE4 now ships its own Clang toolchain on Linux, so you should probably consider using that to compile. I don't know what the situation is on macOS right now.
I've placed the static libs in lib/
, and headers in include/
.
Next up, we need to inform UnrealBuildTool of the existence of our library, and where to find it. Here, we write libassimp.Build.cs
, a small C# script which checks what platform we're compiling for, and sets PublicAdditionalLibraries
and PublicIncludePaths
appropriately.
using UnrealBuildTool;
using System;
public class libassimp : ModuleRules
{
public libassimp(ReadOnlyTargetRules Target) : base(Target)
{
// We neeed to depend on Core in order to implement our game module in the next step
PublicDependencyModuleNames.AddRange(new string[]{"Core"});
bAddDefaultIncludePaths = false;
if (Target.Platform == UnrealTargetPlatform.Win32)
{
Console.Error.WriteLine("Win32 platform not supported!");
Environment.Exit(1);
}
else if (Target.Platform == UnrealTargetPlatform.Win64)
{
PublicIncludePaths.Add(ModuleDirectory + "\\include");
PublicAdditionalLibraries.Add(ModuleDirectory + "\\lib\\assimp.lib");
PublicAdditionalLibraries.Add(ModuleDirectory + "\\lib\\IrrXML.lib");
PublicAdditionalLibraries.Add(ModuleDirectory + "\\lib\\zlibstatic.lib");
}
else if (Target.Platform == UnrealTargetPlatform.Mac)
{
PublicIncludePaths.Add(ModuleDirectory + "/include/");
PublicAdditionalLibraries.Add(ModuleDirectory + "/lib/libassimp.a");
PublicAdditionalLibraries.Add(ModuleDirectory + "/lib/libIrrXML.a");
}
else if (Target.Platform == UnrealTargetPlatform.Linux)
{
PublicIncludePaths.Add(ModuleDirectory + "/include/");
PublicAdditionalLibraries.Add(ModuleDirectory + "/lib/libassimp.a");
PublicAdditionalLibraries.Add(ModuleDirectory + "/lib/libIrrXML.a");
}
else
{
// Some other platform
Console.Error.WriteLine("Other target platforms not supported");
Environment.Exit(1);
}
}
}
Using this script, UBT will create dynamic libraries from the static ones, in addition to configuring include paths.
We also need to provide a .cpp file to implement our game module in. Thankfully this is quick-n-easy to create - just use the IMPLEMENT_GAME_MODULE
macro and pass it the name of the library.
#include <Runtime/Core/Public/Modules/ModuleManager.h>
IMPLEMENT_GAME_MODULE(FDefaultGameModuleImpl, libassimp)
libassimp.cpp
Now that we've gotten the new module and its implementation, we just need to add it to our game and we can start using it! First, we'll add it to our target files. In your project's Source/ folder should be a Project.Target.cs and ProjectEditor.Target.cs. Simply add your module name to the ExtraModuleNames
array for both files.
ExtraModuleNames.AddRange(new string[] {"Project", "libassimp"});
And finally, add it to your project's Build script. In Source/Project/Project.Build.cs, add the module name to the PublicDependencyModuleNames
array too.
PublicDependencyModuleNames.AddRange(new string[] {
"Core",
"CoreUObject",
"Engine",
"InputCore",
"Sockets",
"Networking",
"XmlParser",
// External dependencies
"libassimp" // <--- Our new entry
});
And with that, you should be good to go! Re-generate project files and start #including and using your new library.