// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using EpicGames.Core; using UnrealBuildBase; namespace UnrealBuildTool { /// /// Encapsulates the environment that is used to link object files. /// class LinkEnvironment { /// /// The platform to be compiled/linked for. /// public readonly UnrealTargetPlatform Platform; /// /// The configuration to be compiled/linked for. /// public readonly CppConfiguration Configuration; /// /// The architecture that is being compiled/linked (empty string by default) /// public UnrealArchitectures Architectures; /// /// Gets the Architecture in the normal case where there is a single Architecture in Architectures /// public UnrealArch Architecture => Architectures.SingleArchitecture; /// /// Root paths for this environment. Used for Clang VFS and UBA /// public readonly CppRootPaths RootPaths; /// /// On Mac, indicates the path to the target's application bundle /// public DirectoryReference? BundleDirectory; /// /// The directory to put the non-executable files in (PDBs, import library, etc) /// public DirectoryReference? OutputDirectory; /// /// Intermediate file directory /// public DirectoryReference? IntermediateDirectory; /// /// The directory to shadow source files in for syncing to remote compile servers /// public DirectoryReference? LocalShadowDirectory = null; /// /// The file path for the executable file that is output by the linker. /// public List OutputFilePaths = new List(); /// /// Returns the OutputFilePath is there is only one entry in OutputFilePaths /// public FileReference OutputFilePath { get { if (OutputFilePaths.Count != 1) { throw new BuildException("Attempted to use LinkEnvironmentConfiguration.OutputFilePath property, but there are multiple (or no) OutputFilePaths. You need to handle multiple in the code that called this (size = {0})", OutputFilePaths.Count); } return OutputFilePaths[0]; } } /// /// List of libraries to link in /// public List Libraries = new List(); /// /// A list of additional libraries to link in (using the list of library search paths) /// public List SystemLibraries = new List(); /// /// A list of the paths used to find libraries. /// public List SystemLibraryPaths = new List(); /// /// A list of libraries to exclude from linking. /// public List ExcludedLibraries = new List(); /// /// Paths to add as search paths for runtime libraries /// public List RuntimeLibraryPaths = new List(); /// /// A list of additional frameworks to link in. /// public List AdditionalFrameworks = new List(); /// /// The iOS/Mac frameworks to link in /// public List Frameworks = new List(); public List WeakFrameworks = new List(); /// /// iOS/Mac resources that should be copied to the app bundle /// public List AdditionalBundleResources = new List(); /// /// A list of the dynamically linked libraries that shouldn't be loaded until they are first called /// into. /// public List DelayLoadDLLs = new List(); /// /// Per-architecture lists of dependencies for linking to ignore (useful when building for multiple architectures, and a lib only is needed for one architecture), it's up to the Toolchain to use this /// public Dictionary> DependenciesToSkipPerArchitecture = new(); /// /// Additional arguments to pass to the linker. /// public string AdditionalArguments = ""; /// /// True if debug info should be created. /// public bool bCreateDebugInfo = true; /// /// True if runtime symbols files should be generated as a post build step for some platforms. /// These files are used by the engine to resolve symbol names of callstack backtraces in logs. /// public bool bGenerateRuntimeSymbolFiles = true; /// /// True if debug symbols that are cached for some platforms should not be created. /// public bool bDisableSymbolCache = false; /// /// True if we're compiling .cpp files that will go into a library (.lib file) /// public bool bIsBuildingLibrary = false; /// /// True if we're compiling a DLL /// public bool bIsBuildingDLL = false; /// /// The method of linking the target uses /// public TargetLinkType LinkType; /// /// Whether we should compile using the statically-linked CRT. This is not widely supported for the whole engine, but is required for programs that need to run without dependencies. /// public bool bUseStaticCRT = false; /// /// Whether to use the debug CRT in debug configurations /// public bool bUseDebugCRT = false; /// /// True if this is a console application that's being build /// public bool bIsBuildingConsoleApplication = false; /// /// If set, overrides the program entry function on Windows platform. This is used by the base Unreal /// program so we can link in either command-line mode or windowed mode without having to recompile the Launch module. /// public string WindowsEntryPointOverride = String.Empty; /// /// True if we're building a EXE/DLL target with an import library, and that library is needed by a dependency that /// we're directly dependent on. /// public bool bIsCrossReferenced = false; /// /// True if the application we're linking has any exports, and we should be expecting the linker to /// generate a .lib and/or .exp file along with the target output file /// public bool bHasExports = true; /// /// True if we're building a .NET assembly (e.g. C# project) /// public bool bIsBuildingDotNetAssembly = false; /// /// The default stack memory size allocation /// public int DefaultStackSize = 5000000; /// /// The amount of the default stack size to commit initially. Set to 0 to allow the OS to decide. /// public int DefaultStackSizeCommit = 0; /// /// Wether to link code coverage / tracing libs /// public bool bCodeCoverage = false; /// /// Whether to omit frame pointers or not. Disabling is useful for e.g. memory profiling on the PC /// public bool bOmitFramePointers = true; /// /// Whether to support edit and continue. Only works on Microsoft compilers in 32-bit compiles. /// public bool bSupportEditAndContinue; /// /// Whether to use incremental linking or not. /// public bool bUseIncrementalLinking; /// /// Whether to allow the use of LTCG (link time code generation) /// public bool bAllowLTCG; /// /// Whether to enable Profile Guided Optimization (PGO) instrumentation in this build. /// public bool bPGOProfile; /// /// Whether to optimize this build with Profile Guided Optimization (PGO). /// public bool bPGOOptimize; /// /// Platform specific directory where PGO profiling data is stored. /// public string? PGODirectory; /// /// Platform specific filename where PGO profiling data is saved. /// public string? PGOFilenamePrefix; /// /// Platform specific filename where pre-merged PGO profiling data is saved. /// public string? PGOMergedFilenamePrefix; /// /// Whether to request the linker create a map file as part of the build /// public bool bCreateMapFile; /// /// Whether PDB files should be used for Visual C++ builds. /// public bool bUsePDBFiles; /// /// Whether to use the :FASTLINK option when building with /DEBUG to create local PDBs /// public bool bUseFastPDBLinking; /// /// Use Position Independent Executable (PIE). Has an overhead cost /// public bool bUsePIE = false; /// /// Whether to ignore dangling (i.e. unresolved external) symbols in modules /// public bool bIgnoreUnresolvedSymbols; /// /// Set flags for determinstic compiles. /// public bool bDeterministic; /// /// Whether to log detailed timing information /// public bool bPrintTimingInfo; /// /// Package full path (directory + filename) where to store input files used at link time /// Normally used to debug a linker crash for platforms that support it /// public string? PackagePath; /// /// Directory where to put crash report files for platforms that support it /// public string? CrashDiagnosticDirectory; /// /// Directory where to put the ThinLTO cache for platforms that support it /// public string? ThinLTOCacheDirectory; /// /// Arguments that will be applied to prune the ThinLTO cache for platforms that support it. /// The arguments will only be applied if ThinLTOCacheDirectory is set. /// public string? ThinLTOCachePruningArguments; /// /// Bundle version for Mac apps /// public string? BundleVersion; /// /// When building a dynamic library on Apple platforms, specifies the installed name for other binaries that link against it. /// public string? InstallName; /// /// A list of the object files to be linked. /// public List InputFiles = new List(); /// /// The default resource file to link in to every binary if a custom one is not provided /// public List DefaultResourceFiles = new List(); /// /// Resource files which should be compiled into every binary /// public List CommonResourceFiles = new List(); /// /// List of functions that should be exported from this module /// public List IncludeFunctions = new List(); /// /// Debugger visualizer files to build into debug info for this binary. /// public List DebuggerVisualizerFiles = new List(); /// /// Provides a Module Definition File (.def) to the linker to describe various attributes of a DLL. /// Necessary when exporting functions by ordinal values instead of by name. /// public string? ModuleDefinitionFile; /// /// All the additional properties from the modules linked into this binary /// public List AdditionalProperties = new List(); /// /// List of all of the runtime dependencies. /// public List RuntimeDependencies = new List(); /// /// Default constructor. /// public LinkEnvironment(UnrealTargetPlatform Platform, CppConfiguration Configuration, UnrealArchitectures Architectures) { this.Platform = Platform; this.Configuration = Configuration; this.Architectures = new(Architectures); RootPaths = new(); } /// /// Copy constructor. /// public LinkEnvironment(LinkEnvironment Other) { Platform = Other.Platform; Configuration = Other.Configuration; Architectures = Other.Architectures; LinkType = Other.LinkType; RootPaths = new(Other.RootPaths); BundleDirectory = Other.BundleDirectory; OutputDirectory = Other.OutputDirectory; IntermediateDirectory = Other.IntermediateDirectory; LocalShadowDirectory = Other.LocalShadowDirectory; OutputFilePaths = Other.OutputFilePaths.ToList(); RuntimeDependencies.AddRange(Other.RuntimeDependencies); Libraries.AddRange(Other.Libraries); SystemLibraries.AddRange(Other.SystemLibraries); SystemLibraryPaths.AddRange(Other.SystemLibraryPaths); ExcludedLibraries.AddRange(Other.ExcludedLibraries); RuntimeLibraryPaths.AddRange(Other.RuntimeLibraryPaths); RuntimeDependencies.AddRange(Other.RuntimeDependencies); Frameworks.AddRange(Other.Frameworks); AdditionalFrameworks.AddRange(Other.AdditionalFrameworks); WeakFrameworks.AddRange(Other.WeakFrameworks); AdditionalBundleResources.AddRange(Other.AdditionalBundleResources); DelayLoadDLLs.AddRange(Other.DelayLoadDLLs); AdditionalArguments = Other.AdditionalArguments; bCreateDebugInfo = Other.bCreateDebugInfo; bGenerateRuntimeSymbolFiles = Other.bGenerateRuntimeSymbolFiles; bIsBuildingLibrary = Other.bIsBuildingLibrary; bDisableSymbolCache = Other.bDisableSymbolCache; bIsBuildingDLL = Other.bIsBuildingDLL; LinkType = Other.LinkType; bUseStaticCRT = Other.bUseStaticCRT; bUseDebugCRT = Other.bUseDebugCRT; bIsBuildingConsoleApplication = Other.bIsBuildingConsoleApplication; WindowsEntryPointOverride = Other.WindowsEntryPointOverride; bIsCrossReferenced = Other.bIsCrossReferenced; bHasExports = Other.bHasExports; bIsBuildingDotNetAssembly = Other.bIsBuildingDotNetAssembly; DefaultStackSize = Other.DefaultStackSize; DefaultStackSizeCommit = Other.DefaultStackSizeCommit; bCodeCoverage = Other.bCodeCoverage; bOmitFramePointers = Other.bOmitFramePointers; bSupportEditAndContinue = Other.bSupportEditAndContinue; bUseIncrementalLinking = Other.bUseIncrementalLinking; bAllowLTCG = Other.bAllowLTCG; bPGOOptimize = Other.bPGOOptimize; bPGOProfile = Other.bPGOProfile; PGODirectory = Other.PGODirectory; PGOFilenamePrefix = Other.PGOFilenamePrefix; PGOMergedFilenamePrefix = Other.PGOMergedFilenamePrefix; bCreateMapFile = Other.bCreateMapFile; bUsePDBFiles = Other.bUsePDBFiles; bUseFastPDBLinking = Other.bUseFastPDBLinking; bUsePIE = Other.bUsePIE; bIgnoreUnresolvedSymbols = Other.bIgnoreUnresolvedSymbols; bDeterministic = Other.bDeterministic; bPrintTimingInfo = Other.bPrintTimingInfo; PackagePath = Other.PackagePath; CrashDiagnosticDirectory = Other.CrashDiagnosticDirectory; ThinLTOCacheDirectory = Other.ThinLTOCacheDirectory; ThinLTOCachePruningArguments = Other.ThinLTOCachePruningArguments; BundleVersion = Other.BundleVersion; InstallName = Other.InstallName; InputFiles.AddRange(Other.InputFiles); DefaultResourceFiles.AddRange(Other.DefaultResourceFiles); CommonResourceFiles.AddRange(Other.CommonResourceFiles); IncludeFunctions.AddRange(Other.IncludeFunctions); DebuggerVisualizerFiles.AddRange(Other.DebuggerVisualizerFiles); ModuleDefinitionFile = Other.ModuleDefinitionFile; AdditionalProperties.AddRange(Other.AdditionalProperties); foreach (KeyValuePair> Pair in Other.DependenciesToSkipPerArchitecture) { DependenciesToSkipPerArchitecture[Pair.Key] = new HashSet(Pair.Value); } } /// /// Construct a LinkEnvironment from another, and filter it down to only files/dependencies that apply to the given architecture /// /// Parent LinkEnvironment to start with that may have been created from multiple architectures (arch1+arch2) /// The single architecture to filter down to public LinkEnvironment(LinkEnvironment Other, UnrealArch OverrideArchitecture) : this(Other) { Architectures = new UnrealArchitectures(OverrideArchitecture); // filter the input files UnrealArchitectureConfig ArchConfig = UnrealArchitectureConfig.ForPlatform(Platform); string IntermediateDirPart = ArchConfig.GetFolderNameForArchitectures(Architectures); InputFiles = Other.InputFiles.Where(x => x.Location.ContainsName(IntermediateDirPart, 0)).ToList(); IntermediateDirectory = new DirectoryReference(Other.IntermediateDirectory!.FullName.Replace( ArchConfig.GetFolderNameForArchitectures(Other.Architectures), ArchConfig.GetFolderNameForArchitecture(OverrideArchitecture))); if (DependenciesToSkipPerArchitecture.Count > 0) { // add more arrays here? Libraries = Libraries.Where(x => !DependenciesToSkipPerArchitecture.ContainsKey(x.FullName) || !DependenciesToSkipPerArchitecture[x.FullName].Contains(Architecture)).ToList(); SystemLibraries = SystemLibraries.Where(x => !DependenciesToSkipPerArchitecture.ContainsKey(x) || !DependenciesToSkipPerArchitecture[x].Contains(Architecture)).ToList(); Frameworks = Frameworks.Where(x => !DependenciesToSkipPerArchitecture.ContainsKey(x) || !DependenciesToSkipPerArchitecture[x].Contains(Architecture)).ToList(); AdditionalFrameworks = AdditionalFrameworks.Where(x => !DependenciesToSkipPerArchitecture.ContainsKey(x.Name) || !DependenciesToSkipPerArchitecture[x.Name].Contains(Architecture)).ToList(); WeakFrameworks = WeakFrameworks.Where(x => !DependenciesToSkipPerArchitecture.ContainsKey(x) || !DependenciesToSkipPerArchitecture[x].Contains(Architecture)).ToList(); AdditionalBundleResources = AdditionalBundleResources.Where(x => x.ResourcePath == null || !DependenciesToSkipPerArchitecture.ContainsKey(x.ResourcePath) || !DependenciesToSkipPerArchitecture[x.ResourcePath].Contains(Architecture)).ToList(); DelayLoadDLLs = DelayLoadDLLs.Where(x => !DependenciesToSkipPerArchitecture.ContainsKey(x) || !DependenciesToSkipPerArchitecture[x].Contains(Architecture)).ToList(); } } } }