/// <summary> /// Recursively searches for the specified project and returns the folder that it lives in, or null if not found /// </summary> /// <param name="Project">The project file to look for</param> /// <returns>The found folder that the project is in, or null</returns> public MasterProjectFolder FindFolderForProject(ProjectFile Project) { foreach (var CurFolder in SubFolders) { MasterProjectFolder FoundFolder = CurFolder.FindFolderForProject(Project); if (FoundFolder != null) { return FoundFolder; } } foreach (var ChildProject in ChildProjects) { if (ChildProject == Project) { return this; } } return null; }
protected override bool WriteMasterProjectFile(ProjectFile UBTProject) { bool bSuccess = true; return bSuccess; }
/// <summary> /// Add the given project to the DepondsOn project list. /// </summary> /// <param name="InProjectFile">The project this project is dependent on</param> public void AddDependsOnProject(ProjectFile InProjectFile) { // Make sure that it doesn't exist already var AlreadyExists = false; foreach (var ExistingDependentOn in DependsOnProjects) { if (ExistingDependentOn == InProjectFile) { AlreadyExists = true; break; } } if (AlreadyExists == false) { DependsOnProjects.Add(InProjectFile); } }
protected override bool WriteMasterProjectFile(ProjectFile UBTProject) { bool bSuccess = true; var SolutionFileName = MasterProjectName + ".sln"; // Setup solution file content var VCSolutionFileContent = new StringBuilder(); // Solution file header if (ProjectFileFormat == VCProjectFileFormat.VisualStudio2013) { VCSolutionFileContent.Append( ProjectFileGenerator.NewLine + "Microsoft Visual Studio Solution File, Format Version 12.00" + ProjectFileGenerator.NewLine + "# Visual Studio 2013" + ProjectFileGenerator.NewLine); /* This is not required by VS 2013 to load the projects VCSolutionFileContent.Append( "VisualStudioVersion = 12.0.20617.1 PREVIEW" + ProjectFileGenerator.NewLine + "MinimumVisualStudioVersion = 10.0.40219.1" + ProjectFileGenerator.NewLine );*/ } else if (ProjectFileFormat == VCProjectFileFormat.VisualStudio2012) { VCSolutionFileContent.Append( ProjectFileGenerator.NewLine + "Microsoft Visual Studio Solution File, Format Version 12.00" + ProjectFileGenerator.NewLine + "# Visual Studio 2012" + ProjectFileGenerator.NewLine); } else { throw new BuildException("Unexpected ProjectFileFormat"); } // Solution folders, files and project entries { // This the GUID that Visual Studio uses to identify a solution folder var SolutionFolderEntryGUID = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}"; // Solution folders { var AllSolutionFolders = new List<MasterProjectFolder>(); System.Action<List<MasterProjectFolder> /* Folders */ > GatherFoldersFunction = null; GatherFoldersFunction = FolderList => { AllSolutionFolders.AddRange(FolderList); foreach (var CurSubFolder in FolderList) { GatherFoldersFunction(CurSubFolder.SubFolders); } }; GatherFoldersFunction(RootFolder.SubFolders); foreach (VisualStudioSolutionFolder CurFolder in AllSolutionFolders) { var FolderGUIDString = CurFolder.FolderGUID.ToString("B").ToUpperInvariant(); VCSolutionFileContent.Append( "Project(\"" + SolutionFolderEntryGUID + "\") = \"" + CurFolder.FolderName + "\", \"" + CurFolder.FolderName + "\", \"" + FolderGUIDString + "\"" + ProjectFileGenerator.NewLine); // Add any files that are inlined right inside the solution folder if (CurFolder.Files.Count > 0) { VCSolutionFileContent.Append( " ProjectSection(SolutionItems) = preProject" + ProjectFileGenerator.NewLine); foreach (var CurFile in CurFolder.Files) { // Syntax is: <relative file path> = <relative file path> VCSolutionFileContent.Append( " " + CurFile + " = " + CurFile + ProjectFileGenerator.NewLine); } VCSolutionFileContent.Append( " EndProjectSection" + ProjectFileGenerator.NewLine); } VCSolutionFileContent.Append( "EndProject" + ProjectFileGenerator.NewLine ); } } // Project files foreach (MSBuildProjectFile CurProject in AllProjectFiles) { // Visual Studio uses different GUID types depending on the project type string ProjectTypeGUID = CurProject.ProjectTypeGUID; // NOTE: The project name in the solution doesn't actually *have* to match the project file name on disk. However, // we prefer it when it does match so we use the actual file name here. var ProjectNameInSolution = Path.GetFileNameWithoutExtension(CurProject.ProjectFilePath); // Use the existing project's GUID that's already known to us var ProjectGUID = CurProject.ProjectGUID.ToString("B").ToUpperInvariant(); VCSolutionFileContent.Append( "Project(\"" + ProjectTypeGUID + "\") = \"" + ProjectNameInSolution + "\", \"" + CurProject.RelativeProjectFilePath + "\", \"" + ProjectGUID + "\"" + ProjectFileGenerator.NewLine); // Setup dependency on STBuildTool, if we need that. This makes sure that STBuildTool is // freshly compiled before kicking off any build operations on this target project if (!CurProject.IsStubProject) { // Don't add self as a project dependency! if ((CurProject != UBTProject) && (CurProject.IsGeneratedProject || (CurProject.DependsOnProjects.Count > 0))) { VCSolutionFileContent.Append( " ProjectSection(ProjectDependencies) = postProject" + ProjectFileGenerator.NewLine); if (CurProject.IsGeneratedProject && UBTProject != null) { var UBTProjectGUID = ((MSBuildProjectFile)UBTProject).ProjectGUID.ToString("B").ToUpperInvariant(); VCSolutionFileContent.Append( " " + UBTProjectGUID + " = " + UBTProjectGUID + ProjectFileGenerator.NewLine); } // Setup any addition dependencies this project has... foreach (var DependsOnProject in CurProject.DependsOnProjects) { var DependsOnProjectGUID = ((MSBuildProjectFile)DependsOnProject).ProjectGUID.ToString("B").ToUpperInvariant(); VCSolutionFileContent.Append( " " + DependsOnProjectGUID + " = " + DependsOnProjectGUID + ProjectFileGenerator.NewLine); } VCSolutionFileContent.Append( " EndProjectSection" + ProjectFileGenerator.NewLine); } } VCSolutionFileContent.Append( "EndProject" + ProjectFileGenerator.NewLine ); } } // Solution configuration platforms. This is just a list of all of the platforms and configurations that // appear in Visual Studio's build configuration selector. var SolutionConfigCombinations = new List<VCSolutionConfigCombination>(); // The "Global" section has source control, solution configurations, project configurations, // preferences, and project hierarchy data { VCSolutionFileContent.Append( "Global" + ProjectFileGenerator.NewLine); { { VCSolutionFileContent.Append( " GlobalSection(SolutionConfigurationPlatforms) = preSolution" + ProjectFileGenerator.NewLine); var SolutionConfigurationsValidForProjects = new Dictionary<string, Tuple<STTargetConfiguration, string>>(); var PlatformsValidForProjects = new HashSet<STTargetPlatform>(); foreach (var CurConfiguration in SupportedConfigurations) { if (STBuildTool.IsValidConfiguration(CurConfiguration)) { foreach (var CurPlatform in SupportedPlatforms) { if (STBuildTool.IsValidPlatform(CurPlatform)) { foreach (var CurProject in AllProjectFiles) { if (!CurProject.IsStubProject) { if (CurProject.ProjectTargets.Count == 0) { throw new BuildException("Expecting project '" + CurProject.ProjectFilePath + "' to have at least one ProjectTarget associated with it!"); } // Figure out the set of valid target configuration names foreach (var ProjectTarget in CurProject.ProjectTargets) { if (VCProjectFile.IsValidProjectPlatformAndConfiguration(ProjectTarget, CurPlatform, CurConfiguration)) { PlatformsValidForProjects.Add(CurPlatform); // Default to a target configuration name of "Game", since that will collapse down to an empty string var TargetConfigurationName = TargetRules.TargetType.Game.ToString(); if (ProjectTarget.TargetRules != null) { TargetConfigurationName = ProjectTarget.TargetRules.ConfigurationName; } var SolutionConfigName = MakeSolutionConfigurationName(CurConfiguration, TargetConfigurationName); SolutionConfigurationsValidForProjects[SolutionConfigName] = new Tuple<STTargetConfiguration, string>(CurConfiguration, TargetConfigurationName); } } } } } } } } foreach (var CurPlatform in PlatformsValidForProjects) { foreach (var SolutionConfigKeyValue in SolutionConfigurationsValidForProjects) { // e.g. "Development|Win64 = Development|Win64" var SolutionConfigName = SolutionConfigKeyValue.Key; var Configuration = SolutionConfigKeyValue.Value.Item1; var TargetConfigurationName = SolutionConfigKeyValue.Value.Item2; var SolutionPlatformName = CurPlatform.ToString(); // For Rocket, there are currently no targets that are valid to build both for Win32 and Win64. So we simply things by // only displaying a "Windows" platform and building for the appropriate Windows platform automatically based on whichever // configuration they have selected. if (STBuildTool.RunningRocket() && (CurPlatform == STTargetPlatform.Win32 || CurPlatform == STTargetPlatform.Win64)) { SolutionPlatformName = "Windows"; if (Configuration == STTargetConfiguration.Shipping) { if (CurPlatform != STTargetPlatform.Win32) { continue; } } else { if (CurPlatform != STTargetPlatform.Win64) { continue; } } } var SolutionConfigAndPlatformPair = SolutionConfigName + "|" + SolutionPlatformName; SolutionConfigCombinations.Add( new VCSolutionConfigCombination { VCSolutionConfigAndPlatformName = SolutionConfigAndPlatformPair, Configuration = Configuration, Platform = CurPlatform, TargetConfigurationName = TargetConfigurationName } ); } } // Sort the list of solution platform strings alphabetically (Visual Studio prefers it) SolutionConfigCombinations.Sort( new Comparison<VCSolutionConfigCombination>( (x, y) => { return String.Compare(x.VCSolutionConfigAndPlatformName, y.VCSolutionConfigAndPlatformName, StringComparison.InvariantCultureIgnoreCase); } ) ); var AppendedSolutionConfigAndPlatformNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase); foreach (var SolutionConfigCombination in SolutionConfigCombinations) { // We alias "Game" and "Program" to both have the same solution configuration, so we're careful not to add the same combination twice. if (!AppendedSolutionConfigAndPlatformNames.Contains(SolutionConfigCombination.VCSolutionConfigAndPlatformName)) { VCSolutionFileContent.Append( " " + SolutionConfigCombination.VCSolutionConfigAndPlatformName + " = " + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ProjectFileGenerator.NewLine); AppendedSolutionConfigAndPlatformNames.Add(SolutionConfigCombination.VCSolutionConfigAndPlatformName); } } VCSolutionFileContent.Append( " EndGlobalSection" + ProjectFileGenerator.NewLine); } // Assign each project's "project configuration" to our "solution platform + configuration" pairs. This // also sets up which projects are actually built when building the solution. { VCSolutionFileContent.Append( " GlobalSection(ProjectConfigurationPlatforms) = postSolution" + ProjectFileGenerator.NewLine); var CombinationsThatWereMatchedToProjects = new List<VCSolutionConfigCombination>(); foreach (MSBuildProjectFile CurProject in AllProjectFiles) { // NOTE: We don't emit solution configuration entries for "stub" projects. Those projects are only // built using STBuildTool and don't require a presence in the solution project list // NOTE: We also process projects that were "imported" here, hoping to match those to our solution // configurations. In some cases this may not be successful though. Imported projects // should always be carefully setup to match our project generator's solution configs. if (!CurProject.IsStubProject) { if (CurProject.ProjectTargets.Count == 0) { throw new BuildException("Expecting project '" + CurProject.ProjectFilePath + "' to have at least one ProjectTarget associated with it!"); } var IsProgramProject = CurProject.ProjectTargets[0].TargetRules != null && CurProject.ProjectTargets[0].TargetRules.Type == TargetRules.TargetType.Program; var GameOrProgramConfigsAlreadyMapped = new HashSet<string>(); foreach (var SolutionConfigCombination in SolutionConfigCombinations) { // Handle aliasing of Program and Game target configuration names if ((IsProgramProject && GameOrProgramConfigsAlreadyMapped.Add(SolutionConfigCombination.VCSolutionConfigAndPlatformName)) || IsProgramProject && SolutionConfigCombination.TargetConfigurationName != TargetRules.TargetType.Game.ToString() || !IsProgramProject && SolutionConfigCombination.TargetConfigurationName != TargetRules.TargetType.Program.ToString()) { var TargetConfigurationName = SolutionConfigCombination.TargetConfigurationName; if (IsProgramProject && TargetConfigurationName == TargetRules.TargetType.Game.ToString()) { TargetConfigurationName = TargetRules.TargetType.Program.ToString(); } // Now, we want to find a target in this project that maps to the current solution config combination. Only up to one target should // and every solution config combination should map to at least one target in one project (otherwise we shouldn't have added it!). ProjectTarget MatchingProjectTarget = null; foreach (var ProjectTarget in CurProject.ProjectTargets) { bool IsMatchingCombination = VCProjectFile.IsValidProjectPlatformAndConfiguration(ProjectTarget, SolutionConfigCombination.Platform, SolutionConfigCombination.Configuration); if (ProjectTarget.TargetRules != null) { if (TargetConfigurationName != ProjectTarget.TargetRules.ConfigurationName) { // Solution configuration name for this combination doesn't match this target's configuration name. It's not buildable. IsMatchingCombination = false; } } else { // UBT gets a pass because it is a dependency of every single configuration combination if (CurProject != UBTProject && !CurProject.ShouldBuildForAllSolutionTargets && TargetConfigurationName != TargetRules.TargetType.Game.ToString()) { // Can't build non-generated project in configurations except for the default (Game) IsMatchingCombination = false; } } if (IsMatchingCombination) { if (MatchingProjectTarget != null) { // Not expecting more than one target to match a single solution configuration per project! throw new BuildException("Not expecting more than one target for project " + CurProject.ProjectFilePath + " to match solution configuration " + SolutionConfigCombination.VCSolutionConfigAndPlatformName); } MatchingProjectTarget = ProjectTarget; // NOTE: For faster perf, we could "break" here and bail out early, but that would circumvent the error checking // for multiple targets within a project that may map to a single solution configuration. } } var SolutionConfiguration = SolutionConfigCombination.Configuration; var SolutionPlatform = SolutionConfigCombination.Platform; if (MatchingProjectTarget == null) { // The current configuration/platform and target configuration name doesn't map to anything our project actually supports. // We'll map it to a default config. SolutionConfiguration = STTargetConfiguration.Development; // Prefer using Win64 as the default, but fall back to a platform the project file actually supports if needed. This is for // projects that can never be compiled in Windows, such as UnrealLaunchDaemon which is an iOS-only program SolutionPlatform = STTargetPlatform.Win64; if (CurProject.ProjectTargets[0].TargetRules != null) { var ProjectSupportedPlatforms = new List<STTargetPlatform>(); CurProject.ProjectTargets[0].TargetRules.GetSupportedPlatforms(ref ProjectSupportedPlatforms); if (!ProjectSupportedPlatforms.Contains(SolutionPlatform)) { SolutionPlatform = ProjectSupportedPlatforms[0]; } } if (IsProgramProject) { TargetConfigurationName = TargetRules.TargetType.Program.ToString(); } else { TargetConfigurationName = TargetRules.TargetType.Game.ToString(); } } // If the project wants to always build in "Development", regardless of what the solution // configuration is set to, then we'll do that here. This is used for projects like // STBuildTool and ShaderCompileWorker if (MatchingProjectTarget != null) { if (MatchingProjectTarget.ForceDevelopmentConfiguration) { SolutionConfiguration = STTargetConfiguration.Development; } } string ProjectConfigName; string ProjectPlatformName; CurProject.MakeProjectPlatformAndConfigurationNames(SolutionPlatform, SolutionConfiguration, TargetConfigurationName, out ProjectPlatformName, out ProjectConfigName); var ProjectConfigAndPlatformPair = ProjectConfigName.ToString() + "|" + ProjectPlatformName.ToString(); // e.g. "{4232C52C-680F-4850-8855-DC39419B5E9B}.Debug|iOS.ActiveCfg = iOS_Debug|Win32" var CurProjectGUID = CurProject.ProjectGUID.ToString("B").ToUpperInvariant(); VCSolutionFileContent.Append( " " + CurProjectGUID + "." + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ".ActiveCfg = " + ProjectConfigAndPlatformPair + ProjectFileGenerator.NewLine); // Set whether this project configuration should be built when the user initiates "build solution" if (MatchingProjectTarget != null) { VCSolutionFileContent.Append( " " + CurProjectGUID + "." + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ".Build.0 = " + ProjectConfigAndPlatformPair + ProjectFileGenerator.NewLine); var ProjGen = STPlatformProjectGenerator.GetPlatformProjectGenerator(SolutionConfigCombination.Platform, true); if (MatchingProjectTarget.ProjectDeploys || ((ProjGen != null) && (ProjGen.GetVisualStudioDeploymentEnabled(SolutionPlatform, SolutionConfiguration) == true))) { VCSolutionFileContent.Append( " " + CurProjectGUID + "." + SolutionConfigCombination.VCSolutionConfigAndPlatformName + ".Deploy.0 = " + ProjectConfigAndPlatformPair + ProjectFileGenerator.NewLine); } } CombinationsThatWereMatchedToProjects.Add(SolutionConfigCombination); } } } } // Check for problems foreach (var SolutionConfigCombination in SolutionConfigCombinations) { if (!CombinationsThatWereMatchedToProjects.Contains(SolutionConfigCombination)) { throw new BuildException("Unable to find a ProjectTarget that matches the solution configuration/platform mapping: " + SolutionConfigCombination.Configuration.ToString() + ", " + SolutionConfigCombination.Platform.ToString() + ", " + SolutionConfigCombination.TargetConfigurationName); } } VCSolutionFileContent.Append( " EndGlobalSection" + ProjectFileGenerator.NewLine); } // Setup other solution properties { VCSolutionFileContent.Append( " GlobalSection(SolutionProperties) = preSolution" + ProjectFileGenerator.NewLine); // HideSolutionNode sets whether or not the top-level solution entry is completely hidden in the UI. // We don't want that, as we need users to be able to right click on the solution tree item. VCSolutionFileContent.Append( " HideSolutionNode = FALSE" + ProjectFileGenerator.NewLine); VCSolutionFileContent.Append( " EndGlobalSection" + ProjectFileGenerator.NewLine); } // Solution directory hierarchy { VCSolutionFileContent.Append( " GlobalSection(NestedProjects) = preSolution" + ProjectFileGenerator.NewLine); // Every entry in this section is in the format "Guid1 = Guid2". Guid1 is the child project (or solution // filter)'s GUID, and Guid2 is the solution filter directory to parent the child project (or solution // filter) to. This sets up the hierarchical solution explorer tree for all solution folders and projects. System.Action<StringBuilder /* VCSolutionFileContent */, List<MasterProjectFolder> /* Folders */ > FolderProcessorFunction = null; FolderProcessorFunction = (LocalVCSolutionFileContent, LocalMasterProjectFolders) => { foreach (VisualStudioSolutionFolder CurFolder in LocalMasterProjectFolders) { var CurFolderGUIDString = CurFolder.FolderGUID.ToString("B").ToUpperInvariant(); foreach (MSBuildProjectFile ChildProject in CurFolder.ChildProjects) { // e.g. "{BF6FB09F-A2A6-468F-BE6F-DEBE07EAD3EA} = {C43B6BB5-3EF0-4784-B896-4099753BCDA9}" LocalVCSolutionFileContent.Append( " " + ChildProject.ProjectGUID.ToString("B").ToUpperInvariant() + " = " + CurFolderGUIDString + ProjectFileGenerator.NewLine); } foreach (VisualStudioSolutionFolder SubFolder in CurFolder.SubFolders) { // e.g. "{BF6FB09F-A2A6-468F-BE6F-DEBE07EAD3EA} = {C43B6BB5-3EF0-4784-B896-4099753BCDA9}" LocalVCSolutionFileContent.Append( " " + SubFolder.FolderGUID.ToString("B").ToUpperInvariant() + " = " + CurFolderGUIDString + ProjectFileGenerator.NewLine); } // Recurse into subfolders FolderProcessorFunction(LocalVCSolutionFileContent, CurFolder.SubFolders); } }; FolderProcessorFunction(VCSolutionFileContent, RootFolder.SubFolders); VCSolutionFileContent.Append( " EndGlobalSection" + ProjectFileGenerator.NewLine); } } VCSolutionFileContent.Append( "EndGlobal" + ProjectFileGenerator.NewLine); } // Save the solution file if (bSuccess) { var SolutionFilePath = Path.Combine(MasterProjectRelativePath, SolutionFileName); bSuccess = WriteFileIfChanged(SolutionFilePath, VCSolutionFileContent.ToString()); } // Save a solution config file which selects the development editor configuration by default. if (bSuccess) { // Figure out the filename for the SUO file. VS2013 will automatically import the VS2012 options if necessary. string SolutionOptionsExtension = (ProjectFileFormat == VCProjectFileFormat.VisualStudio2012) ? "v11.suo" : "v12.suo"; // Check it doesn't exist before overwriting it. Since these files store the user's preferences, it'd be bad form to overwrite them. string SolutionOptionsFileName = Path.Combine(MasterProjectRelativePath, Path.ChangeExtension(SolutionFileName, SolutionOptionsExtension)); if (!File.Exists(SolutionOptionsFileName)) { VCSolutionOptions Options = new VCSolutionOptions(); // Set the default configuration and startup project VCSolutionConfigCombination DefaultConfig = SolutionConfigCombinations.Find(x => x.Configuration == STTargetConfiguration.Development && x.Platform == STTargetPlatform.Win64 && x.TargetConfigurationName == "Editor"); if (DefaultConfig != null) { List<VCBinarySetting> Settings = new List<VCBinarySetting>(); Settings.Add(new VCBinarySetting("ActiveCfg", DefaultConfig.VCSolutionConfigAndPlatformName)); if (DefaultProject != null) { Settings.Add(new VCBinarySetting("StartupProject", ((MSBuildProjectFile)DefaultProject).ProjectGUID.ToString("B"))); } Options.SetConfiguration(Settings); } // Mark all the projects as closed by default, apart from the startup project VCSolutionExplorerState ExplorerState = new VCSolutionExplorerState(); foreach (ProjectFile ProjectFile in AllProjectFiles) { string ProjectName = Path.GetFileNameWithoutExtension(ProjectFile.ProjectFilePath); if (ProjectFile == DefaultProject) { ExplorerState.OpenProjects.Add(new Tuple<string, string[]>(ProjectName, new string[] { ProjectName })); } else { ExplorerState.OpenProjects.Add(new Tuple<string, string[]>(ProjectName, new string[] { })); } } if (IncludeEnginePrograms) { ExplorerState.OpenProjects.Add(new Tuple<string, string[]>("Automation", new string[0])); } Options.SetExplorerState(ExplorerState); // Write the file if (Options.Sections.Count > 0) { Options.Write(SolutionOptionsFileName); } } } return bSuccess; }
/// Adds shader source code to the specified project protected void AddEngineShaderSource(ProjectFile EngineProject) { // Setup a project file entry for this module's project. Remember, some projects may host multiple modules! var ShadersDirectory = Path.Combine(EngineRelativePath, "Shaders"); var DirectoriesToSearch = new List<string>(); DirectoriesToSearch.Add(ShadersDirectory); var SubdirectoryNamesToExclude = new List<string>(); { // Don't include binary shaders in the project file. SubdirectoryNamesToExclude.Add("Binaries"); // We never want shader intermediate files in our project file SubdirectoryNamesToExclude.Add("PDBDump"); SubdirectoryNamesToExclude.Add("WorkingDirectory"); } EngineProject.AddFilesToProject(SourceFileSearch.FindFiles( DirectoriesToSearch: DirectoriesToSearch, ExcludeNoRedistFiles: bExcludeNoRedistFiles, SubdirectoryNamesToExclude: SubdirectoryNamesToExclude), EngineRelativePath); }
/// Adds engine documentation to the specified project protected void AddEngineDocumentation(ProjectFile EngineProject) { // NOTE: The project folder added here will actually be collapsed away later if not needed var DocumentationProjectDirectory = Path.Combine(EngineRelativePath, "Documentation"); var DocumentationSourceDirectory = Path.Combine(EngineRelativePath, "Documentation", "Source"); DirectoryInfo DirInfo = new DirectoryInfo(DocumentationProjectDirectory); if (DirInfo.Exists && Directory.Exists(DocumentationSourceDirectory)) { Log.TraceVerbose("Adding documentation files..."); var DirectoriesToSearch = new List<string>(); DirectoriesToSearch.Add(DocumentationSourceDirectory); var SubdirectoryNamesToExclude = new List<string>(); { // We never want any of the images or attachment files included in our generated project SubdirectoryNamesToExclude.Add("Images"); SubdirectoryNamesToExclude.Add("Attachments"); // The API directory is huge, so don't include any of it SubdirectoryNamesToExclude.Add("API"); // Omit Javascript source because it just confuses the Visual Studio IDE SubdirectoryNamesToExclude.Add("Javascript"); } var DocumentationFiles = SourceFileSearch.FindFiles( DirectoriesToSearch: DirectoriesToSearch, ExcludeNoRedistFiles: bExcludeNoRedistFiles, SubdirectoryNamesToExclude: SubdirectoryNamesToExclude); // Filter out non-English documentation files if we were configured to do so if (!bAllDocumentationLanguages) { var FilteredDocumentationFiles = new List<string>(); foreach (var DocumentationFile in DocumentationFiles) { bool bPassesFilter = true; if (DocumentationFile.EndsWith(".udn", StringComparison.InvariantCultureIgnoreCase)) { var LanguageSuffix = Path.GetExtension(Path.GetFileNameWithoutExtension(DocumentationFile)); if (!String.IsNullOrEmpty(LanguageSuffix) && !LanguageSuffix.Equals(".int", StringComparison.InvariantCultureIgnoreCase)) { bPassesFilter = false; } } if (bPassesFilter) { FilteredDocumentationFiles.Add(DocumentationFile); } } DocumentationFiles = FilteredDocumentationFiles; } EngineProject.AddFilesToProject(DocumentationFiles, EngineRelativePath); } else { Log.TraceVerbose("Skipping documentation project... directory not found"); } }
/// Adds engine build infrastructure files to the specified project protected void AddEngineBuildFiles(ProjectFile EngineProject) { var BuildDirectory = Path.Combine(EngineRelativePath, "Build"); var DirectoriesToSearch = new List<string>(); DirectoriesToSearch.Add(BuildDirectory); var SubdirectoryNamesToExclude = new List<string>(); { // Nothing to exclude, yet! // SubdirectoryNamesToExclude.Add( "DirectoryName" ); } EngineProject.AddFilesToProject(SourceFileSearch.FindFiles( DirectoriesToSearch: DirectoriesToSearch, ExcludeNoRedistFiles: bExcludeNoRedistFiles, SubdirectoryNamesToExclude: SubdirectoryNamesToExclude), EngineRelativePath); }
/// <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(); } } } }
/// Adds UnrealHeaderTool config files to the specified project private void AddUnrealHeaderToolConfigFiles(ProjectFile EngineProject) { var UHTConfigDirectory = Path.Combine(EngineRelativePath, "Programs", "UnrealHeaderTool", "Config"); if (Directory.Exists(UHTConfigDirectory)) { var DirectoriesToSearch = new List<string>(); DirectoriesToSearch.Add(UHTConfigDirectory); EngineProject.AddFilesToProject(SourceFileSearch.FindFiles(DirectoriesToSearch, ExcludeNoRedistFiles: bExcludeNoRedistFiles), EngineRelativePath); } }
/// <summary> /// Adds the given project to the OtherProjects list /// </summary> /// <param name="InProject">The project to add</param> /// <returns>True if successful</returns> public void AddExistingProjectFile(ProjectFile InProject, bool bNeedsAllPlatformAndConfigurations = false, bool bForceDevelopmentConfiguration = false, bool bProjectDeploys = false, List<STTargetPlatform> InSupportedPlatforms = null, List<STTargetConfiguration> InSupportedConfigurations = null) { if (InProject.ProjectTargets.Count != 0) { throw new BuildException("Expecting existing project to not have any ProjectTargets defined yet."); } var ProjectTarget = new ProjectTarget(); if (bForceDevelopmentConfiguration) { ProjectTarget.ForceDevelopmentConfiguration = true; } ProjectTarget.ProjectDeploys = bProjectDeploys; if (bNeedsAllPlatformAndConfigurations) { // Add all platforms var AllPlatforms = Enum.GetValues(typeof(STTargetPlatform)); foreach (STTargetPlatform CurPlatfrom in AllPlatforms) { ProjectTarget.ExtraSupportedPlatforms.Add(CurPlatfrom); } // Add all configurations var AllConfigurations = Enum.GetValues(typeof(STTargetConfiguration)); foreach (STTargetConfiguration CurConfiguration in AllConfigurations) { ProjectTarget.ExtraSupportedConfigurations.Add(CurConfiguration); } } else if (InSupportedPlatforms != null || InSupportedConfigurations != null) { if (InSupportedPlatforms != null) { // Add all explicitly specified platforms foreach (STTargetPlatform CurPlatfrom in InSupportedPlatforms) { ProjectTarget.ExtraSupportedPlatforms.Add(CurPlatfrom); } } else { // Otherwise, add all platforms var AllPlatforms = Enum.GetValues(typeof(STTargetPlatform)); foreach (STTargetPlatform CurPlatfrom in AllPlatforms) { ProjectTarget.ExtraSupportedPlatforms.Add(CurPlatfrom); } } if (InSupportedConfigurations != null) { // Add all explicitly specified configurations foreach (STTargetConfiguration CurConfiguration in InSupportedConfigurations) { ProjectTarget.ExtraSupportedConfigurations.Add(CurConfiguration); } } else { // Otherwise, add all configurations var AllConfigurations = Enum.GetValues(typeof(STTargetConfiguration)); foreach (STTargetConfiguration CurConfiguration in AllConfigurations) { ProjectTarget.ExtraSupportedConfigurations.Add(CurConfiguration); } } } else { // For existing project files, just support the default desktop platforms and configurations STBuildTool.GetAllDesktopPlatforms(ref ProjectTarget.ExtraSupportedPlatforms, false); // Debug and Development only ProjectTarget.ExtraSupportedConfigurations.Add(STTargetConfiguration.Debug); ProjectTarget.ExtraSupportedConfigurations.Add(STTargetConfiguration.Development); } InProject.ProjectTargets.Add(ProjectTarget); // Existing projects must always have a GUID. This will throw an exception if one isn't found. InProject.LoadGUIDFromExistingProject(); OtherProjectFiles.Add(InProject); }
/// <summary> /// Adds detected UBT configuration files (BuildConfiguration.xml) to engine project. /// </summary> /// <param name="EngineProject">Engine project to add files to.</param> private void AddUBTConfigFilesToEngineProject(ProjectFile EngineProject) { EngineProject.AddAliasedFileToProject(new AliasedFile( XmlConfigLoader.GetXSDPath(), Path.Combine("Programs", "STBuildTool") )); foreach (var BuildConfigurationPath in XmlConfigLoader.ConfigLocationHierarchy) { if (!BuildConfigurationPath.bExists) { continue; } EngineProject.AddAliasedFileToProject( new AliasedFile( BuildConfigurationPath.FSLocation, Path.Combine("Config", "STBuildTool", BuildConfigurationPath.IDEFolderName) ) ); } }
/// <summary> /// Adds STBuildTool to the master project /// </summary> private void AddSTBuildToolProject(MasterProjectFolder ProgramsFolder) { var ProjectFileName = Utils.MakePathRelativeTo(Path.Combine(Path.Combine(EngineRelativePath, "Source"), "Programs", "STBuildTool", "STBuildTool.csproj"), MasterProjectRelativePath); var STBuildToolProject = new VCSharpProjectFile(ProjectFileName); STBuildToolProject.ShouldBuildForAllSolutionTargets = true; // Store it off as we need it when generating target projects. UBTProject = STBuildToolProject; // Add the project AddExistingProjectFile(STBuildToolProject, bNeedsAllPlatformAndConfigurations: true, bForceDevelopmentConfiguration: true); // Put this in a solution folder ProgramsFolder.ChildProjects.Add(STBuildToolProject); }
/// <summary> /// Creates project entries for all known targets (*.Target.cs files) /// </summary> /// <param name="AllGameFolders">All game folders</param> /// <param name="EngineProject">The engine project we created</param> /// <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="TemplateGameProjects">Set of template game projects we found. These will also be in the GameProjects map</param> private void AddProjectsForAllTargets(List<UProjectInfo> AllGames, out ProjectFile EngineProject, out Dictionary<string, ProjectFile> GameProjects, out Dictionary<string, ProjectFile> ProgramProjects, out HashSet<ProjectFile> TemplateGameProjects) { // As we're creating project files, we'll also keep track of whether we created an "engine" project and return that if we have one EngineProject = null; GameProjects = new Dictionary<string, ProjectFile>(StringComparer.InvariantCultureIgnoreCase); ProgramProjects = new Dictionary<string, ProjectFile>(StringComparer.InvariantCultureIgnoreCase); TemplateGameProjects = new HashSet<ProjectFile>(); // Find all of the target files. This will filter out any modules or targets that don't // belong to platforms we're generating project files for. var AllTargetFiles = DiscoverTargets(); foreach (var TargetFilePath in AllTargetFiles) { var TargetName = Utils.GetFilenameWithoutAnyExtensions(TargetFilePath); // Remove both ".cs" and ".Target" // Check to see if this is an Engine target. That is, the target is located under the "Engine" folder bool IsEngineTarget = false; string TargetFileRelativeToEngineDirectory = Utils.MakePathRelativeTo(TargetFilePath, Path.Combine(EngineRelativePath), AlwaysTreatSourceAsDirectory: false); if (!TargetFileRelativeToEngineDirectory.StartsWith("..") && !Path.IsPathRooted(TargetFileRelativeToEngineDirectory)) { // This is an engine target IsEngineTarget = true; } bool WantProjectFileForTarget = true; if (TargetFileRelativeToEngineDirectory.StartsWith(Path.Combine("Source", "Programs"), StringComparison.InvariantCultureIgnoreCase)) { WantProjectFileForTarget = IncludeEnginePrograms; } else if (TargetFileRelativeToEngineDirectory.StartsWith(Path.Combine("Source"), StringComparison.InvariantCultureIgnoreCase)) { WantProjectFileForTarget = IncludeEngineSource; } if (WantProjectFileForTarget) { // Create target rules for all of the platforms and configuration combinations that we want to enable support for. // Just use the current platform as we only need to recover the target type and both should be supported for all targets... string UnusedTargetFilePath; var TargetRulesObject = RulesCompiler.CreateTargetRules(TargetName, new TargetInfo(BuildHostPlatform.Current.Platform, STTargetConfiguration.Development), false, out UnusedTargetFilePath); // Exclude client and server targets under binary Rocket; it's impossible to build without precompiled engine binaries if (!STBuildTool.RunningRocket() || (TargetRulesObject.Type != TargetRules.TargetType.Client && TargetRulesObject.Type != TargetRules.TargetType.Server)) { bool IsProgramTarget = false; string GameFolder = null; string ProjectFileNameBase = null; if (TargetRulesObject.Type == TargetRules.TargetType.Program) { IsProgramTarget = true; ProjectFileNameBase = TargetName; } else if (IsEngineTarget) { ProjectFileNameBase = EngineProjectFileNameBase; } else { // Figure out which game project this target belongs to UProjectInfo ProjectInfo = FindGameContainingFile(AllGames, TargetFilePath); if (ProjectInfo == null) { throw new BuildException("Found a non-engine target file (" + TargetFilePath + ") that did not exist within any of the known game folders"); } GameFolder = ProjectInfo.Folder; ProjectFileNameBase = ProjectInfo.GameName; } // @todo projectfiles: We should move all of the Target.cs files out of sub-folders to clean up the project directories a bit (e.g. GameUncooked folder) var ProjectFilePath = Path.Combine(IntermediateProjectFilesPath, ProjectFileNameBase + ProjectFileExtension); if (TargetRules.IsGameType(TargetRulesObject.Type) && (TargetRules.IsEditorType(TargetRulesObject.Type) == false)) { // Allow platforms to generate stub projects here... STPlatformProjectGenerator.GenerateGameProjectStubs( InGenerator: this, InTargetName: TargetName, InTargetFilepath: TargetFilePath, InTargetRules: TargetRulesObject, InPlatforms: SupportedPlatforms, InConfigurations: SupportedConfigurations); } ProjectFilePath = Utils.MakePathRelativeTo(ProjectFilePath, MasterProjectRelativePath); bool bProjectAlreadyExisted; var ProjectFile = FindOrAddProject(ProjectFilePath, IncludeInGeneratedProjects: true, bAlreadyExisted: out bProjectAlreadyExisted); ProjectFile.IsForeignProject = bGeneratingGameProjectFiles && STBuildTool.HasUProjectFile() && Utils.IsFileUnderDirectory(TargetFilePath, STBuildTool.GetUProjectPath()); ProjectFile.IsGeneratedProject = true; ProjectFile.IsStubProject = false; bool IsTemplateTarget = false; { // Check to see if this is a template target. That is, the target is located under the "Templates" folder string TargetFileRelativeToTemplatesDirectory = Utils.MakePathRelativeTo(TargetFilePath, Path.Combine(RootRelativePath, "Templates")); if (!TargetFileRelativeToTemplatesDirectory.StartsWith("..") && !Path.IsPathRooted(TargetFileRelativeToTemplatesDirectory)) { IsTemplateTarget = true; } } string BaseFolder = null; if (IsProgramTarget) { ProgramProjects[TargetName] = ProjectFile; BaseFolder = Path.GetDirectoryName(TargetFilePath); } else if (IsEngineTarget) { EngineProject = ProjectFile; BaseFolder = EngineRelativePath; } else { GameProjects[GameFolder] = ProjectFile; if (IsTemplateTarget) { TemplateGameProjects.Add(ProjectFile); } BaseFolder = GameFolder; if (!bProjectAlreadyExisted) { // Add the .uproject file for this game/template var UProjectFilePath = Path.Combine(BaseFolder, ProjectFileNameBase + ".uproject"); if (File.Exists(UProjectFilePath)) { ProjectFile.AddFileToProject(UProjectFilePath, BaseFolder); } else { throw new BuildException("Not expecting to find a game with no .uproject file. File '{0}' doesn't exist", UProjectFilePath); } } } foreach (var ExistingProjectTarget in ProjectFile.ProjectTargets) { if (ExistingProjectTarget.TargetRules.ConfigurationName.Equals(TargetRulesObject.ConfigurationName, StringComparison.InvariantCultureIgnoreCase)) { throw new BuildException("Not expecting project {0} to already have a target rules of with configuration name {1} ({2}) while trying to add: {3}", ProjectFilePath, TargetRulesObject.ConfigurationName, ExistingProjectTarget.TargetRules.ToString(), TargetRulesObject.ToString()); } // Not expecting to have both a game and a program in the same project. These would alias because we share the project and solution configuration names (just because it makes sense to) if (ExistingProjectTarget.TargetRules.Type == TargetRules.TargetType.Game && ExistingProjectTarget.TargetRules.Type == TargetRules.TargetType.Program || ExistingProjectTarget.TargetRules.Type == TargetRules.TargetType.Program && ExistingProjectTarget.TargetRules.Type == TargetRules.TargetType.Game) { throw new BuildException("Not expecting project {0} to already have a Game/Program target ({1}) associated with it while trying to add: {2}", ProjectFilePath, ExistingProjectTarget.TargetRules.ToString(), TargetRulesObject.ToString()); } } var ProjectTarget = new ProjectTarget() { TargetRules = TargetRulesObject, TargetFilePath = TargetFilePath }; if (TargetName == "ShaderCompileWorker") // @todo projectfiles: Ideally, the target rules file should set this { ProjectTarget.ForceDevelopmentConfiguration = true; } ProjectFile.ProjectTargets.Add(ProjectTarget); // Make sure the *.Target.cs file is in the project. ProjectFile.AddFileToProject(TargetFilePath, BaseFolder); // We special case ShaderCompileWorker. It needs to always be compiled in Development mode. Log.TraceVerbose("Generating target {0} for {1}", TargetRulesObject.Type.ToString(), ProjectFilePath); } } } }
/// Adds all engine template text files to the specified project private void AddEngineTemplateFiles(ProjectFile EngineProject) { var EngineTemplateDirectory = Path.Combine(EngineRelativePath, "Content", "Editor", "Templates"); if (Directory.Exists(EngineTemplateDirectory)) { var DirectoriesToSearch = new List<string>(); DirectoriesToSearch.Add(EngineTemplateDirectory); EngineProject.AddFilesToProject(SourceFileSearch.FindFiles(DirectoriesToSearch, ExcludeNoRedistFiles: bExcludeNoRedistFiles), EngineRelativePath); } }
/// <summary> /// Writes the master project file (e.g. Visual Studio Solution file) /// </summary> /// <param name="UBTProject">The STBuildTool project</param> /// <returns>True if successful</returns> protected abstract bool WriteMasterProjectFile(ProjectFile UBTProject);