// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Text; using EpicGames.Core; using Microsoft.Extensions.Logging; namespace UnrealBuildTool { /// /// Base class for platform-specific project generators /// abstract class PlatformProjectGenerator { public static readonly string DefaultPlatformConfigurationType = "Makefile"; protected readonly ILogger Logger; /// /// Constructor /// /// Command line arguments passed to the project generator /// Logger for output public PlatformProjectGenerator(CommandLineArguments Arguments, ILogger Logger) { this.Logger = Logger; } /// /// Register the platform with the UEPlatformProjectGenerator class /// public abstract IEnumerable GetPlatforms(); public virtual void GenerateGameProjectStub(ProjectFileGenerator InGenerator, string InTargetName, string InTargetFilepath, TargetRules InTargetRules, List InPlatforms, List InConfigurations) { // Do nothing } public virtual void GenerateGameProperties(UnrealTargetConfiguration Configuration, StringBuilder VCProjectFileContent, TargetType TargetType, DirectoryReference RootDirectory, FileReference TargetFilePath) { // Do nothing } public virtual bool RequiresVSUserFileGeneration() { return false; } ConcurrentDictionary FoundVSISupportDict = new(); public struct VSSettings { public UnrealTargetPlatform Platform; public UnrealTargetConfiguration Configuration = UnrealTargetConfiguration.Development; public VCProjectFileFormat ProjectFileFormat = VCProjectFileFormat.Default; public UnrealArch? Architecture = null; public VSSettings(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, VCProjectFileFormat InProjectFileFormat, UnrealArch? InArchitecture) { Platform = InPlatform; Configuration = InConfiguration; ProjectFileFormat = InProjectFileFormat; Architecture = InArchitecture; } }; /// /// Checks the local VS install directories to see if the platform is supported. /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// bool true if native VisualStudio support (or custom VSI) is available public virtual bool HasVisualStudioSupport(VSSettings InVSSettings) { int HashResult = 691; HashResult *= InVSSettings.Platform.ToString().GetHashCode(); HashResult *= InVSSettings.Configuration.ToString().GetHashCode(); HashResult *= InVSSettings.ProjectFileFormat.ToString().GetHashCode(); HashResult *= InVSSettings.Architecture != null ? InVSSettings.Architecture.ToString()!.GetHashCode() : 1; return FoundVSISupportDict.GetOrAdd(HashResult, _ => { WindowsCompiler VSCompiler; string VCVersion; switch (InVSSettings.ProjectFileFormat) { case VCProjectFileFormat.VisualStudio2022: VSCompiler = WindowsCompiler.VisualStudio2022; VCVersion = "v170"; break; default: // Unknown VS Version return false; } IEnumerable? InstallDirs = WindowsPlatform.TryGetVSInstallDirs(VSCompiler, Logger); if (InstallDirs != null) { foreach (DirectoryReference VSInstallDir in InstallDirs) { DirectoryReference PlatformsPath = new DirectoryReference(System.IO.Path.Combine(VSInstallDir.FullName, "MSBuild\\Microsoft\\VC\\", VCVersion, "Platforms", GetVisualStudioPlatformName(InVSSettings))); if (DirectoryReference.Exists(PlatformsPath)) { return true; } } } return false; }); } /// /// Return the VisualStudio platform name for this build platform /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// string The name of the platform that VisualStudio recognizes public virtual string GetVisualStudioPlatformName(VSSettings InVSSettings) { // By default, return the platform string return InVSSettings.Platform.ToString(); } /// /// Return whether we need a distinct platform name - for cases where there are two targets of the same VS solution platform /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// bool public virtual bool RequiresDistinctVisualStudioConfigurationName(VSSettings InVSSettings) { return false; } /// /// Return project configuration settings that must be included before the default props file for all configurations /// /// The UnrealTargetPlatform being built /// String builder for the project file /// string The custom configuration section for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioPreDefaultString(UnrealTargetPlatform InPlatform, StringBuilder ProjectFileBuilder) { } /// /// Return project configuration settings that must be included before the default props file /// /// The UnrealTargetPlatform being built /// The UnrealTargetConfiguration being built /// String builder for the project file /// string The custom configuration section for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioPreDefaultString(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, StringBuilder ProjectFileBuilder) { } /// /// Return the platform toolset string to write into the project configuration /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// String builder for the project file /// string The custom configuration section for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioPlatformToolsetString(VSSettings InVSSettings, StringBuilder ProjectFileBuilder) { } /// /// Return any custom property group lines /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// String builder for the project file /// string The custom property import lines for the project file; Empty string if it doesn't require one public virtual void GetAdditionalVisualStudioPropertyGroups(VSSettings InVSSettings, StringBuilder ProjectFileBuilder) { } /// /// Return any custom property group lines /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// string The platform configuration type. Defaults to "Makefile" unless overridden public virtual string GetVisualStudioPlatformConfigurationType(VSSettings InVSSettings) { return DefaultPlatformConfigurationType; } /// /// Return any custom paths for VisualStudio this platform requires /// This include ReferencePath, LibraryPath, LibraryWPath, IncludePath and ExecutablePath. /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// The type of target (game or program) /// Path to the .target.cs file /// /// /// String builder for the project file /// The custom path lines for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioPathsEntries(VSSettings InVSSettings, TargetType TargetType, FileReference TargetRulesPath, FileReference ProjectFilePath, FileReference NMakeOutputPath, StringBuilder ProjectFileBuilder) { } /// /// Return any custom property settings. These will be included in the ImportGroup section /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// String builder for the project file /// string The custom property import lines for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioImportGroupProperties(VSSettings InVSSettings, StringBuilder ProjectFileBuilder) { } /// /// Return any custom property settings. These will be included right after Global properties to make values available to all other imports. /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// String builder for the project file /// string The custom property import lines for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioGlobalProperties(VSSettings InVSSettings, StringBuilder ProjectFileBuilder) { } /// /// Return any custom target overrides. These will be included last in the project file so they have the opportunity to override any existing settings. /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// String builder for the project file /// string The custom property import lines for the project file; Empty string if it doesn't require one public virtual void GetVisualStudioTargetOverrides(VSSettings InVSSettings, StringBuilder ProjectFileBuilder) { } /// /// Return any custom layout directory sections /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// /// The type of target (game or program) /// /// /// /// string The custom property import lines for the project file; Empty string if it doesn't require one public virtual string GetVisualStudioLayoutDirSection(VSSettings InVSSettings, string InConditionString, TargetType TargetType, FileReference TargetRulesPath, FileReference ProjectFilePath, FileReference NMakeOutputPath) { return ""; } /// /// Get the output manifest section, if required /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// The type of the target being built /// Path to the .target.cs file /// Path to the project file /// The output manifest section for the project file; Empty string if it doesn't require one public virtual string GetVisualStudioOutputManifestSection(VSSettings InVSSettings, TargetType TargetType, FileReference TargetRulesPath, FileReference ProjectFilePath) { return ""; } /// /// Get whether this platform deploys /// /// bool true if the 'Deploy' option should be enabled public virtual bool GetVisualStudioDeploymentEnabled(VSSettings InVSSettings) { return false; } /// /// Additional configuration related to Visual Studio user file (.vcxproj.user). /// public class VisualStudioUserFileSettings { public IReadOnlySet PropertiesToPatch => PropertiesToPatchContainer; public IReadOnlySet PropertiesToPatchOrderButPreserveValue => PropertiesToPatchOrderButPreserveValueContainer; /// /// Patch existing .vcxproj.user file based on the new file content and corresponding patching settings, by doing the following: /// - Go over every <PropertyGroup> in the new document. /// - Finds <PropertyGroup> in the current document with matching "Condition" attribute. /// - If no property group is found, appends property group from new document to the end of current document. /// - Otherwise, saves values of properties configured with bPreserveExistingValue == true. /// - Removes all properties flagged for patching from current document property group. /// - Adds all properties required for patching from new document property group as declared in new document order. /// /// This makes possible to override some properties crucial for UE features while keeping rest of user configuration intact. /// /// Otherwise, if .vcxproj.user doesn't exist, patching do nothing and instead creates a new file based on new file content. /// /// Name of the property to patch. /// If true, the value of the property will be taken from existing user file, but relative order will be taken from newly generated file. public void PatchProperty(string PropertyName, bool bPreserveExistingValue = false) { if (!PropertiesToPatchContainer.Contains(PropertyName)) { PropertiesToPatchContainer.Add(PropertyName); } if (bPreserveExistingValue && !PropertiesToPatchOrderButPreserveValueContainer.Contains(PropertyName)) { PropertiesToPatchOrderButPreserveValueContainer.Add(PropertyName); } } private HashSet PropertiesToPatchContainer = new(); private HashSet PropertiesToPatchOrderButPreserveValueContainer = new(); } /// /// Get the text to insert into the user file for the given platform/configuration/target /// /// Configuration for user file creation/patching/etc. /// The ProjectFileSettings that contains the project platform/configuration/etc info being built /// The condition string /// The target rules /// The target rules path /// The project file path /// Output path for NMake /// The name of the project /// Path to foreign .uproject file, if any /// The string to append to the user file public virtual string GetVisualStudioUserFileStrings(VisualStudioUserFileSettings VCUserFileSettings, VSSettings InVSSettings, string InConditionString, TargetRules InTargetRules, FileReference TargetRulesPath, FileReference ProjectFilePath, FileReference? NMakeOutputPath, string ProjectName, string? ForeignUProjectPath) { return String.Empty; } /// /// For Additional Project Property files that need to be written out. This is currently used only on Android. /// public virtual void WriteAdditionalPropFile() { } /// /// For additional Project files (ex. *PROJECTNAME*-AndroidRun.androidproj.user) that needs to be written out. This is currently used only on Android. /// /// Project file this will be related to public virtual void WriteAdditionalProjUserFile(ProjectFile ProjectFile) { } /// /// For additional Project files (ex. *PROJECTNAME*-AndroidRun.androidproj) that needs to be written out. This is currently used only on Android. /// /// Project file this will be related to /// Project file written out, Solution folder it should be put in public virtual Tuple? WriteAdditionalProjFile(ProjectFile ProjectFile) { return null; } /// /// Gets the text to insert into the UnrealVS configuration file /// public virtual void GetUnrealVSConfigurationEntries(StringBuilder UnrealVSContent) { } /// /// Gets the text to insert into the Project files as additional build arguments for given platform/configuration /// /// The ProjectFileSettings that contains the project platform/configuration/etc info being built public virtual string GetExtraBuildArguments(VSSettings InVSSettings) { return ""; } /// /// Indicates whether this generator will be emitting additional build targets. /// Functionally, it's fine to return true and not return any additional text in GetVisualStudioTargetsString, but doing /// so may incur additional cost of preparing data for generation. /// /// The platform being added /// True if Targets will be generate, false otherwise. If true is returned, GetVisualStudioTargetsString will be called next. /// public virtual bool HasVisualStudioTargets(UnrealTargetPlatform InPlatform) { return false; } /// /// Get the text to insert into the Project files as additional build targets for the given platform. /// /// The platform being added /// List of build configurations for the platform /// String builder for the project file public virtual void GetVisualStudioTargetsString(UnrealTargetPlatform InPlatform, List InPlatformConfigurations, StringBuilder ProjectFileBuilder) { } /// /// Get include paths to system headers (STL, SDK, ...) needed for coding assistance features in IDE /// /// Target for which include paths shall be returned /// The list of include paths public virtual IList GetSystemIncludePaths(UEBuildTarget InTarget) { return new List(0); } } }