📚 Lesson 8.2: Integrating Third-Party Libraries
Sometimes the code you need already exists — a physics solver, an analytics SDK, a JSON parser, a networking library. Linking external C++ into Unreal is a superpower Blueprint simply doesn't have, and it's all done through the .Build.cs you now understand.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Distinguish header-only, static, and dynamic (DLL) libraries
- Add include paths and link libraries via
.Build.cs - Stage a runtime DLL so it ships with the game
- Wrap third-party headers to avoid Unreal warnings-as-errors
- Decide where third-party code lives in the project
Estimated Time: 60 minutes
Engine Version: Unreal Engine 5.8
In This Lesson
Three Kinds of Library
How you integrate a library depends on how it's distributed. There are three forms, in increasing integration effort:
(just .h files)"] --> He["Add include path. Done."] S["Static library
(.lib / .a)"] --> Se["Include path + link the lib"] D["Dynamic library
(.dll / .so / .dylib)"] --> De["Include path + link import lib + SHIP the runtime binary"]
📖 Where third-party code lives
Convention is a ThirdParty/ folder — either under your project's Source/ or in a dedicated module/plugin. Inside, keep the library's include/ headers and its lib/ binaries organized by platform. Keeping it self-contained makes the .Build.cs paths clean and the dependency obvious to teammates.
Header-Only Libraries
The easiest case — a library that's entirely in headers (many modern C++ libs are). You just tell the build where the headers are.
public class MyModule : ModuleRules
{
public MyModule(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(new string[]
{ "Core", "CoreUObject", "Engine" });
// Point the compiler at the header-only library's include folder.
PublicIncludePaths.Add(
Path.Combine(ModuleDirectory, "ThirdParty", "somelib", "include"));
}
}
// Then just include and use it in your .cpp:
#include "somelib/somelib.hpp"
void UMyClass::DoThing()
{
somelib::Widget w; // the third-party API, now available
}
✅ ModuleDirectory keeps paths portable
Use Path.Combine(ModuleDirectory, ...) rather than an absolute path — ModuleDirectory resolves to wherever the module is on any machine, so the project builds for every teammate and on CI without edits. Absolute paths are a classic "works on my machine" trap.
Static & Dynamic Libraries
A precompiled library adds a linking step: you point at the headers and the library binary. For a static lib, that's all — it gets baked into your module's binary.
public MyModule(ReadOnlyTargetRules Target) : base(Target)
{
// ... dependencies ...
string ThirdParty = Path.Combine(ModuleDirectory, "ThirdParty", "physicslib");
// 1) Where the headers are:
PublicIncludePaths.Add(Path.Combine(ThirdParty, "include"));
// 2) The library to link (platform-specific):
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PublicAdditionalLibraries.Add(
Path.Combine(ThirdParty, "lib", "Win64", "physicslib.lib"));
}
}
⚠️ Match the platform and the runtime
Precompiled libraries are platform- and often toolchain-specific. A Win64 .lib won't link on Mac; a lib built with a different MSVC runtime can cause obscure link errors. Branch on Target.Platform and use libraries built for the same compiler Unreal uses. This is the fiddliest part of third-party integration — expect to consult the library's build docs.
Shipping a DLL
A dynamic library (DLL) needs three things: the headers, an import library to link against, and — critically — the DLL itself staged next to the packaged game so it loads at runtime. Miss the last step and it works in the editor but crashes in a packaged build.
if (Target.Platform == UnrealTargetPlatform.Win64)
{
string Bin = Path.Combine(ThirdParty, "bin", "Win64");
// Link against the import library at build time:
PublicAdditionalLibraries.Add(Path.Combine(ThirdParty, "lib", "Win64", "netlib.lib"));
// Tell Unreal about the DLL that must load at runtime:
string Dll = Path.Combine(Bin, "netlib.dll");
PublicDelayLoadDLLs.Add("netlib.dll");
// Stage the DLL into the packaged build's binaries:
RuntimeDependencies.Add(
"$(BinaryOutputDir)/netlib.dll", Dll);
}
📖 Why RuntimeDependencies matters
RuntimeDependencies.Add tells the packaging system to copy the DLL into the shipped game. Without it, the editor finds the DLL (it's in your source tree) but the packaged game doesn't — the "works in editor, crashes when packaged" bug. PublicDelayLoadDLLs plus loading the DLL explicitly (via FPlatformProcess::GetDllHandle) gives you control over exactly when it loads. This is the single most-missed step in DLL integration.
Taming Warnings
Unreal compiles your code with strict warnings (often warnings-as-errors). Third-party headers rarely meet Unreal's bar, so including them raw can fail the build. Wrap them in Unreal's third-party include guards.
// Wrap noisy third-party includes so their warnings don't break your build:
#include "Windows/AllowWindowsPlatformTypes.h" // (Windows-specific headers)
THIRD_PARTY_INCLUDES_START
#include "somelib/somelib.hpp"
THIRD_PARTY_INCLUDES_END
#include "Windows/HideWindowsPlatformTypes.h"
✅ The general pattern
THIRD_PARTY_INCLUDES_START/_END temporarily relax Unreal's warning settings around external headers. The Windows platform-types guards additionally prevent clashes between Windows API macros (like TEXT, GetObject) and Unreal's. Wrap third-party includes this way and a lot of mysterious build failures simply disappear. Keep third-party usage in .cpp files where possible so these includes don't leak into your headers.
Hands-on Exercise & Quiz
🏋️ Exercise: Plan an integration
Objective: Map out integrating a hypothetical analytics SDK shipped as a Win64 DLL + headers.
- Where do the headers and binaries go in the project?
- List the
.Build.csadditions needed (include path, link, runtime). - What extra step makes it work in a packaged build, not just the editor?
- How would you include the SDK header without triggering warnings-as-errors?
✅ Answers
- 1. A
ThirdParty/analytics/folder withinclude/andbin/lib per-platform. - 2.
PublicIncludePaths.Add(include),PublicAdditionalLibraries.Add(.lib),PublicDelayLoadDLLs.Add("analytics.dll"). - 3.
RuntimeDependencies.Add(...)to stage the DLL into the packaged binaries. - 4. Wrap the include in
THIRD_PARTY_INCLUDES_START/END(plus Windows platform-type guards).
🎯 Quick Quiz
Question 1: A header-only library needs only:
Question 2: A DLL integration works in editor but crashes when packaged. Most likely you forgot:
Question 3: Third-party headers fail Unreal's warnings-as-errors. The fix:
Summary
🎉 Key Takeaways
- Integration effort scales with form: header-only (include path only) → static (+ link) → dynamic/DLL (+ stage at runtime).
- Add headers with
PublicIncludePathsand libs withPublicAdditionalLibraries, usingPath.Combine(ModuleDirectory, ...)for portability. - For DLLs,
RuntimeDependencies.Addstages the binary into the packaged game — the most-missed step ("works in editor, crashes packaged"). - Branch on
Target.Platform; match the library's platform and toolchain. - Wrap third-party includes in
THIRD_PARTY_INCLUDES_START/END(+ platform-type guards) to survive warnings-as-errors; keep usage in.cpp.
📚 Additional Resources
🚀 What's Next?
You can organize your modules and pull in external code. The module finale packages your work for reuse: writing a C++ plugin — a self-contained bundle you can drop into any project or share.
🎉 Lesson complete!
External code links cleanly. Now let's package your own for reuse.