Workaround for Circular Dependencies

Article written by Branden T.

During development, you may encounter an error while building, such as:

UnrealBuildTool : error : Circular dependency on ModuleA.Build.cs detected.

Full Route: Target -> ModuleA.Build.cs -> ModuleB.Build.cs -> ModuleA.Build.cs
Cycled Route: is ModuleA -> ModuleB -> ModuleA.

Break this loop by moving dependencies into a separate module or using Private/PublicIncludePathModuleNames to reference declarations.

The goal is to remove circular dependencies wherever possible by moving circularly referenced functionality to a separate module, so that both modules that were originally dependent on each other, would then depend on this new module. If for some reason this isn’t possible, UBT offers a way to explicitly declare circular dependencies to silence this error.

To achieve this, you’ll need to leverage the CircularlyReferencedDependentModules list on top of the normal PrivateDependencyModuleNames or PublicDependencyModuleNames.

Example ( Module A and B are circularly dependent ):

ModuleA.Build.cs

 using UnrealBuildTool;
public class ModuleA : ModuleRules
{
	public ModuleA(ReadOnlyTargetRules Target) : base(Target)
	{		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"ModuleB"
			}
		);		

		CircularlyReferencedDependentModules.Add("ModuleB");
	}
}

ModuleB.Build.cs

using UnrealBuildTool;

public class ModuleB : ModuleRules
{
	public ModuleB(ReadOnlyTargetRules Target) : base(Target)
	{		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"ModuleA"
			}
		);		

		CircularlyReferencedDependentModules.Add("ModuleA");
	}
}

There are examples of this in the Engine code, so we’re guilty of doing it as well, although we’re still pushing to eliminate our circular references to improve build times and modularity. An example is located in [UERoot]\Engine\Source\Runtime\AIModule\AIModule.Build.cs. There are more examples you can find by searching for CircularlyReferencedDependentModules in the engine code if you’d like more information.

If you’d like to see how the cycles are detected and dealt with, the code in [UERoot]\Engine\Source\Programs\UnrealBuildTool\ ( try searching this directory’s files for CircularlyReferencedDependentModules as well as Circular dependency to see the code revolving around circular references ), namely in [UERoot]\Engine\Source\Programs\UnrealBuildTool\Configuration\UEBuildModule.cs, in the RecursivelyCreateModules method under the CheckForCycles block.

Our overall recommendation is to remove circular dependencies if at all possible.

2 Likes