Adding third-party dependency for Core

For my profiling work I needed to add a third-party dependency to /Engine/Source/Runtime/Core/Public/Stats/Stats2.h. I was hoping that by adding my third-party dependency (which already has a proper buid file) to Core.Build.cs using the AddThirdPartyPrivateStaticDependencies() function would be enough but I still get build errors due to missing the include path. How should I add the dependency? The third-party dependency has just a static library (in 32 and 64 bit versions) and some headers.

Here is the output for the failing project:


17>------ Build started: Project: UE4, Configuration: Development_Editor x64 ------
17> PCH.Shared.Core.h.cpp
17> PCH.Shared.CoreUObject.h.cpp
17> PCH.Shared.Engine.h.cpp
17> PCH.Shared.UnrealEd.h.cpp
17>d:\dev\unrealengine\engine\source\runtime\core\public\stats\stats2.h(10): fatal error C1083: Cannot open include file: ‘vprofiler.h’: No such file or directory
17>d:\dev\unrealengine\engine\source\runtime\core\public\stats\stats2.h(10): fatal error C1083: Cannot open include file: ‘vprofiler.h’: No such file or directory
17>d:\dev\unrealengine\engine\source\runtime\core\public\stats\stats2.h(10): fatal error C1083: Cannot open include file: ‘vprofiler.h’: No such file or directory
17>d:\dev\unrealengine\engine\source\runtime\core\public\stats\stats2.h(10): fatal error C1083: Cannot open include file: ‘vprofiler.h’: No such file or directory
17> -------- End Detailed Actions Stats -----------------------------------------------------------
17>ERROR : UBT error : Failed to produce item: D:\dev\UnrealEngine\Engine\Binaries\Win64\UE4Editor-Projects.dll
17> Cumulative action seconds (12 processors): 0.00 building projects, 4.49 compiling, 0.00 creating app bundles, 0.00 generating debug info, 0.00 linking, 0.00 other
17> UBT execution time: 9.52 seconds
17>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.MakeFile.Targets(38,5): error MSB3073: The command “…..\Build\BatchFiles\Build.bat UE4Editor Win64 Development” exited with code -1.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 27 skipped ==========

Thanks,
.

Does Build.cs file for your module add correct include folders to PublicIncludePaths?

Yes. I checked the paths that I’m adding and comparing them to other third-party libraries.I also checked the path in Engine\Intermediate\ProjectFiles\UE4.vcxproj

Did you model it off of something like UELibPNG? You need to have the External .build.cs and then your module that needs to use it (Core) would reference that.

If it’s already like that, paste your relevant Build.cs files, which may help suss out the problem,
Josh

I based it on zlib which is a dependency already used in Core. Here is my build file, the path is Engine\Source\ThirdParty\VProfiler:
using UnrealBuildTool;

public class VProfiler : ModuleRules
{
	public VProfiler(TargetInfo Target)
	{
		Type = ModuleType.External;

		string VProfilerPath = UEBuildConfiguration.UEThirdPartyDirectory + "VProfiler/";
		PublicIncludePaths.Add(VProfilerPath + "include");

		if (Target.Platform == UnrealTargetPlatform.Win64)
		{
			PublicLibraryPaths.Add(VProfilerPath + "lib64");
		}
		else if (Target.Platform == UnrealTargetPlatform.Win32)
		{
			PublicLibraryPaths.Add(VProfilerPath + "lib32");
		}

		PublicAdditionalLibraries.Add("libvprofiler.lib");
	}
}

Well that sure looks right to me!

One thing you can do is to dump out how it’s compiling. One way is to set:

		bPrintDebugInfo = Utils.GetEnvironmentVariable("ue.bPrintDebugInfo", false);

to true (either set env var, or change code).

Alternatively, you change some code near the bottom of CompileCPPFiles in VCToolChain.cs:

	Log.TraceVerbose("   Compiling: " + CompileAction.StatusDescription);
	Log.TraceVerbose("     Command: " + CompileAction.CommandArguments);

