Files
UnrealEngine/Engine/Source/Programs/UnrealBuildTool/ToolChain/ClangToolChain.Link.cs
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

148 lines
4.9 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using EpicGames.Core;
using System;
using System.Collections.Generic;
namespace UnrealBuildTool
{
abstract partial class ClangToolChain : ISPCToolChain
{
protected virtual void GetLinkArguments_Optimizations(LinkEnvironment linkEnvironment, List<string> arguments)
{
bool bLTOEnabled = Options.HasFlag(ClangToolChainOptions.EnableLinkTimeOptimization);
bool bThinLTOEnabled = Options.HasFlag(ClangToolChainOptions.EnableThinLTO);
// Profile Guided Optimization (PGO)
if (linkEnvironment.bPGOOptimize && linkEnvironment.PGODirectory != null && linkEnvironment.PGOFilenamePrefix != null)
{
DirectoryReference PGODir = new(linkEnvironment.PGODirectory);
arguments.Add($"-fprofile-use=\"{NormalizeCommandLinePath(DirectoryReference.Combine(PGODir, linkEnvironment.PGOFilenamePrefix), linkEnvironment.RootPaths)}\"");
//
// Clang emits a warning for each compiled function that doesn't have a matching entry in the profile data.
// This can happen when the profile data is older than the binaries we're compiling.
//
// Disable this warning. It's far too verbose.
//
arguments.Add("-Wno-profile-instr-out-of-date");
arguments.Add("-Wno-profile-instr-unprofiled");
arguments.Add("-Wno-backend-plugin");
}
else if (linkEnvironment.bPGOProfile)
{
arguments.Add("-fprofile-generate");
// generate minimal debugging information for profiling
arguments.Add("-gline-tables-only");
}
// Link Time Optimization (LTO)
if (bLTOEnabled)
{
if (bThinLTOEnabled)
{
arguments.Add("-flto=thin");
// lld should consider logical cores when determining how many threads to use
arguments.Add("-Wl,--thinlto-jobs=all");
DirectoryReference? thinLTOCacheDir = DirectoryReference.FromString(linkEnvironment.ThinLTOCacheDirectory);
if (thinLTOCacheDir != null)
{
arguments.Add($"-Wl,--thinlto-cache-dir=\"{NormalizeCommandLinePath(thinLTOCacheDir, linkEnvironment.RootPaths)}\"");
string? thinLTOCachePruningArgs = linkEnvironment.ThinLTOCachePruningArguments;
if (thinLTOCachePruningArgs != null)
{
arguments.Add($"-Wl,--thinlto-cache-policy,{thinLTOCachePruningArgs}");
}
}
}
else
{
arguments.Add("-flto");
}
}
}
protected virtual void GetLinkArguments_Sanitizers(LinkEnvironment linkEnvironment, List<string> arguments)
{
// ASan
if (Options.HasFlag(ClangToolChainOptions.EnableAddressSanitizer))
{
arguments.Add("-fsanitize=address");
arguments.Add("-fsanitize-recover=address");
}
// TSan
if (Options.HasFlag(ClangToolChainOptions.EnableThreadSanitizer))
{
arguments.Add("-fsanitize=thread");
}
// UBSan
if (Options.HasFlag(ClangToolChainOptions.EnableUndefinedBehaviorSanitizer))
{
arguments.Add("-fsanitize=undefined");
}
// MSan
if (Options.HasFlag(ClangToolChainOptions.EnableMemorySanitizer))
{
arguments.Add("-fsanitize=memory");
}
// LibFuzzer
if (Options.HasFlag(ClangToolChainOptions.EnableLibFuzzer))
{
arguments.Add("-fsanitize=fuzzer");
}
}
protected virtual void GetLinkArguments_WarningsAndErrors(LinkEnvironment linkEnvironment, List<string> arguments)
{
// always use absolute paths for errors, this can help IDEs go to the error properly
arguments.Add("-fdiagnostics-absolute-paths"); // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fdiagnostics-absolute-paths
// https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-cla-fcolor-diagnostics
if (Log.ColorConsoleOutput)
{
arguments.Add("-fdiagnostics-color");
}
// https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fdiagnostics-format
if (OperatingSystem.IsWindows())
{
arguments.Add("-fdiagnostics-format=msvc");
}
DirectoryReference? crashDiagnosticDirectory = DirectoryReference.FromString(linkEnvironment.CrashDiagnosticDirectory);
if (crashDiagnosticDirectory != null)
{
if (DirectoryReference.Exists(crashDiagnosticDirectory))
{
arguments.Add($"-fcrash-diagnostics-dir=\"{NormalizeCommandLinePath(crashDiagnosticDirectory, linkEnvironment.RootPaths)}\"");
}
else
{
Log.TraceWarningOnce("CrashDiagnosticDirectory has been specified but directory \"{CrashDiagnosticDirectory}\" does not exist. Linker argument \"-fcrash-diagnostics-dir\" has been discarded.", crashDiagnosticDirectory);
}
}
}
protected virtual void GetArchiveArguments_Global(LinkEnvironment linkEnvironment, List<string> arguments)
{
GetLinkArguments_WarningsAndErrors(linkEnvironment, arguments);
}
protected virtual void GetLinkArguments_Global(LinkEnvironment linkEnvironment, List<string> arguments)
{
GetLinkArguments_Optimizations(linkEnvironment, arguments);
GetLinkArguments_Sanitizers(linkEnvironment, arguments);
GetLinkArguments_WarningsAndErrors(linkEnvironment, arguments);
}
}
}