-
-
Save galeone/f8bdf0fb4fafc517a4f65537b2ae2634 to your computer and use it in GitHub Desktop.
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/ModuleRules.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/ModuleRules.cs | |
@@ -606,6 +606,10 @@ namespace UnrealBuildTool | |
{ | |
get | |
{ | |
+ if (bCodeCoverage) { | |
+ return CodeOptimization.Never; | |
+ } | |
+ | |
if (OptimizeCodeOverride.HasValue) | |
return OptimizeCodeOverride.Value; | |
@@ -703,6 +707,11 @@ namespace UnrealBuildTool | |
/// </summary> | |
public bool bUseRTTI = false; | |
+ /// <summary> | |
+ /// Enable code coverage compilation/linking support. | |
+ /// </summary> | |
+ public bool bCodeCoverage = false; | |
+ | |
/// <summary> | |
/// Direct the compiler to generate AVX instructions wherever SSE or AVX intrinsics are used, on the platforms that support it. | |
/// Note that by enabling this you are changing the minspec for the PC platform, and the resultant executable will crash on machines without AVX support. | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs | |
index b3dac4efa6c..e0b6e130e9c 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs | |
@@ -1083,6 +1083,13 @@ namespace UnrealBuildTool | |
[XmlConfigFile(Category = "BuildConfiguration")] | |
public bool bPGOOptimize = false; | |
+ /// <summary> | |
+ /// Whether the target requires code coverage compilation and linking. | |
+ /// </summary> | |
+ [CommandLine("-CodeCoverage", Value = "true")] | |
+ [XmlConfigFile(Category = "BuildConfiguration")] | |
+ public bool bCodeCoverage; | |
+ | |
/// <summary> | |
/// Whether to support edit and continue. Only works on Microsoft compilers. | |
/// </summary> | |
@@ -2493,6 +2500,11 @@ namespace UnrealBuildTool | |
get { return Inner.bPGOOptimize; } | |
} | |
+ public bool bCodeCoverage | |
+ { | |
+ get {return Inner.bCodeCoverage; } | |
+ } | |
+ | |
public bool bSupportEditAndContinue | |
{ | |
get { return Inner.bSupportEditAndContinue; } | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs | |
index 4809ab00135..ccdaa77f718 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs | |
@@ -184,6 +184,7 @@ namespace UnrealBuildTool | |
// Setup linking environment. | |
LinkEnvironment BinaryLinkEnvironment = SetupBinaryLinkEnvironment(Target, ToolChain, LinkEnvironment, CompileEnvironment, SpecificFilesToCompile, WorkingSet, ExeDir, Graph); | |
+ BinaryLinkEnvironment.bCodeCoverage = CompileEnvironment.bCodeCoverage; | |
// If we're generating projects, we only need include paths and definitions, there is no need to run the linking logic. | |
if (ProjectFileGenerator.bGenerateProjectFiles) | |
@@ -231,6 +232,7 @@ namespace UnrealBuildTool | |
ConsoleAppLinkEvironment.bIsBuildingConsoleApplication = true; | |
ConsoleAppLinkEvironment.WindowsEntryPointOverride = "WinMainCRTStartup"; // For WinMain() instead of "main()" for Launch module | |
ConsoleAppLinkEvironment.OutputFilePaths = ConsoleAppLinkEvironment.OutputFilePaths.Select(Path => GetAdditionalConsoleAppPath(Path)).ToList(); | |
+ ConsoleAppLinkEvironment.bCodeCoverage = CompileEnvironment.bCodeCoverage; | |
// Link the console app executable | |
FileItem[] ConsoleAppOutputFiles = ToolChain.LinkAllFiles(ConsoleAppLinkEvironment, false, Graph); | |
@@ -700,6 +702,7 @@ namespace UnrealBuildTool | |
private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, List<FileReference> SpecificFilesToCompile, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, IActionGraphBuilder Graph) | |
{ | |
LinkEnvironment BinaryLinkEnvironment = new LinkEnvironment(LinkEnvironment); | |
+ BinaryLinkEnvironment.bCodeCoverage = CompileEnvironment.bCodeCoverage; | |
HashSet<UEBuildModule> LinkEnvironmentVisitedModules = new HashSet<UEBuildModule>(); | |
List<UEBuildBinary> BinaryDependencies = new List<UEBuildBinary>(); | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs | |
index 481bb6db1f2..a1caeec2253 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs | |
@@ -624,6 +624,7 @@ namespace UnrealBuildTool | |
CompileEnvironment.PrecompiledHeaderAction = PrecompiledHeaderAction.Create; | |
CompileEnvironment.PrecompiledHeaderIncludeFilename = WrapperFile.Location; | |
CompileEnvironment.bOptimizeCode = ModuleCompileEnvironment.bOptimizeCode; | |
+ CompileEnvironment.bCodeCoverage = ModuleCompileEnvironment.bCodeCoverage; | |
// Create the action to compile the PCH file. | |
CPPOutput Output; | |
@@ -822,6 +823,7 @@ namespace UnrealBuildTool | |
private void CopySettingsForSharedPCH(CppCompileEnvironment ModuleCompileEnvironment, CppCompileEnvironment CompileEnvironment) | |
{ | |
CompileEnvironment.bOptimizeCode = ModuleCompileEnvironment.bOptimizeCode; | |
+ CompileEnvironment.bCodeCoverage = ModuleCompileEnvironment.bCodeCoverage; | |
CompileEnvironment.bUseRTTI = ModuleCompileEnvironment.bUseRTTI; | |
CompileEnvironment.bEnableExceptions = ModuleCompileEnvironment.bEnableExceptions; | |
CompileEnvironment.ShadowVariableWarningLevel = ModuleCompileEnvironment.ShadowVariableWarningLevel; | |
@@ -1238,9 +1240,13 @@ namespace UnrealBuildTool | |
/// <param name="Setting">The optimization setting from the rules file</param> | |
/// <param name="Configuration">The active target configuration</param> | |
/// <param name="bIsEngineModule">Whether the current module is an engine module</param> | |
+ /// <param name="bCodeCoverage">Whether the current module should be compiled with code coverage support</param> | |
/// <returns>True if optimization should be enabled</returns> | |
- public static bool ShouldEnableOptimization(ModuleRules.CodeOptimization Setting, UnrealTargetConfiguration Configuration, bool bIsEngineModule) | |
+ public static bool ShouldEnableOptimization(ModuleRules.CodeOptimization Setting, UnrealTargetConfiguration Configuration, bool bIsEngineModule, bool bCodeCoverage) | |
{ | |
+ if (bCodeCoverage) { | |
+ return false; | |
+ } | |
switch(Setting) | |
{ | |
case ModuleRules.CodeOptimization.Never: | |
@@ -1275,7 +1281,8 @@ namespace UnrealBuildTool | |
// Override compile environment | |
Result.bUseUnity = Rules.bUseUnity; | |
- Result.bOptimizeCode = ShouldEnableOptimization(Rules.OptimizeCode, Target.Configuration, Rules.bTreatAsEngineModule); | |
+ Result.bCodeCoverage = Target.bCodeCoverage; // From Target! | |
+ Result.bOptimizeCode = ShouldEnableOptimization(Rules.OptimizeCode, Target.Configuration, Rules.bTreatAsEngineModule, Result.bCodeCoverage); | |
Result.bUseRTTI |= Rules.bUseRTTI; | |
Result.bUseAVX = Rules.bUseAVX; | |
Result.bEnableBufferSecurityChecks = Rules.bEnableBufferSecurityChecks; | |
@@ -1348,8 +1355,9 @@ namespace UnrealBuildTool | |
{ | |
CppCompileEnvironment CompileEnvironment = new CppCompileEnvironment(BaseCompileEnvironment); | |
- // Use the default optimization setting for | |
- CompileEnvironment.bOptimizeCode = ShouldEnableOptimization(ModuleRules.CodeOptimization.Default, Target.Configuration, Rules.bTreatAsEngineModule); | |
+ // Use the default optimization setting for | |
+ CompileEnvironment.bOptimizeCode = ShouldEnableOptimization(ModuleRules.CodeOptimization.Default, Target.Configuration, Rules.bTreatAsEngineModule, Rules.bCodeCoverage); | |
+ CompileEnvironment.bCodeCoverage = Rules.bCodeCoverage; | |
// Override compile environment | |
CompileEnvironment.bIsBuildingDLL = !Target.ShouldCompileMonolithic(); | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs | |
index 97a937d41af..2b401a4f326 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs | |
@@ -3439,6 +3439,7 @@ namespace UnrealBuildTool | |
GlobalCompileEnvironment.bHideSymbolsByDefault = !Rules.bPublicSymbolsByDefault; | |
GlobalCompileEnvironment.CppStandard = Rules.CppStandard; | |
GlobalCompileEnvironment.AdditionalArguments = Rules.AdditionalCompilerArguments; | |
+ GlobalCompileEnvironment.bCodeCoverage = Rules.bCodeCoverage; | |
GlobalLinkEnvironment.bIsBuildingConsoleApplication = Rules.bIsBuildingConsoleApplication; | |
GlobalLinkEnvironment.bOptimizeForSize = Rules.bCompileForSize; | |
@@ -3456,6 +3457,7 @@ namespace UnrealBuildTool | |
GlobalLinkEnvironment.bUseFastPDBLinking = Rules.bUseFastPDBLinking ?? false; | |
GlobalLinkEnvironment.bPrintTimingInfo = Rules.bPrintToolChainTimingInfo; | |
GlobalLinkEnvironment.AdditionalArguments = Rules.AdditionalLinkerArguments; | |
+ GlobalLinkEnvironment.bCodeCoverage = Rules.bCodeCoverage; | |
if (Rules.bPGOOptimize && Rules.bPGOProfile) | |
{ | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/LinuxToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/LinuxToolChain.cs | |
index fb38ffe34fe..ba6b28f48d0 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/LinuxToolChain.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/LinuxToolChain.cs | |
@@ -170,6 +170,7 @@ namespace UnrealBuildTool | |
bIsCrossCompiling = true; | |
bHasValidCompiler = DetermineCompilerVersion(); | |
+ CompilerRTPath = Path.Combine(Path.Combine(BaseLinuxPath, String.Format("lib/clang/{0}/lib/linux/", CompilerVersionString))); | |
} | |
if (!bHasValidCompiler) | |
@@ -767,8 +768,13 @@ namespace UnrealBuildTool | |
} | |
} | |
- // optimization level | |
- if (!CompileEnvironment.bOptimizeCode) | |
+ if (CompileEnvironment.bCodeCoverage) | |
+ { | |
+ Result += " -O0"; | |
+ Result += " -fprofile-arcs -ftest-coverage"; // gcov | |
+ //Result += " -fprofile-instr-generate -fcoverage-mapping"; // llvm-cov | |
+ } | |
+ else if (!CompileEnvironment.bOptimizeCode) // optimization level | |
{ | |
Result += " -O0"; | |
} | |
@@ -1019,6 +1025,15 @@ namespace UnrealBuildTool | |
Result += " -Wl,--gdb-index"; | |
} | |
+ if (LinkEnvironment.bCodeCoverage) | |
+ { | |
+ // Unreal Separates the linking phase and the compilation phase. | |
+ // We pass to clang the flag `--coverage` during the compile time | |
+ // And we link the correct compiler-rt library (shipped by UE, and part of the LLVM toolchain) | |
+ // to every binary produced. | |
+ Result += string.Format(" -L{0} -l{1}", CompilerRTPath, "clang_rt.profile-x86_64"); // gcov | |
+ // Result += " -fprofile-instr-generate"; // llvm-cov | |
+ } | |
// RPATH for third party libs | |
Result += " -Wl,-rpath=${ORIGIN}"; | |
Result += " -Wl,-rpath-link=${ORIGIN}"; | |
@@ -1142,6 +1157,7 @@ namespace UnrealBuildTool | |
protected string BaseLinuxPath; | |
protected string ClangPath; | |
protected string GCCPath; | |
+ protected string CompilerRTPath; | |
protected string ArPath; | |
protected string LlvmArPath; | |
protected string RanlibPath; | |
@@ -1270,6 +1286,11 @@ namespace UnrealBuildTool | |
Log.TraceInformation(" Prefix for PGO data files='{0}'", CompileEnvironment.PGOFilenamePrefix); | |
} | |
+ if (CompileEnvironment.bCodeCoverage) | |
+ { | |
+ Log.TraceInformation("Using --coverage build flag"); | |
+ } | |
+ | |
if (CompileEnvironment.bPGOProfile) | |
{ | |
Log.TraceInformation("Using PGI (profile guided instrumentation)."); | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/UEBuildLinux.cs b/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/UEBuildLinux.cs | |
index d8b35ac02ab..de3fc2d944e 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/UEBuildLinux.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/Platform/Linux/UEBuildLinux.cs | |
@@ -526,6 +526,8 @@ namespace UnrealBuildTool | |
LinkEnvironment.PGOFilenamePrefix = CompileEnvironment.PGOFilenamePrefix; | |
} | |
+ LinkEnvironment.bCodeCoverage = CompileEnvironment.bCodeCoverage; | |
+ | |
// For consistency with other platforms, also enable LTO whenever doing profile-guided optimizations. | |
// Obviously both PGI (instrumented) and PGO (optimized) binaries need to have that | |
if (CompileEnvironment.bPGOProfile || CompileEnvironment.bPGOOptimize) | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs b/Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs | |
index 189954552a3..f56830c64d2 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs | |
@@ -221,6 +221,11 @@ namespace UnrealBuildTool | |
/// </summary> | |
public bool bOptimizeCode = false; | |
+ /// <summary> | |
+ /// True if the compilation should produce tracing output for code coverage. | |
+ /// </summary> | |
+ public bool bCodeCoverage = false; | |
+ | |
/// <summary> | |
/// Whether to optimize for minimal code size | |
/// </summary> | |
@@ -428,6 +433,7 @@ namespace UnrealBuildTool | |
bUndefinedIdentifierWarningsAsErrors = Other.bUndefinedIdentifierWarningsAsErrors; | |
bEnableUndefinedIdentifierWarnings = Other.bEnableUndefinedIdentifierWarnings; | |
bOptimizeCode = Other.bOptimizeCode; | |
+ bCodeCoverage = Other.bCodeCoverage; | |
bOptimizeForSize = Other.bOptimizeForSize; | |
bCreateDebugInfo = Other.bCreateDebugInfo; | |
bIsBuildingLibrary = Other.bIsBuildingLibrary; | |
diff --git a/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs b/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs | |
index 610e4b3db4d..9a94a6b4388 100644 | |
--- a/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs | |
+++ b/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs | |
@@ -196,6 +196,11 @@ namespace UnrealBuildTool | |
/// </summary> | |
public bool bOptimizeForSize = false; | |
+ /// <summary> | |
+ /// Wether to link code coverage / tracing libs | |
+ /// </summary> | |
+ public bool bCodeCoverage = false; | |
+ | |
/// <summary> | |
/// Whether to omit frame pointers or not. Disabling is useful for e.g. memory profiling on the PC | |
/// </summary> | |
@@ -349,6 +354,7 @@ namespace UnrealBuildTool | |
DefaultStackSize = Other.DefaultStackSize; | |
DefaultStackSizeCommit = Other.DefaultStackSizeCommit; | |
bOptimizeForSize = Other.bOptimizeForSize; | |
+ bCodeCoverage = Other.bCodeCoverage; | |
bOmitFramePointers = Other.bOmitFramePointers; | |
bSupportEditAndContinue = Other.bSupportEditAndContinue; | |
bUseIncrementalLinking = Other.bUseIncrementalLinking; |
That works, albeit a strange issue where I need to run it twice.
[136/2101] Compile Module.Chaos.1_of_7.cpp
[136/2101]Compile Module.Chaos.1_of_7.cpp - Error but no output
[136/2101]Compile Module.Chaos.1_of_7.cpp - 137 /home/administrator/Applications/Epic/UE_5.0_Source/Engine/Source /home/administrator/Applications/Epic/UE_5.0_Source/Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/v19_clang-11.0.1-centos7/x86_64-unknown-linux-gnu/bin/clang++ @"/home/administrator/Applications/Epic/UE_5.0_Source/Engine/Intermediate/Build/Linux/B4D820EA/UnrealEditor/Development/Chaos/Module.Chaos.1_of_7.cpp.o.rsp"
Appears the first time, but compiles okay on the second run.
Cool! Anyway, you shouldn't compile the whole engine with the -CodeCoverage
flag enabled, but it's better to have an installed version of the engine (with the UBT modified) and compile the project/module you want to measure the coverage only - otherwise, compiling the whole engine with optimization disabled will slow down the development a lot
I've only been passing in -CodeCoverage
when compiling the project/module and not the engine. UE5 is doing half the engine on the first project compile using the engine build, 2nd/3rd projects are actually fine too, just seems like a first project only issue. Next fun part is trying to see if I can get this into ue4-docker to automate more. The flag works with ue4cli no problem.
Thanks for all the help so far. I'll write it up if I get the docker images working too.
awesome, keep me posted!
Awesome work @galeone! Have you considered submitting this as a PR?
@galeone Really awesome to see this implemented in 5.3.0 as part of CL 25794147 and documented here: https://docs.unrealengine.com/5.3/en-US/static-code-analysis-in-unreal-engine/
@CanisHelix but these are the sanitizers, it's not the code coverage support
@galeone I will be testing shortly, but trying to apply the patch to 5.3.1, it looks like your changes are finally included in the Unreal release!
Nope, I mean only passing the
--coverage
flag without explicitly link the library. Thus