Includes, unity builds, PCH, IWYU

Mock Q1 · result: Partial (knew transitive includes, not unity/PCH) · 6 min

In one breath

A file can use a header it never included, because unity builds glue many .cpp files together and shared precompiled headers pre-include common stuff. When the grouping changes, the file loses the include it was borrowing and breaks. Prevent it with IWYU (include what you use) and a non-unity build on CI.

New to unity builds? Start with How Unreal builds your code; this page is the interview-question version.

The question

A .cpp uses FMath::Clamp without including its header and compiles fine. Two weeks later an unrelated change (adding a new .cpp to the module) makes it fail. Why did it compile, why did it break, and how do you prevent it?

Three ways to see a header you didn't include

  1. Transitive includes. A header you include includes it.
  2. Precompiled headers. PCHUsage = UseExplicitOrSharedPCHs (it's in WadOfGore's Build.cs too) lets a module compile against a shared PCH that already contains CoreMinimal.h and friends.
  3. Unity builds. UBT concatenates many .cpp files into one generated file that #includes them in turn. A header included by an earlier .cpp in the same group is visible to every later one. Your file borrows its neighbour's include.

Why an unrelated change breaks it

Prevention

30-second answer

"Unity builds and shared PCHs hide missing includes. Unity grouping changes when files are added, or when adaptive unity pulls out a file you're editing, so the error shows up later. I follow IWYU and run a non-unity build on CI to catch it."

Do, don't just read

Build a project once with -DisableUnity -NoPCH -NoSharedPCH and fix whatever breaks. That gives you real findings to talk about.

Quiz yourself

What is a unity build?

UBT combines many .cpp files into one generated file that includes them in turn, so the compiler parses shared headers once. That makes builds much faster.

What is adaptive unity, and why does it cause "I edited it and now it won't compile"?

Files you're working on get compiled on their own, outside the blob. They lose the headers they were borrowing from neighbours.

What does IWYU stand for, and what's the rule?

Include What You Use: every file includes the headers for the things it uses directly, instead of relying on something else to pull them in.

Which build flags surface every hidden include problem?

-DisableUnity -NoPCH -NoSharedPCH (or bUseUnity = false in Build.cs).

Why forward-declare in headers?

Fewer includes leak into everyone who includes your header. That gives faster compiles and fewer accidental dependencies.