You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
829 lines
34 KiB
Diff
829 lines
34 KiB
Diff
From 53e7e3f327d27608575225420cd23829acfcd69b Mon Sep 17 00:00:00 2001
|
|
From: Henrique Fernandes Baggio <hebaggio@microsoft.com>
|
|
Date: Wed, 17 Jan 2024 19:49:54 -0800
|
|
Subject: [PATCH] [UE5.0] Project Generator for VS Workspace support
|
|
|
|
Adding a new Project Generator for Visual Studio that will be used for
|
|
the new support to opening `.uproject` files directly in the IDE without
|
|
generating the traditional `.sln` and .vcxproj files.
|
|
|
|
This is based on the QueryMode API in `ue5-main` and adapted to the
|
|
GenerateProjectFiles flow. The project files will contain information for each
|
|
Target+Configuration+Platform combinations that are used the project.
|
|
|
|
Visual Studio will automatically invoke this new generator during the flow to
|
|
open a `.uproject` file directly.
|
|
---
|
|
.../Configuration/UEBuildTarget.cs | 2 +-
|
|
.../Modes/GenerateProjectFilesMode.cs | 4 +
|
|
.../Platform/Windows/VCToolChain.cs | 26 ++
|
|
.../ProjectFiles/ProjectFileGenerator.cs | 5 +-
|
|
.../VSWorkspaceProjectFile.cs | 394 ++++++++++++++++++
|
|
.../VSWorkspaceProjectFileGenerator.cs | 248 +++++++++++
|
|
.../UnrealBuildTool/ToolChain/UEToolChain.cs | 20 +
|
|
7 files changed, 696 insertions(+), 3 deletions(-)
|
|
create mode 100644 Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFile.cs
|
|
create mode 100644 Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFileGenerator.cs
|
|
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs
|
|
index 25e98e1729cfb..04395105aaf64 100644
|
|
--- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs
|
|
@@ -2249,7 +2249,7 @@ List<RestrictedFolder> GetRestrictedFolders(FileReference File)
|
|
/// Creates a toolchain for the current target. May be overridden by the target rules.
|
|
/// </summary>
|
|
/// <returns>New toolchain instance</returns>
|
|
- private UEToolChain CreateToolchain(UnrealTargetPlatform Platform)
|
|
+ public UEToolChain CreateToolchain(UnrealTargetPlatform Platform)
|
|
{
|
|
if (Rules.ToolChainName == null)
|
|
{
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateProjectFilesMode.cs b/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateProjectFilesMode.cs
|
|
index 5ac8f51d12f4f..a6e0cde49cfa2 100644
|
|
--- a/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateProjectFilesMode.cs
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/Modes/GenerateProjectFilesMode.cs
|
|
@@ -35,6 +35,7 @@ class GenerateProjectFilesMode : ToolMode
|
|
[CommandLine("-EddieProjectFiles", Value = nameof(ProjectFileFormat.Eddie))]
|
|
[CommandLine("-VSCode", Value = nameof(ProjectFileFormat.VisualStudioCode))]
|
|
[CommandLine("-VSMac", Value = nameof(ProjectFileFormat.VisualStudioMac))]
|
|
+ [CommandLine("-VSWorkspace", Value = nameof(ProjectFileFormat.VisualStudioWorkspace))]
|
|
[CommandLine("-CLion", Value = nameof(ProjectFileFormat.CLion))]
|
|
[CommandLine("-Rider", Value = nameof(ProjectFileFormat.Rider))]
|
|
#if __VPROJECT_AVAILABLE__
|
|
@@ -202,6 +203,9 @@ public override int Execute(CommandLineArguments Arguments)
|
|
case ProjectFileFormat.VisualStudioCode:
|
|
Generator = new VSCodeProjectFileGenerator(ProjectFile);
|
|
break;
|
|
+ case ProjectFileFormat.VisualStudioWorkspace:
|
|
+ Generator = new VSWorkspaceProjectFileGenerator(ProjectFile, Arguments);
|
|
+ break;
|
|
case ProjectFileFormat.CLion:
|
|
Generator = new CLionGenerator(ProjectFile);
|
|
break;
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/Platform/Windows/VCToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Platform/Windows/VCToolChain.cs
|
|
index 80ec89d70e37a..287e8abd3e78f 100644
|
|
--- a/Engine/Source/Programs/UnrealBuildTool/Platform/Windows/VCToolChain.cs
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/Platform/Windows/VCToolChain.cs
|
|
@@ -47,6 +47,11 @@ public VCToolChain(ReadOnlyTargetRules Target)
|
|
}
|
|
}
|
|
|
|
+ public override FileReference? GetCppCompilerPath()
|
|
+ {
|
|
+ return EnvVars.CompilerPath;
|
|
+ }
|
|
+
|
|
/// <summary>
|
|
/// Prepares the environment for building
|
|
/// </summary>
|
|
@@ -209,6 +214,27 @@ public static void AddSourceDependsFile(List<string> Arguments, FileItem SourceD
|
|
Arguments.Add($"/clang:-MD /clang:-MF\"{SourceDependsFileString}\"");
|
|
}
|
|
|
|
+ public override IEnumerable<string> GetGlobalCommandLineArgs(CppCompileEnvironment CompileEnvironment)
|
|
+ {
|
|
+ List<string> Arguments = new List<string>();
|
|
+ AppendCLArguments_Global(new CppCompileEnvironment(CompileEnvironment), Arguments);
|
|
+ return Arguments;
|
|
+ }
|
|
+
|
|
+ public override IEnumerable<string> GetCPPCommandLineArgs(CppCompileEnvironment CompileEnvironment)
|
|
+ {
|
|
+ List<string> Arguments = new List<string>();
|
|
+ AppendCLArguments_CPP(CompileEnvironment, Arguments);
|
|
+ return Arguments;
|
|
+ }
|
|
+
|
|
+ public override IEnumerable<string> GetCCommandLineArgs(CppCompileEnvironment CompileEnvironment)
|
|
+ {
|
|
+ List<string> Arguments = new List<string>();
|
|
+ AppendCLArguments_C(Arguments);
|
|
+ return Arguments;
|
|
+ }
|
|
+
|
|
protected virtual void AppendCLArguments_Global(CppCompileEnvironment CompileEnvironment, List<string> Arguments)
|
|
{
|
|
// Suppress generation of object code for unreferenced inline functions. Enabling this option is more standards compliant, and causes a big reduction
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/ProjectFileGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/ProjectFileGenerator.cs
|
|
index 1e8e7e609c166..4276988ed1374 100644
|
|
--- a/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/ProjectFileGenerator.cs
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/ProjectFileGenerator.cs
|
|
@@ -132,6 +132,7 @@ enum ProjectFileFormat
|
|
VisualStudio,
|
|
VisualStudio2019,
|
|
VisualStudio2022,
|
|
+ VisualStudioWorkspace,
|
|
XCode,
|
|
Eddie,
|
|
VisualStudioCode,
|
|
@@ -2297,7 +2298,7 @@ private ProjectFile FindProjectForModule(FileReference CurModuleFile, List<FileR
|
|
/// <param name="GameProjects">Map of game folder name to all of the game projects we created</param>
|
|
/// <param name="ProgramProjects">Map of program names to all of the program projects we created</param>
|
|
/// <param name="RulesAssemblies">Map of RuleAssemblies to their base folders</param>
|
|
- private void AddProjectsForAllTargets(
|
|
+ protected void AddProjectsForAllTargets(
|
|
PlatformProjectGeneratorCollection PlatformProjectGenerators,
|
|
List<FileReference> AllGames,
|
|
List<FileReference> AllTargetFiles,
|
|
@@ -2619,7 +2620,7 @@ protected void AddProjectsForMods(List<ProjectFile> GameProjects, out List<Proje
|
|
/// </summary>
|
|
/// <param name="BaseName">The base name for the project file</param>
|
|
/// <returns>Full path to the project file</returns>
|
|
- protected FileReference GetProjectLocation(string BaseName)
|
|
+ protected virtual FileReference GetProjectLocation(string BaseName)
|
|
{
|
|
return FileReference.Combine(IntermediateProjectFilesPath, BaseName + ProjectFileExtension);
|
|
}
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFile.cs b/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFile.cs
|
|
new file mode 100644
|
|
index 0000000000000..05c5473a616db
|
|
--- /dev/null
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFile.cs
|
|
@@ -0,0 +1,394 @@
|
|
+// Copyright Epic Games, Inc. All Rights Reserved.
|
|
+
|
|
+using System;
|
|
+using System.Collections.Generic;
|
|
+using System.IO;
|
|
+using System.Linq;
|
|
+using System.Text;
|
|
+using System.Text.Json;
|
|
+using EpicGames.Core;
|
|
+using Microsoft.Extensions.Logging;
|
|
+using UnrealBuildBase;
|
|
+
|
|
+namespace UnrealBuildTool
|
|
+{
|
|
+ internal class VSWorkspaceProjectFile : ProjectFile
|
|
+ {
|
|
+ private readonly DirectoryReference RootPath;
|
|
+ private readonly HashSet<TargetType> TargetTypes;
|
|
+ private readonly CommandLineArguments Arguments;
|
|
+ private VCProjectFileSettings Settings;
|
|
+ private bool bUsePrecompiled;
|
|
+
|
|
+ /// <summary>
|
|
+ /// Collection of output files for this project
|
|
+ /// </summary>
|
|
+ public List<ExportedTargetInfo> ExportedTargetProjects { get; set; } = new List<ExportedTargetInfo>();
|
|
+
|
|
+ public VSWorkspaceProjectFile(FileReference InProjectFilePath, DirectoryReference BaseDir,
|
|
+ DirectoryReference RootPath, HashSet<TargetType> TargetTypes, CommandLineArguments Arguments, VCProjectFileSettings Settings, bool bUsePrecompiled)
|
|
+ : base(InProjectFilePath, BaseDir)
|
|
+ {
|
|
+ this.RootPath = RootPath;
|
|
+ this.TargetTypes = TargetTypes;
|
|
+ this.Arguments = Arguments;
|
|
+ this.Settings = Settings;
|
|
+ this.bUsePrecompiled = bUsePrecompiled;
|
|
+ }
|
|
+
|
|
+ /// <summary>
|
|
+ /// Write project file info in JSON file.
|
|
+ /// For every combination of <c>UnrealTargetPlatform</c>, <c>UnrealTargetConfiguration</c> and <c>TargetType</c>
|
|
+ /// will be generated separate JSON file.
|
|
+ /// </summary>
|
|
+ public bool WriteProjectFile(List<UnrealTargetPlatform> InPlatforms,
|
|
+ List<UnrealTargetConfiguration> InConfigurations,
|
|
+ PlatformProjectGeneratorCollection PlatformProjectGenerators, JsonWriterStyle Minimize)
|
|
+ {
|
|
+ DirectoryReference ProjectRootFolder = RootPath;
|
|
+
|
|
+ Dictionary<FileReference, (UEBuildTarget BuildTarget, bool bBuildByDefault)> FileToTarget = new Dictionary<FileReference, (UEBuildTarget, bool)>();
|
|
+
|
|
+ foreach (UnrealTargetPlatform Platform in InPlatforms)
|
|
+ {
|
|
+ foreach (UnrealTargetConfiguration Configuration in InConfigurations)
|
|
+ {
|
|
+ foreach (ProjectTarget ProjectTarget in ProjectTargets.OfType<ProjectTarget>())
|
|
+ {
|
|
+ if (TargetTypes.Any() && !TargetTypes.Contains(ProjectTarget.TargetRules!.Type))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // Skip Programs for all configs except for current platform + Development & Debug configurations
|
|
+ if (ProjectTarget.TargetRules!.Type == TargetType.Program &&
|
|
+ (BuildHostPlatform.Current.Platform != Platform ||
|
|
+ !(Configuration == UnrealTargetConfiguration.Development || Configuration == UnrealTargetConfiguration.Debug)))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // Skip Editor for all platforms except for current platform
|
|
+ if (ProjectTarget.TargetRules.Type == TargetType.Editor &&
|
|
+ (BuildHostPlatform.Current.Platform != Platform ||
|
|
+ (Configuration == UnrealTargetConfiguration.Test || Configuration == UnrealTargetConfiguration.Shipping)))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ bool bBuildByDefault = ShouldBuildByDefaultForSolutionTargets && ProjectTarget.SupportedPlatforms.Contains(Platform);
|
|
+
|
|
+ string DefaultArchitecture = UEBuildPlatform
|
|
+ .GetBuildPlatform(Platform)
|
|
+ .GetDefaultArchitecture(ProjectTarget.UnrealProjectFilePath);
|
|
+
|
|
+ TargetDescriptor TargetDesc = new TargetDescriptor(ProjectTarget.UnrealProjectFilePath, ProjectTarget.Name,
|
|
+ Platform, Configuration, DefaultArchitecture, Arguments);
|
|
+
|
|
+ try
|
|
+ {
|
|
+ FileReference OutputFile = FileReference.Combine(ProjectRootFolder,
|
|
+ $"{ProjectTarget.TargetFilePath.GetFileNameWithoutAnyExtensions()}_{Configuration}_{Platform}.json");
|
|
+
|
|
+ UEBuildTarget BuildTarget = UEBuildTarget.Create(TargetDesc, false, false, false);
|
|
+ FileToTarget.Add(OutputFile, (BuildTarget, bBuildByDefault));
|
|
+ }
|
|
+ catch (Exception Ex)
|
|
+ {
|
|
+ Log.TraceWarning("Exception while generating include data for Target:{Target}, Platform: {Platform}, Configuration: {Configuration}", TargetDesc.Name, Platform.ToString(), Configuration.ToString());
|
|
+ Log.TraceWarning("{Ex}", Ex.ToString());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ foreach (var Entry in FileToTarget)
|
|
+ {
|
|
+ var OutputFile = Entry.Key;
|
|
+ var BuildTarget = Entry.Value.BuildTarget;
|
|
+ var bBuildByDefault = Entry.Value.bBuildByDefault;
|
|
+
|
|
+ try
|
|
+ {
|
|
+ BuildTarget.PreBuildSetup();
|
|
+
|
|
+ ExportedTargetInfo TargetInfo = ExportTarget(BuildTarget, bBuildByDefault, PlatformProjectGenerators);
|
|
+
|
|
+ DirectoryReference.CreateDirectory(OutputFile.Directory);
|
|
+
|
|
+ File.WriteAllText(OutputFile.FullName, JsonSerializer.Serialize(TargetInfo, options: new JsonSerializerOptions()
|
|
+ {
|
|
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
+ WriteIndented = Minimize == JsonWriterStyle.Readable,
|
|
+ }));
|
|
+
|
|
+ ExportedTargetProjects.Add(TargetInfo);
|
|
+ }
|
|
+ catch (Exception Ex)
|
|
+ {
|
|
+ Log.TraceWarning("Exception while generating include data for Target:{Target}, Platform: {Platform}, Configuration: {Configuration}",
|
|
+ BuildTarget.AppName, BuildTarget.Platform.ToString(), BuildTarget.Configuration.ToString());
|
|
+ Log.TraceWarning("{Ex}", Ex.ToString());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ private ExportedTargetInfo ExportTarget(
|
|
+ UEBuildTarget Target, bool bBuildByDefault, PlatformProjectGeneratorCollection PlatformProjectGenerators)
|
|
+ {
|
|
+ ExportedTargetInfo TargetInfo = new ExportedTargetInfo()
|
|
+ {
|
|
+ TargetName = Target.TargetName,
|
|
+ TargetPath = Target.TargetRulesFile.FullName,
|
|
+ ProjectPath = Target.ProjectFile?.FullName ?? String.Empty,
|
|
+ TargetType = Target.TargetType.ToString(),
|
|
+ Platform = Target.Platform.ToString(),
|
|
+ Configuration = Target.Configuration.ToString(),
|
|
+ BuildInfo = ExportBuildInfo(Target, PlatformProjectGenerators, bBuildByDefault)
|
|
+ };
|
|
+
|
|
+ UEToolChain TargetToolChain = Target.CreateToolchain(Target.Platform);
|
|
+ CppCompileEnvironment GlobalCompileEnvironment = Target.CreateCompileEnvironmentForProjectFiles();
|
|
+
|
|
+ HashSet<string> ModuleNames = new HashSet<string>();
|
|
+ foreach (UEBuildBinary Binary in Target.Binaries)
|
|
+ {
|
|
+ CppCompileEnvironment BinaryCompileEnvironment = Binary.CreateBinaryCompileEnvironment(GlobalCompileEnvironment);
|
|
+ IEnumerable<UEBuildModuleCPP> CandidateModules = Binary.Modules.Where(x => x is UEBuildModuleCPP).Cast<UEBuildModuleCPP>();
|
|
+
|
|
+ foreach (var ModuleCpp in CandidateModules)
|
|
+ {
|
|
+ if (!ModuleNames.Add(ModuleCpp.Name))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ CppCompileEnvironment ModuleCompileEnvironment = ModuleCpp.CreateCompileEnvironmentForIntellisense(Target.Rules, BinaryCompileEnvironment);
|
|
+ TargetInfo.ModuleToCompileSettings.Add(ModuleCpp.Name, ExportModule(ModuleCpp, TargetToolChain, ModuleCompileEnvironment));
|
|
+
|
|
+ foreach (DirectoryReference ModuleDirectory in ModuleCpp.ModuleDirectories)
|
|
+ {
|
|
+ TargetInfo.DirToModule.TryAdd(ModuleDirectory.FullName, ModuleCpp.Name);
|
|
+ }
|
|
+
|
|
+ if (ModuleCpp.GeneratedCodeDirectory != null)
|
|
+ {
|
|
+ TargetInfo.DirToModule.TryAdd(ModuleCpp.GeneratedCodeDirectory.FullName, ModuleCpp.Name);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return TargetInfo;
|
|
+ }
|
|
+
|
|
+ private static ExportedModuleInfo ExportModule(UEBuildModuleCPP Module, UEToolChain TargetToolChain, CppCompileEnvironment ModuleCompileEnvironment)
|
|
+ {
|
|
+ ExportedModuleInfo Result = new ExportedModuleInfo()
|
|
+ {
|
|
+ Name = Module.Name,
|
|
+ Directory = Module.ModuleDirectory.FullName,
|
|
+ Rules = Module.RulesFile.FullName,
|
|
+ GeneratedCodeDirectory = Module.GeneratedCodeDirectory != null ? Module.GeneratedCodeDirectory.FullName : String.Empty,
|
|
+ Standard = ModuleCompileEnvironment.CppStandard.ToString(),
|
|
+ };
|
|
+
|
|
+ Result.IncludePaths.AddRange(Module.PublicIncludePaths.Select(x => x.FullName));
|
|
+ Result.IncludePaths.AddRange(Module.PublicSystemIncludePaths.Select(x => x.FullName));
|
|
+ Result.IncludePaths.AddRange(Module.InternalIncludePaths.Select(x => x.FullName));
|
|
+ Result.IncludePaths.AddRange(Module.LegacyPublicIncludePaths.Select(x => x.FullName));
|
|
+ Result.IncludePaths.AddRange(Module.PrivateIncludePaths.Select(x => x.FullName));
|
|
+
|
|
+ Result.IncludePaths.AddRange(ModuleCompileEnvironment.UserIncludePaths.Select(x => x.FullName));
|
|
+
|
|
+ Result.IncludePaths.AddRange(Module.PublicSystemLibraryPaths.Select(x => x.FullName));
|
|
+ Result.IncludePaths.AddRange(Module.PublicSystemLibraries.Concat(Module.PublicLibraries.Select(x => x.FullName)));
|
|
+
|
|
+ if (TargetToolChain is VCToolChain TargetVCToolChain)
|
|
+ {
|
|
+ string VCIncludePaths = VCToolChain.GetVCIncludePaths(ModuleCompileEnvironment.Platform, WindowsCompiler.VisualStudio2022, null);
|
|
+ Result.IncludePaths.AddRange(VCIncludePaths.Split(";"));
|
|
+ }
|
|
+
|
|
+ Result.Defines.AddRange(Module.PublicDefinitions);
|
|
+ Result.Defines.AddRange(Module.Rules.PrivateDefinitions);
|
|
+ Result.Defines.AddRange(Module.Rules.bTreatAsEngineModule ? Array.Empty<string>() : Module.Rules.Target.ProjectDefinitions);
|
|
+ Result.Defines.AddRange(Module.GetEmptyApiMacros());
|
|
+
|
|
+ var ForcedIncludes = ModuleCompileEnvironment.ForceIncludeFiles.ToList();
|
|
+ if (ModuleCompileEnvironment.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
|
|
+ {
|
|
+ FileItem IncludeHeader = FileItem.GetItemByFileReference(ModuleCompileEnvironment.PrecompiledHeaderIncludeFilename!);
|
|
+ ForcedIncludes.Insert(0, IncludeHeader);
|
|
+ }
|
|
+
|
|
+ Result.ForcedIncludes.AddRange(ForcedIncludes.Select(x => x.FullName));
|
|
+
|
|
+ Result.CompilerPath = TargetToolChain.GetCppCompilerPath()?.ToString();
|
|
+ Result.CompilerArgs.AddRange(TargetToolChain.GetGlobalCommandLineArgs(ModuleCompileEnvironment));
|
|
+ Result.CompilerAdditionalArgs.Add("c", TargetToolChain.GetCCommandLineArgs(ModuleCompileEnvironment).ToList());
|
|
+ Result.CompilerAdditionalArgs.Add("cpp", TargetToolChain.GetCPPCommandLineArgs(ModuleCompileEnvironment).ToList());
|
|
+
|
|
+ return Result;
|
|
+ }
|
|
+
|
|
+ private TargetBuildInfo? ExportBuildInfo(UEBuildTarget Target, PlatformProjectGeneratorCollection PlatformProjectGenerators, bool bBuildByDefault)
|
|
+ {
|
|
+ if (!BuildHostPlatform.Current.Platform.IsInGroup(UnrealPlatformGroup.Windows))
|
|
+ {
|
|
+ Log.TraceWarning("Unsupported platform for Build Information: {Platform}", BuildHostPlatform.Current.Platform.ToString());
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if (IsStubProject)
|
|
+ {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ ProjectTarget ProjectTarget = ProjectTargets.OfType<ProjectTarget>().Single(It => Target.TargetRulesFile == It.TargetFilePath);
|
|
+ UnrealTargetPlatform Platform = Target.Platform;
|
|
+ UnrealTargetConfiguration Configuration = Target.Configuration;
|
|
+
|
|
+ string UProjectPath = "";
|
|
+ if (IsForeignProject)
|
|
+ {
|
|
+ UProjectPath = String.Format("\"{0}\"", ProjectTarget.UnrealProjectFilePath!.FullName);
|
|
+ }
|
|
+
|
|
+ PlatformProjectGenerator? ProjGenerator = PlatformProjectGenerators.GetPlatformProjectGenerator(Platform, true);
|
|
+
|
|
+ string BuildArguments = GetBuildArguments(ProjGenerator, ProjectTarget, Target, UProjectPath);
|
|
+
|
|
+ return new TargetBuildInfo()
|
|
+ {
|
|
+ BuildCmd = $"{GetBuildScript("Build")} {BuildArguments}",
|
|
+ RebuildCmd = $"{GetBuildScript("Rebuild")} {BuildArguments}",
|
|
+ CleanCmd = $"{GetBuildScript("Clean")} {BuildArguments}",
|
|
+ PrimaryOutput = Target.Binaries[0].OutputFilePath.FullName,
|
|
+ BuildByDefault = bBuildByDefault,
|
|
+ };
|
|
+ }
|
|
+
|
|
+ private string GetBuildScript(string Cmd)
|
|
+ {
|
|
+ DirectoryReference BatchFilesDirectory = DirectoryReference.Combine(Unreal.EngineDirectory, "Build", "BatchFiles");
|
|
+ return EscapePath(FileReference.Combine(BatchFilesDirectory, $"{Cmd}.bat").FullName);
|
|
+ }
|
|
+
|
|
+ private string GetBuildArguments(
|
|
+ PlatformProjectGenerator? ProjGenerator, ProjectTarget ProjectTarget, UEBuildTarget Target, string UProjectPath)
|
|
+ {
|
|
+ UnrealTargetConfiguration Configuration = Target.Configuration;
|
|
+ UnrealTargetPlatform Platform = Target.Platform;
|
|
+ string TargetName = ProjectTarget.TargetFilePath.GetFileNameWithoutAnyExtensions();
|
|
+ TargetRules TargetRulesObject = ProjectTarget.TargetRules!;
|
|
+
|
|
+ // This is the standard UE based project NMake build line:
|
|
+ // ..\..\Build\BatchFiles\Build.bat <TARGETNAME> <PLATFORM> <CONFIGURATION>
|
|
+ // ie ..\..\Build\BatchFiles\Build.bat BlankProgram Win64 Debug
|
|
+
|
|
+ StringBuilder BuildArguments = new StringBuilder();
|
|
+
|
|
+ BuildArguments.AppendFormat("{0} {1} {2}", TargetName, Configuration, Platform);
|
|
+ if (IsForeignProject)
|
|
+ {
|
|
+ BuildArguments.AppendFormat(" -Project={0}", UProjectPath);
|
|
+ }
|
|
+
|
|
+ List<string> ExtraTargets = new List<string>();
|
|
+ if (!bUsePrecompiled)
|
|
+ {
|
|
+ if (TargetRulesObject.Type == TargetType.Editor && Settings.bEditorDependsOnShaderCompileWorker && !Unreal.IsEngineInstalled())
|
|
+ {
|
|
+ ExtraTargets.Add("ShaderCompileWorker Win64 Development");
|
|
+ }
|
|
+ if (TargetRulesObject.bWithLiveCoding && Settings.bBuildLiveCodingConsole && !Unreal.IsEngineInstalled() && TargetRulesObject.Name != "LiveCodingConsole")
|
|
+ {
|
|
+ ExtraTargets.Add(TargetRulesObject.bUseDebugLiveCodingConsole ? "LiveCodingConsole Win64 Debug" : "LiveCodingConsole Win64 Development");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ExtraTargets.Count > 0)
|
|
+ {
|
|
+ BuildArguments.Replace("\"", "\\\"");
|
|
+ BuildArguments.Insert(0, "-Target=\"");
|
|
+ BuildArguments.Append("\"");
|
|
+ foreach (string ExtraTarget in ExtraTargets)
|
|
+ {
|
|
+ BuildArguments.AppendFormat(" -Target=\"{0} -Quiet\"", ExtraTarget);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (bUsePrecompiled)
|
|
+ {
|
|
+ BuildArguments.Append(" -UsePrecompiled");
|
|
+ }
|
|
+
|
|
+ // Always wait for the mutex between UBT invocations, so that building the whole solution doesn't fail.
|
|
+ BuildArguments.Append(" -WaitMutex");
|
|
+
|
|
+ // Always include a flag to format log messages for MSBuild
|
|
+ BuildArguments.Append(" -FromMsBuild");
|
|
+
|
|
+ if (Settings.bAddFastPDBToProjects)
|
|
+ {
|
|
+ // Pass Fast PDB option to make use of Visual Studio's /DEBUG:FASTLINK option
|
|
+ BuildArguments.Append(" -FastPDB");
|
|
+ }
|
|
+
|
|
+ if (ProjGenerator != null)
|
|
+ {
|
|
+ BuildArguments.Append(ProjGenerator.GetExtraBuildArguments(Platform, Configuration));
|
|
+ }
|
|
+
|
|
+ return BuildArguments.ToString();
|
|
+ }
|
|
+
|
|
+ private static void WriteCommand(JsonWriter Writer, string CommandName, string Command, string Arguments)
|
|
+ {
|
|
+ Writer.WriteObjectStart(CommandName);
|
|
+ Writer.WriteValue("Command", Command);
|
|
+ Writer.WriteValue("Args", Arguments);
|
|
+ Writer.WriteObjectEnd();
|
|
+ }
|
|
+
|
|
+ internal class ExportedTargetInfo
|
|
+ {
|
|
+ public string TargetName { get; set; } = String.Empty;
|
|
+ public string TargetPath { get; set; } = String.Empty;
|
|
+ public string ProjectPath { get; set; } = String.Empty;
|
|
+ public string TargetType { get; set; } = String.Empty;
|
|
+ public string Platform { get; set; } = String.Empty;
|
|
+ public string Configuration { get; set; } = String.Empty;
|
|
+ public TargetBuildInfo? BuildInfo { get; set; }
|
|
+ public Dictionary<string, ExportedModuleInfo> ModuleToCompileSettings { get; set; } = new Dictionary<string, ExportedModuleInfo>();
|
|
+ public Dictionary<string, string> DirToModule { get; set; } = new Dictionary<string, string>();
|
|
+ }
|
|
+
|
|
+ internal class ExportedModuleInfo
|
|
+ {
|
|
+ public string Name { get; set; } = String.Empty;
|
|
+ public string Directory { get; set; } = String.Empty;
|
|
+ public string Rules { get; set; } = String.Empty;
|
|
+ public string GeneratedCodeDirectory { get; set; } = String.Empty;
|
|
+ public List<string> IncludePaths { get; set; } = new List<string>();
|
|
+ public List<string> Defines { get; set; } = new List<string>();
|
|
+ public string? Standard { get; set; }
|
|
+ public List<string> ForcedIncludes { get; set; } = new List<string>();
|
|
+ public string? CompilerPath { get; set; }
|
|
+ public List<string> CompilerArgs { get; set; } = new List<string>();
|
|
+ public Dictionary<string, List<string>> CompilerAdditionalArgs { get; set; } = new Dictionary<string, List<string>>();
|
|
+ public string? WindowsSdkVersion { get; set; }
|
|
+ }
|
|
+
|
|
+ internal class TargetBuildInfo
|
|
+ {
|
|
+ public string BuildCmd { get; set; } = String.Empty;
|
|
+ public string RebuildCmd { get; set; } = String.Empty;
|
|
+ public string CleanCmd { get; set; } = String.Empty;
|
|
+ public string PrimaryOutput { get; set; } = String.Empty;
|
|
+ public bool BuildByDefault { get; internal set; }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFileGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFileGenerator.cs
|
|
new file mode 100644
|
|
index 0000000000000..454e291171e00
|
|
--- /dev/null
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/VisualStudioWorkspace/VSWorkspaceProjectFileGenerator.cs
|
|
@@ -0,0 +1,248 @@
|
|
+// Copyright Epic Games, Inc. All Rights Reserved.
|
|
+
|
|
+using System;
|
|
+using System.Collections.Generic;
|
|
+using System.IO;
|
|
+using System.Linq;
|
|
+using System.Text.Json;
|
|
+using EpicGames.Core;
|
|
+using Microsoft.Extensions.Logging;
|
|
+using UnrealBuildBase;
|
|
+
|
|
+namespace UnrealBuildTool
|
|
+{
|
|
+ class VSWorkspaceProjectFileGenerator : ProjectFileGenerator
|
|
+ {
|
|
+ public override string ProjectFileExtension => ".json";
|
|
+
|
|
+ // These properties are used by Visual Studio to determine where to read the project files.
|
|
+ // So they must remain constant.
|
|
+ private const string VSUnrealWorkspaceFileName = ".vs-unreal-workspace";
|
|
+ private const string ProjectFilesFolder = "VisualStudio";
|
|
+
|
|
+ private readonly CommandLineArguments Arguments;
|
|
+
|
|
+ /// <summary>
|
|
+ /// List of deprecated platforms.
|
|
+ /// Don't generate project model for these platforms unless they are specified in "Platforms" console arguments.
|
|
+ /// </summary>
|
|
+ /// <returns></returns>
|
|
+ private readonly HashSet<UnrealTargetPlatform> DeprecatedPlatforms = new HashSet<UnrealTargetPlatform>();
|
|
+
|
|
+ /// <summary>
|
|
+ /// Platforms to generate project files for
|
|
+ /// </summary>
|
|
+ [CommandLine("-Platforms=", ListSeparator = '+')]
|
|
+ HashSet<UnrealTargetPlatform> Platforms = new HashSet<UnrealTargetPlatform>();
|
|
+
|
|
+ /// <summary>
|
|
+ /// Target types to generate project files for
|
|
+ /// </summary>
|
|
+ [CommandLine("-TargetTypes=", ListSeparator = '+')]
|
|
+ HashSet<TargetType> TargetTypes = new HashSet<TargetType>();
|
|
+
|
|
+ /// <summary>
|
|
+ /// Target configurations to generate project files for
|
|
+ /// </summary>
|
|
+ [CommandLine("-TargetConfigurations=", ListSeparator = '+')]
|
|
+ HashSet<UnrealTargetConfiguration> TargetConfigurations = new HashSet<UnrealTargetConfiguration>();
|
|
+
|
|
+ /// <summary>
|
|
+ /// Projects to generate project files for
|
|
+ /// </summary>
|
|
+ [CommandLine("-ProjectNames=", ListSeparator = '+')]
|
|
+ HashSet<string> ProjectNames = new HashSet<string>();
|
|
+
|
|
+ /// <summary>
|
|
+ /// Should format JSON files in human readable form, or use packed one without indents
|
|
+ /// </summary>
|
|
+ [CommandLine("-Minimize", Value = "Compact")]
|
|
+ private JsonWriterStyle Minimize = JsonWriterStyle.Readable;
|
|
+
|
|
+ /// <summary>
|
|
+ /// The settings object
|
|
+ /// </summary>
|
|
+ protected VCProjectFileSettings Settings = new VCProjectFileSettings();
|
|
+
|
|
+ public VSWorkspaceProjectFileGenerator(FileReference? InOnlyGameProject,
|
|
+ CommandLineArguments InArguments)
|
|
+ : base(InOnlyGameProject)
|
|
+ {
|
|
+ Arguments = InArguments;
|
|
+ Arguments.ApplyTo(this);
|
|
+ XmlConfig.ApplyTo(Settings);
|
|
+ }
|
|
+
|
|
+ public override bool ShouldGenerateIntelliSenseData() => true;
|
|
+
|
|
+ public override void CleanProjectFiles(DirectoryReference InPrimaryProjectDirectory, string InPrimaryProjectName,
|
|
+ DirectoryReference InIntermediateProjectFilesDirectory)
|
|
+ {
|
|
+ DirectoryReference.Delete(InPrimaryProjectDirectory);
|
|
+ }
|
|
+
|
|
+ protected override void ConfigureProjectFileGeneration(string[] Arguments, ref bool IncludeAllPlatforms)
|
|
+ {
|
|
+ base.ConfigureProjectFileGeneration(Arguments, ref IncludeAllPlatforms);
|
|
+ }
|
|
+
|
|
+ protected override ProjectFile AllocateProjectFile(FileReference InitFilePath, DirectoryReference BaseDir)
|
|
+ {
|
|
+ VSWorkspaceProjectFile projectFile = new VSWorkspaceProjectFile(InitFilePath, BaseDir, InitFilePath.Directory,
|
|
+ TargetTypes, Arguments, Settings, bUsePrecompiled);
|
|
+ return projectFile;
|
|
+ }
|
|
+
|
|
+ protected override bool WriteProjectFiles(PlatformProjectGeneratorCollection PlatformProjectGenerators)
|
|
+ {
|
|
+ using ProgressWriter Progress = new ProgressWriter("Writing project files...", true);
|
|
+ List<ProjectFile> ProjectsToGenerate = new List<ProjectFile>(GeneratedProjectFiles);
|
|
+ if (ProjectNames.Any())
|
|
+ {
|
|
+ ProjectsToGenerate = ProjectsToGenerate.Where(Project =>
|
|
+ ProjectNames.Contains(Project.ProjectFilePath.GetFileNameWithoutAnyExtensions())).ToList();
|
|
+ }
|
|
+
|
|
+ int TotalProjectFileCount = ProjectsToGenerate.Count;
|
|
+
|
|
+ HashSet<UnrealTargetPlatform> PlatformsToGenerate = new HashSet<UnrealTargetPlatform>(SupportedPlatforms);
|
|
+ if (Platforms.Any())
|
|
+ {
|
|
+ PlatformsToGenerate.IntersectWith(Platforms);
|
|
+ }
|
|
+
|
|
+ List<UnrealTargetPlatform> FilteredPlatforms = PlatformsToGenerate.Where(Platform =>
|
|
+ {
|
|
+ // Skip deprecated unless explicitly specified in the command line.
|
|
+ return (!DeprecatedPlatforms.Contains(Platform) || Platforms.Contains(Platform))
|
|
+ && UEBuildPlatform.IsPlatformAvailable(Platform);
|
|
+ }).ToList();
|
|
+
|
|
+ HashSet<UnrealTargetConfiguration> ConfigurationsToGenerate = new HashSet<UnrealTargetConfiguration>(SupportedConfigurations);
|
|
+ if (TargetConfigurations.Any())
|
|
+ {
|
|
+ ConfigurationsToGenerate.IntersectWith(TargetConfigurations);
|
|
+ }
|
|
+
|
|
+ List<UnrealTargetConfiguration> Configurations = ConfigurationsToGenerate.ToList();
|
|
+
|
|
+ for (int ProjectFileIndex = 0; ProjectFileIndex < ProjectsToGenerate.Count; ++ProjectFileIndex)
|
|
+ {
|
|
+ VSWorkspaceProjectFile? CurrentProject = ProjectsToGenerate[ProjectFileIndex] as VSWorkspaceProjectFile;
|
|
+ if (CurrentProject == null)
|
|
+ {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (!CurrentProject.WriteProjectFile(FilteredPlatforms, Configurations, PlatformProjectGenerators, Minimize))
|
|
+ {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ Progress.Write(ProjectFileIndex + 1, TotalProjectFileCount);
|
|
+ }
|
|
+
|
|
+ Progress.Write(TotalProjectFileCount, TotalProjectFileCount);
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ public override bool GenerateProjectFiles(PlatformProjectGeneratorCollection PlatformProjectGenerators,
|
|
+ String[] Arguments)
|
|
+ {
|
|
+ bool IncludeAllPlatforms = true;
|
|
+ ConfigureProjectFileGeneration(Arguments, ref IncludeAllPlatforms);
|
|
+
|
|
+ if (bGeneratingGameProjectFiles || Unreal.IsEngineInstalled())
|
|
+ {
|
|
+ PrimaryProjectPath = OnlyGameProject!.Directory;
|
|
+ PrimaryProjectName = OnlyGameProject.GetFileNameWithoutExtension();
|
|
+
|
|
+ IntermediateProjectFilesPath =
|
|
+ DirectoryReference.Combine(PrimaryProjectPath, "Intermediate", "ProjectFiles");
|
|
+ }
|
|
+
|
|
+ SetupSupportedPlatformsAndConfigurations(IncludeAllPlatforms: true, out string SupportedPlatformNames);
|
|
+ Log.TraceVerbose("Supported platforms: {Platforms}", SupportedPlatformNames);
|
|
+
|
|
+ List<FileReference> AllGames = FindGameProjects();
|
|
+
|
|
+ {
|
|
+ // Find all of the target files.
|
|
+ List<FileReference> AllTargetFiles = DiscoverTargets(AllGames);
|
|
+
|
|
+ // If there are multiple targets of a given type for a project, use the order to determine which one gets a suffix.
|
|
+ AllTargetFiles = AllTargetFiles.OrderBy(x => x.FullName, StringComparer.OrdinalIgnoreCase).ToList();
|
|
+
|
|
+ AddProjectsForAllTargets(
|
|
+ PlatformProjectGenerators,
|
|
+ AllGames,
|
|
+ AllTargetFiles,
|
|
+ Arguments,
|
|
+ out ProjectFile? EngineProject,
|
|
+ out List<ProjectFile>? GameProjects,
|
|
+ out Dictionary<FileReference, ProjectFile>? ProgramProjects,
|
|
+ out Dictionary<RulesAssembly, DirectoryReference>? RulesAssemblies);
|
|
+
|
|
+ AddAllGameProjects(GameProjects);
|
|
+ }
|
|
+
|
|
+ WriteProjectFiles(PlatformProjectGenerators);
|
|
+ WritePrimaryProjectFile(UBTProject, PlatformProjectGenerators);
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ protected override bool WritePrimaryProjectFile(ProjectFile? UBTProject,
|
|
+ PlatformProjectGeneratorCollection PlatformProjectGenerators)
|
|
+ {
|
|
+ try
|
|
+ {
|
|
+ FileReference PrimaryProjectFile = FileReference.Combine(
|
|
+ IntermediateProjectFilesPath, ProjectFilesFolder, VSUnrealWorkspaceFileName);
|
|
+
|
|
+ DirectoryReference.CreateDirectory(PrimaryProjectFile.Directory);
|
|
+
|
|
+ // Collect all the resulting project files and aggregate the target-level data
|
|
+ var AggregatedProjectInfo = GeneratedProjectFiles
|
|
+ .Where(Project => Project is VSWorkspaceProjectFile)
|
|
+ .OfType<VSWorkspaceProjectFile>()
|
|
+ .SelectMany(Project => Project.ExportedTargetProjects)
|
|
+ .GroupBy(TargetProject => TargetProject.TargetName)
|
|
+ .Select(g => (g.Key, Target: new
|
|
+ {
|
|
+ TargetType = g.Select(i => i.TargetType).Distinct().Single(),
|
|
+ TargetPath = g.Select(i => i.TargetPath).Distinct().Single(),
|
|
+ ProjectPath = g.Select(i => i.ProjectPath).Distinct().Single(),
|
|
+ Configurations = g.Select(i => i.Configuration).Distinct().ToList(),
|
|
+ Platforms = g.Select(i => i.Platform).Distinct().ToList(),
|
|
+ }));
|
|
+
|
|
+ // The inner Targets object is needed for schema compatibility with the Query Mode API.
|
|
+ var Result = new
|
|
+ {
|
|
+ Targets = AggregatedProjectInfo.ToDictionary(item => item.Key, item => item.Target)
|
|
+ };
|
|
+
|
|
+ File.WriteAllText(PrimaryProjectFile.FullName, JsonSerializer.Serialize(Result, new JsonSerializerOptions
|
|
+ {
|
|
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
+ WriteIndented = Minimize == JsonWriterStyle.Readable,
|
|
+ }));
|
|
+ }
|
|
+ catch (Exception Ex)
|
|
+ {
|
|
+ Log.TraceWarning("Exception while writing root project file: {Ex}", Ex.ToString());
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /// <inheritdoc />
|
|
+ protected override FileReference GetProjectLocation(string BaseName)
|
|
+ {
|
|
+ return FileReference.Combine(IntermediateProjectFilesPath, ProjectFilesFolder, BaseName + ProjectFileExtension);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs
|
|
index e8b40fff208d9..4f4fff19c8551 100644
|
|
--- a/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs
|
|
+++ b/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs
|
|
@@ -34,6 +34,12 @@ public static DirectoryReference GetModuleInterfaceDir(DirectoryReference Output
|
|
return DirectoryReference.Combine(OutputDir, "Ifc");
|
|
}
|
|
|
|
+ // Return the path to the cpp compiler that will be used by this toolchain.
|
|
+ public virtual FileReference? GetCppCompilerPath()
|
|
+ {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
public abstract CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List<FileItem> InputFiles, DirectoryReference OutputDir, string ModuleName, IActionGraphBuilder Graph);
|
|
|
|
public virtual CPPOutput CompileRCFiles(CppCompileEnvironment Environment, List<FileItem> InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph)
|
|
@@ -65,6 +71,20 @@ public virtual FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBu
|
|
return LinkFile != null ? new FileItem[] { LinkFile } : new FileItem[] { };
|
|
}
|
|
|
|
+ public virtual IEnumerable<string> GetGlobalCommandLineArgs(CppCompileEnvironment CompileEnvironment)
|
|
+ {
|
|
+ return Array.Empty<string>();
|
|
+ }
|
|
+
|
|
+ public virtual IEnumerable<string> GetCPPCommandLineArgs(CppCompileEnvironment CompileEnvironment)
|
|
+ {
|
|
+ return Array.Empty<string>();
|
|
+ }
|
|
+
|
|
+ public virtual IEnumerable<string> GetCCommandLineArgs(CppCompileEnvironment CompileEnvironment)
|
|
+ {
|
|
+ return Array.Empty<string>();
|
|
+ }
|
|
|
|
/// <summary>
|
|
/// Get the name of the response file for the current linker environment and output file
|