Created
February 16, 2022 08:30
-
-
Save galeone/f8bdf0fb4fafc517a4f65537b2ae2634 to your computer and use it in GitHub Desktop.
Enable code coverage support on Unreal Built Tool Linux Toolchain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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; |
I did it, but I'm getting ignored lol
EpicGames/UnrealEngine#9294
…On Wed, Jul 20, 2022, 03:50 Sam Jeeves ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
Awesome work @galeone <https://github.com/galeone>! Have you considered
submitting this as a PR?
—
Reply to this email directly, view it on GitHub
<https://gist.github.com/f8bdf0fb4fafc517a4f65537b2ae2634#gistcomment-4238767>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACAJSDCAW465ICYB5FNFIWTVU7KXTANCNFSM5S6A5SOQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
@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!
Verified. The merged it in 5.4.1 for sure (just tested). They modified this a little bit (for no reason). So instead of ForceQuit, you must use Quit. And instead of Quit, you must use SoftQuit
All the rest is the same
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Awesome work @galeone! Have you considered submitting this as a PR?