/// <summary> /// Generates a Visual Studio solution file and Visual C++ project files for all known engine and game targets. /// Does not actually build anything. /// </summary> /// <param name="Arguments">Command-line arguments</param> /// <param name="bSuccess">True if everything went OK</param> public virtual void GenerateProjectFiles(String[] Arguments, out bool bSuccess) { bSuccess = true; // Parse project generator options bool IncludeAllPlatforms = true; ConfigureProjectFileGeneration(Arguments, ref IncludeAllPlatforms); if (bGeneratingGameProjectFiles) { Log.TraceInformation("Discovering modules, targets and source code for game..."); MasterProjectRelativePath = STBuildTool.GetUProjectPath(); // Set the project file name MasterProjectName = Path.GetFileNameWithoutExtension(STBuildTool.GetUProjectFile()); if (!Directory.Exists(MasterProjectRelativePath + "/Source")) { if (BuildHostPlatform.Current.Platform == STTargetPlatform.Mac) { MasterProjectRelativePath = Path.GetFullPath(Path.Combine(Utils.GetExecutingAssemblyDirectory(), "..", "..", "..", "Engine")); GameProjectName = "UE4Game"; } if (!Directory.Exists(MasterProjectRelativePath + "/Source")) { throw new BuildException("Directory '{0}' is missing 'Source' folder.", MasterProjectRelativePath); } } IntermediateProjectFilesPath = Path.Combine(MasterProjectRelativePath, "Intermediate", "ProjectFiles"); } else if (bGeneratingRocketProjectFiles) { Log.TraceInformation("Discovering modules, targets and source code for project..."); // NOTE: Realistically, the distro that the Rocket user is generating projects FROM won't have NoRedist files in it. But when // testing from a developer branch, this is useful to get authentic projects. This only really matters when // bIncludeEngineModulesInRocketProjects=true (defaults to false.) bExcludeNoRedistFiles = true; MasterProjectRelativePath = STBuildTool.GetUProjectPath(); IntermediateProjectFilesPath = Path.Combine(MasterProjectRelativePath, "Intermediate", "ProjectFiles"); // Set the project file name MasterProjectName = Path.GetFileNameWithoutExtension(STBuildTool.GetUProjectFile()); if (!Directory.Exists(MasterProjectRelativePath + "/Source")) { throw new BuildException("Directory '{0}' is missing 'Source' folder.", MasterProjectRelativePath); } } // Modify the name if specific platforms were given if (ProjectPlatforms.Count > 0) { // Sort the platforms names so we get consistent names List<string> SortedPlatformNames = new List<string>(); foreach (STTargetPlatform SpecificPlatform in ProjectPlatforms) { SortedPlatformNames.Add(SpecificPlatform.ToString()); } SortedPlatformNames.Sort(); MasterProjectName += "_"; foreach (string SortedPlatform in SortedPlatformNames) { MasterProjectName += SortedPlatform; IntermediateProjectFilesPath += SortedPlatform; } } bool bCleanProjectFiles = STBuildTool.CommandLineContains("-CleanProjects"); if (bCleanProjectFiles) { CleanProjectFiles(MasterProjectRelativePath, MasterProjectName, IntermediateProjectFilesPath); } // Figure out which platforms we should generate project files for. string SupportedPlatformNames; SetupSupportedPlatformsAndConfigurations(IncludeAllPlatforms: IncludeAllPlatforms, SupportedPlatformNames: out SupportedPlatformNames); Log.TraceVerbose("Detected supported platforms: " + SupportedPlatformNames); RootFolder = AllocateMasterProjectFolder(this, "<Root>"); // Build the list of games to generate projects for var AllGameProjects = UProjectInfo.FilterGameProjects(true, bGeneratingGameProjectFiles ? GameProjectName : null); var AssemblyName = "ProjectFileGenerator"; if (bGeneratingGameProjectFiles) { AssemblyName = GameProjectName + "ProjectFileGenerator"; } else if (bGeneratingRocketProjectFiles) { AssemblyName = "RocketProjectFileGenerator"; } List<string> AssemblyGameFolders = new List<string>(); foreach (UProjectInfo Project in AllGameProjects) { AssemblyGameFolders.Add(Project.Folder); } RulesCompiler.SetAssemblyNameAndGameFolders(AssemblyName, AssemblyGameFolders); ProjectFile EngineProject = null; Dictionary<string, ProjectFile> GameProjects = null; Dictionary<string, ProjectFile> ProgramProjects = null; HashSet<ProjectFile> TemplateGameProjects = null; { // Setup buildable projects for all targets AddProjectsForAllTargets(AllGameProjects, out EngineProject, out GameProjects, out ProgramProjects, out TemplateGameProjects); // Add all game projects and game config files AddAllGameProjects(GameProjects, SupportedPlatformNames, RootFolder); // Set the game to be the default project if (bGeneratingGameProjectFiles && GameProjects.Count > 0) { DefaultProject = GameProjects.Values.First(); } // Place projects into root level solution folders if (IncludeEngineSource) { // If we're still missing an engine project because we don't have any targets for it, make one up. if (EngineProject == null) { string ProjectFilePath = Path.Combine(IntermediateProjectFilesPath, "UE4" + ProjectFileExtension); bool bAlreadyExisted; EngineProject = FindOrAddProject(Utils.MakePathRelativeTo(ProjectFilePath, MasterProjectRelativePath), true, out bAlreadyExisted); EngineProject.IsForeignProject = false; EngineProject.IsGeneratedProject = true; EngineProject.IsStubProject = true; } if (EngineProject != null) { RootFolder.AddSubFolder("Engine").ChildProjects.Add(EngineProject); // Engine config files if (IncludeConfigFiles) { AddEngineConfigFiles(EngineProject); if (IncludeEnginePrograms) { AddUnrealHeaderToolConfigFiles(EngineProject); AddUBTConfigFilesToEngineProject(EngineProject); } } // Engine localization files if (IncludeLocalizationFiles) { AddEngineLocalizationFiles(EngineProject); } // Engine template files if (IncludeTemplateFiles) { AddEngineTemplateFiles(EngineProject); } if (IncludeShaderSource) { Log.TraceVerbose("Adding shader source code..."); // Find shader source files and generate stub project AddEngineShaderSource(EngineProject); } if (IncludeBuildSystemFiles) { Log.TraceVerbose("Adding build system files..."); AddEngineBuildFiles(EngineProject); } if (IncludeDocumentation) { AddEngineDocumentation(EngineProject); } } foreach (var CurGameProject in GameProjects.Values) { // Templates go under a different solution folder than games if (TemplateGameProjects.Contains(CurGameProject)) { RootFolder.AddSubFolder("Templates").ChildProjects.Add(CurGameProject); } else { RootFolder.AddSubFolder("Games").ChildProjects.Add(CurGameProject); } } foreach (var CurProgramProject in ProgramProjects.Values) { RootFolder.AddSubFolder("Programs").ChildProjects.Add(CurProgramProject); } // Add all of the config files for generated program targets AddEngineProgramConfigFiles(ProgramProjects); } } // Find all of the module files. This will filter out any modules or targets that don't belong to platforms // we're generating project files for. var AllModuleFiles = DiscoverModules(); // Setup "stub" projects for all modules AddProjectsForAllModules(AllGameProjects, ProgramProjects, AllModuleFiles, bGatherThirdPartySource); { if (IncludeEnginePrograms) { MasterProjectFolder ProgramsFolder = RootFolder.AddSubFolder("Programs"); // Add STBuildTool to the master project AddSTBuildToolProject(ProgramsFolder); // Add AutomationTool to the master project ProgramsFolder.ChildProjects.Add(AddSimpleCSharpProject("AutomationTool", bShouldBuildForAllSolutionTargets: true, bForceDevelopmentConfiguration: true)); // Add UnrealAutomationTool (launcher) to the master project ProgramsFolder.ChildProjects.Add(AddSimpleCSharpProject("AutomationToolLauncher", bShouldBuildForAllSolutionTargets: true, bForceDevelopmentConfiguration: true)); // Add automation.csproj files to the master project AddAutomationModules(ProgramsFolder); // Add Distill to the master project ProgramsFolder.ChildProjects.Add(AddSimpleCSharpProject("Distill")); // Add DotNETUtilities to the master project ProgramsFolder.ChildProjects.Add(AddSimpleCSharpProject("DotNETCommon/DotNETUtilities", bShouldBuildForAllSolutionTargets: true, bForceDevelopmentConfiguration: true)); // Add the Git dependencies project ProgramsFolder.ChildProjects.Add(AddSimpleCSharpProject("GitDependencies", bShouldBuildForAllSolutionTargets: true, bForceDevelopmentConfiguration: true)); // Add all of the IOS C# projects AddIOSProjects(ProgramsFolder); // Add all of the Android C# projects AddAndroidProjects(ProgramsFolder); // Add all of the PS4 C# projects AddPS4Projects(ProgramsFolder); } // Eliminate all redundant master project folders. E.g., folders which contain only one project and that project // has the same name as the folder itself. To the user, projects "feel like" folders already in the IDE, so we // want to collapse them down where possible. EliminateRedundantMasterProjectSubFolders(RootFolder, ""); bool bWriteFileManifest = STBuildTool.CommandLineContains("-filemanifest"); if (bWriteFileManifest == false) { // Figure out which targets we need about IntelliSense for. We only need to worry about targets for projects // that we're actually generating in this session. var IntelliSenseTargetFiles = new List<Tuple<ProjectFile, string>>(); { // Engine targets if (EngineProject != null && !bGeneratingRocketProjectFiles) { foreach (var ProjectTarget in EngineProject.ProjectTargets) { if (!String.IsNullOrEmpty(ProjectTarget.TargetFilePath)) { // Only bother with the editor target. We want to make sure that definitions are setup to be as inclusive as possible // for good quality IntelliSense. For example, we want WITH_EDITORONLY_DATA=1, so using the editor targets works well. if (ProjectTarget.TargetRules.Type == TargetRules.TargetType.Editor) { IntelliSenseTargetFiles.Add(Tuple.Create(EngineProject, ProjectTarget.TargetFilePath)); } } } } // Program targets foreach (var ProgramProject in ProgramProjects.Values) { foreach (var ProjectTarget in ProgramProject.ProjectTargets) { if (!String.IsNullOrEmpty(ProjectTarget.TargetFilePath)) { IntelliSenseTargetFiles.Add(Tuple.Create(ProgramProject, ProjectTarget.TargetFilePath)); } } } // Game/template targets foreach (var GameProject in GameProjects.Values) { foreach (var ProjectTarget in GameProject.ProjectTargets) { if (!String.IsNullOrEmpty(ProjectTarget.TargetFilePath)) { // Only bother with the editor target. We want to make sure that definitions are setup to be as inclusive as possible // for good quality IntelliSense. For example, we want WITH_EDITORONLY_DATA=1, so using the editor targets works well. if (ProjectTarget.TargetRules.Type == TargetRules.TargetType.Editor) { IntelliSenseTargetFiles.Add(Tuple.Create(GameProject, ProjectTarget.TargetFilePath)); } } } } } // Generate IntelliSense data if we need to. This involves having UBT simulate the action compilation of // the targets so that we can extra the compiler defines, include paths, etc. bSuccess = GenerateIntelliSenseData(Arguments, IntelliSenseTargetFiles); } // If everything went OK, we'll now save out all of the new project files if (bSuccess) { if (bWriteFileManifest == false) { // Save new project files WriteProjectFiles(); Log.TraceVerbose("Project generation complete ({0} generated, {1} imported)", GeneratedProjectFiles.Count, OtherProjectFiles.Count); } else { WriteProjectFileManifest(); } } } }
/// <summary> /// Adds all .automation.csproj files to the solution. /// </summary> void AddAutomationModules(MasterProjectFolder ProgramsFolder) { var Folder = ProgramsFolder.AddSubFolder("Automation"); var AllGameFolders = STBuildTarget.DiscoverAllGameFolders(); var BuildFolders = new List<string>(AllGameFolders.Count); foreach (var GameFolder in AllGameFolders) { var GameBuildFolder = Path.Combine(GameFolder, "Build"); if (Directory.Exists(GameBuildFolder)) { BuildFolders.Add(GameBuildFolder); } } // Find all the automation modules .csproj files to add var ModuleFiles = RulesCompiler.FindAllRulesSourceFiles(RulesCompiler.RulesFileType.AutomationModule, BuildFolders); foreach (var ProjectFile in ModuleFiles) { FileInfo Info = new FileInfo(Path.Combine(ProjectFile)); if (Info.Exists) { var RelativeFileName = Utils.MakePathRelativeTo(ProjectFile, MasterProjectRelativePath); var Project = new VCSharpProjectFile(RelativeFileName); Project.ShouldBuildForAllSolutionTargets = true; AddExistingProjectFile(Project, bForceDevelopmentConfiguration: true); Folder.ChildProjects.Add(Project); } } }