Change those to just Console.WriteLine(). The PrintDebugInfo will spam a LOT. :slight_smile:

Anyway, after that, make sure that when you compile Core files, you are getting the /I parameters for VProfiler.

Josh

According to the log it isn’t being included in the following files:

  • Engine\Intermediate\Build\Win64\UE4Editor\Development\SharedPCHs\PCH.Shared.Core.h.cpp
  • Engine\Intermediate\Build\Win64\UE4Editor\Development\SharedPCHs\PCH.Shared.Engine.h.cpp
  • Engine\Intermediate\Build\Win64\UE4Editor\Development\SharedPCHs\PCH.Shared.CoreUObject.h.cpp
  • Engine\Intermediate\Build\Win64\UE4Editor\Development\SharedPCHs\PCH.Shared.UnrealEd.h.cpp

How can I make sure that they are included there?

To be clear, does the /I show up for the non-PCH files?

Yes it does.

Weird! Time to call in help from someone who will be more familiar with the PCH stuff. In the meantime, you can disable PCHs in BuildConfiguration.cs:

bUsePCHFiles = Utils.GetEnvironmentVariable(“ue.bUsePCHFiles”, true);

Josh

Since what I’m changing is FCycleCounter in \Engine\Source\Runtime\Core\Public\Stats\Stats2.h perhaps I need to add the dependency by hand in other build files? Which ones would they be for those files?

Well that didn’t work out either so I decided to disable unity builds to see what happens. In any case it seems that in the end I will be forced to add VProfiler as a dependency in almost every build file that depends on Core…

Hey PZurita! You are on the right track. Sorry the module files are a bit confusing. You are encountering a fairly advanced use case however.

The reason what you are trying to do isn’t working is because we made efforts to explicitly forbid it from being possible. We don’t want third party libraries to be referenced in public header files because it causes a third party library dependency to be introduced to all referencers of the depending modules.

The reason we don’t like that is because it makes supporting the “installed” version of Unreal Engine more complicated. For example, if DirectX was a “public” dependency module, you would need the DirectX SDK installed in order to compile your game module code using the installed version of the engine. We want to minimize third party requirements as much as possible. Hopefully I explained that well enough.

Luckily, for your case there is an easy workaround! :slight_smile:

Instead of using AddThirdPartyPrivateStaticDependencies(), please try using:

PublicDependencyModuleNames.Add( "VProfiler" );

This tells UnrealBuildTool that you have public source files (Stats2.h) that will be referencing another module (VProfiler), so all modules that refer to this module (Core) also will need to have the correct public include propagated.

Hope this helps!

–Mike

Cool! The only remaining issue was that the solution didn’t properly handle the library, so the headers were found but the linking failed. I tried using PublicLibraryPaths and then adding the library to PublicAdditionalLibraries on my build file, as well as just using PublicAdditionalLibraries with the directory included but neither of them worked. In the end I just added something like this on Core but with the proper path for x86 and x64

PublicDependencyModuleNames.Add("VProfiler");
PublicAdditionalLibraries.Add("ThirdParty/VProfiler/lib64/libvprofiler.lib");

Thanks!

Great! That’s a good workaround for now!!

Unreal Engine modules do not currently support cascading library dependencies to dependent modules.

This was intentional because often you have modules that only need inline header declarations and don’t need to actually link with the library, so forcing modules to explicitly declare the dependent modules they need to link against actually allows us to have optimal parallel compiles (IncrediBuild).

However, as the engine gets bigger and more complex, we’ve realized that this savings in compile time is not worth the confusion to users who are adding new dependencies and having to update all dependent modules with cascading those link-time dependencies.

I’ll talk to the team soon and we’ll try to improve this in one of the upcoming releases.

This is really great feedback!

–Mike

What if the lib has a dll as a Runtime dependency? … my solution for now is throwing the dependencies in the Binaries/Win64 and Unreal finds them is this the intended solution??

There are now better ways to do that than 5 years ago. Take a look at Apex.Build.cs for an example.