Esempio n. 1
0
		// Anonymous function that writes project configuration data
		private void WriteConfiguration(string ProjectName, ProjectConfigAndTargetCombination Combination, StringBuilder VCProjectFileContent, StringBuilder VCUserFileContent)
		{
			UnrealTargetPlatform Platform = Combination.Platform;
			UnrealTargetConfiguration Configuration = Combination.Configuration;

			UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
			if (((ProjGenerator == null) && (Platform != UnrealTargetPlatform.Unknown)))
			{
				return;
			}
	
			string UProjectPath = "";
			if (IsForeignProject)
			{
				UProjectPath = "\"$(SolutionDir)$(ProjectName).uproject\"";
			}

			string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + Combination.ProjectConfigurationAndPlatformName + "'\"";

			{
				VCProjectFileContent.Append(
					"	<ImportGroup " + ConditionString + " Label=\"PropertySheets\">" + ProjectFileGenerator.NewLine +
					"		<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />" + ProjectFileGenerator.NewLine +
					"	</ImportGroup>" + ProjectFileGenerator.NewLine);

				if (IsStubProject)
				{
					string ProjectRelativeUnusedDirectory = NormalizeProjectPath(Path.Combine(ProjectFileGenerator.EngineRelativePath, BuildConfiguration.BaseIntermediateFolder, "Unused"));

					VCProjectFileContent.Append(
						"	<PropertyGroup " + ConditionString + ">" + ProjectFileGenerator.NewLine +
						"		<OutDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</OutDir>" + ProjectFileGenerator.NewLine +
						"		<IntDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator.NewLine +
						"		<NMakeBuildCommandLine>@rem Nothing to do.</NMakeBuildCommandLine>" + ProjectFileGenerator.NewLine +
						"		<NMakeReBuildCommandLine>@rem Nothing to do.</NMakeReBuildCommandLine>" + ProjectFileGenerator.NewLine +
						"		<NMakeCleanCommandLine>@rem Nothing to do.</NMakeCleanCommandLine>" + ProjectFileGenerator.NewLine +
						"		<NMakeOutput/>" + ProjectFileGenerator.NewLine +
						"	</PropertyGroup>" + ProjectFileGenerator.NewLine);
				}
				else if(ProjectFileGenerator.bGeneratingRocketProjectFiles && Combination.ProjectTarget != null && Combination.ProjectTarget.TargetRules != null && !Combination.ProjectTarget.TargetRules.SupportsPlatform(Combination.Platform))
				{
					List<UnrealTargetPlatform> SupportedPlatforms = new List<UnrealTargetPlatform>();
					Combination.ProjectTarget.TargetRules.GetSupportedPlatforms(ref SupportedPlatforms);

					string ProjectRelativeUnusedDirectory = NormalizeProjectPath(Path.Combine(ProjectFileGenerator.EngineRelativePath, BuildConfiguration.BaseIntermediateFolder, "Unused"));

					VCProjectFileContent.AppendFormat(
						"	<PropertyGroup " + ConditionString + ">" + ProjectFileGenerator.NewLine +
						"		<OutDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</OutDir>" + ProjectFileGenerator.NewLine +
						"		<IntDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator.NewLine +
						"		<NMakeBuildCommandLine>@echo {0} is not a supported platform for {1}. Valid platforms are {2}.</NMakeBuildCommandLine>" + ProjectFileGenerator.NewLine +
						"		<NMakeReBuildCommandLine>@echo {0} is not a supported platform for {1}. Valid platforms are {2}.</NMakeReBuildCommandLine>" + ProjectFileGenerator.NewLine +
						"		<NMakeCleanCommandLine>@echo {0} is not a supported platform for {1}. Valid platforms are {2}.</NMakeCleanCommandLine>" + ProjectFileGenerator.NewLine +
						"		<NMakeOutput/>" + ProjectFileGenerator.NewLine +
						"	</PropertyGroup>" + ProjectFileGenerator.NewLine, Combination.Platform, Utils.GetFilenameWithoutAnyExtensions(Combination.ProjectTarget.TargetFilePath), String.Join(", ", SupportedPlatforms.Select(x => x.ToString())));
				}
				else
				{
					TargetRules TargetRulesObject = Combination.ProjectTarget.TargetRules;
					string TargetFilePath = Combination.ProjectTarget.TargetFilePath;
					string TargetName = Utils.GetFilenameWithoutAnyExtensions(TargetFilePath);
					var UBTPlatformName = IsStubProject ? StubProjectPlatformName : Platform.ToString();
					var UBTConfigurationName = IsStubProject ? StubProjectConfigurationName : Configuration.ToString();

					// Setup output path
					var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform);

					// Figure out if this is a monolithic build
					bool bShouldCompileMonolithic = BuildPlatform.ShouldCompileMonolithicBinary(Platform);
					bShouldCompileMonolithic |= TargetRulesObject.ShouldCompileMonolithic(Platform, Configuration);

					// Get the output directory
					string EngineRootDirectory = Path.GetFullPath(ProjectFileGenerator.EngineRelativePath);
					string RootDirectory = EngineRootDirectory;
					if ((TargetRules.IsAGame(TargetRulesObject.Type) || TargetRulesObject.Type == TargetRules.TargetType.Server) && bShouldCompileMonolithic && !TargetRulesObject.bOutputToEngineBinaries)
					{
						if (UnrealBuildTool.HasUProjectFile() && Utils.IsFileUnderDirectory(TargetFilePath, UnrealBuildTool.GetUProjectPath()))
						{
							RootDirectory = Path.GetFullPath(UnrealBuildTool.GetUProjectPath());
						}
						else
						{
							string UnrealProjectPath = UProjectInfo.GetProjectFilePath(ProjectName);
							if (!String.IsNullOrEmpty(UnrealProjectPath))
							{
								RootDirectory = Path.GetDirectoryName(Path.GetFullPath(UnrealProjectPath));
							}
						}
					}

					if(TargetRulesObject.Type == TargetRules.TargetType.Program && !TargetRulesObject.bOutputToEngineBinaries)
					{
						string UnrealProjectPath = UProjectInfo.GetProjectForTarget(TargetName);
						if (!String.IsNullOrEmpty(UnrealProjectPath))
						{
							RootDirectory = Path.GetDirectoryName(Path.GetFullPath(UnrealProjectPath));
						}
					}

					// Get the output directory
					string OutputDirectory = Path.Combine(RootDirectory, "Binaries", UBTPlatformName);

					// Get the executable name (minus any platform or config suffixes)
					string BaseExeName = TargetName;
					if (!bShouldCompileMonolithic && TargetRulesObject.Type != TargetRules.TargetType.Program)
					{
						// Figure out what the compiled binary will be called so that we can point the IDE to the correct file
						string TargetConfigurationName = TargetRulesObject.ConfigurationName;
						if (TargetConfigurationName != TargetRules.TargetType.Game.ToString() && TargetConfigurationName != TargetRules.TargetType.Program.ToString())
						{
							BaseExeName = "UE4" + TargetConfigurationName;
						}
					}

					// Make the output file path
					string NMakePath = Path.Combine(OutputDirectory, BaseExeName);
					if (Configuration != UnrealTargetConfiguration.Development && (Configuration != UnrealTargetConfiguration.DebugGame || bShouldCompileMonolithic))
					{
						NMakePath += "-" + UBTPlatformName + "-" + UBTConfigurationName;
					}
					NMakePath += BuildPlatform.GetActiveArchitecture();
					NMakePath += BuildPlatform.GetBinaryExtension(UEBuildBinaryType.Executable);
					NMakePath = (BuildPlatform as UEBuildPlatform).ModifyNMakeOutput(NMakePath);

					VCProjectFileContent.Append(
						"	<PropertyGroup " + ConditionString + ">" + ProjectFileGenerator.NewLine);

					string PathStrings = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioPathsEntries(Platform, Configuration, TargetRulesObject.Type, TargetFilePath, ProjectFilePath, NMakePath) : "";
					if (string.IsNullOrEmpty(PathStrings) || (PathStrings.Contains("<IntDir>") == false))
					{
						string ProjectRelativeUnusedDirectory = "$(ProjectDir)..\\Build\\Unused";
						VCProjectFileContent.Append(
							PathStrings +
							"		<OutDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</OutDir>" + ProjectFileGenerator.NewLine +
							"		<IntDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator.NewLine);
					}
					else
					{
						VCProjectFileContent.Append(PathStrings);
					}

					if (TargetRules.IsGameType(TargetRulesObject.Type) &&
						(TargetRules.IsEditorType(TargetRulesObject.Type) == false))
					{
						// Allow platforms to add any special properties they require... like aumid override for Xbox One
						UEPlatformProjectGenerator.GenerateGamePlatformSpecificProperties(Platform, Configuration, TargetRulesObject.Type, VCProjectFileContent, RootDirectory, TargetFilePath);
					}

					// This is the standard UE4 based project NMake build line:
					//	..\..\Build\BatchFiles\Build.bat <TARGETNAME> <PLATFORM> <CONFIGURATION>
					//	ie ..\..\Build\BatchFiles\Build.bat BlankProgram Win64 Debug

					string BuildArguments = " " + TargetName + " " + UBTPlatformName + " " + UBTConfigurationName;
					if(ProjectFileGenerator.bUsePrecompiled)
					{
						BuildArguments += " -useprecompiled";
					}
					if (IsForeignProject)
					{
						BuildArguments += " " + UProjectPath + (UnrealBuildTool.RunningRocket() ? " -rocket" : "");
					}

					// Always wait for the mutex between UBT invocations, so that building the whole solution doesn't fail.
					BuildArguments += " -waitmutex";

					string BatchFilesDirectoryName = Path.Combine(ProjectFileGenerator.EngineRelativePath, "Build", "BatchFiles");

					// @todo UWP: For the MS toolchains, if an override was set for project generation, push that into the build strings to override the build toolchain as well
					string BuildToolOverride = "";
					if (UnrealBuildTool.CommandLineContains("-2012"))
					{
						BuildToolOverride = " -2012";
					}
					if (UnrealBuildTool.CommandLineContains("-2013"))
					{
						BuildToolOverride = " -2013";
					}
					if (UnrealBuildTool.CommandLineContains("-2015"))
					{
						BuildToolOverride = " -2015";
					}
					BuildArguments += BuildToolOverride;

					// NMake Build command line
					VCProjectFileContent.Append("		<NMakeBuildCommandLine>");
					VCProjectFileContent.Append(EscapePath(NormalizeProjectPath(Path.Combine(BatchFilesDirectoryName, "Build.bat"))) + BuildArguments.ToString());
					VCProjectFileContent.Append("</NMakeBuildCommandLine>" + ProjectFileGenerator.NewLine);

					// NMake ReBuild command line
					VCProjectFileContent.Append("		<NMakeReBuildCommandLine>");
					VCProjectFileContent.Append(EscapePath(NormalizeProjectPath(Path.Combine(BatchFilesDirectoryName, "Rebuild.bat"))) + BuildArguments.ToString());
					VCProjectFileContent.Append("</NMakeReBuildCommandLine>" + ProjectFileGenerator.NewLine);

					// NMake Clean command line
					VCProjectFileContent.Append("		<NMakeCleanCommandLine>");
					VCProjectFileContent.Append(EscapePath(NormalizeProjectPath(Path.Combine(BatchFilesDirectoryName, "Clean.bat"))) + BuildArguments.ToString());
					VCProjectFileContent.Append("</NMakeCleanCommandLine>" + ProjectFileGenerator.NewLine);

					VCProjectFileContent.Append("		<NMakeOutput>");
					VCProjectFileContent.Append(NormalizeProjectPath(NMakePath));
					VCProjectFileContent.Append("</NMakeOutput>" + ProjectFileGenerator.NewLine);
					VCProjectFileContent.Append("	</PropertyGroup>" + ProjectFileGenerator.NewLine);

					string LayoutDirString = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioLayoutDirSection(Platform, Configuration, ConditionString, Combination.ProjectTarget.TargetRules.Type, Combination.ProjectTarget.TargetFilePath, ProjectFilePath, NMakePath) : "";
					VCProjectFileContent.Append(LayoutDirString);
				}

				if (VCUserFileContent != null && Combination.ProjectTarget != null)
				{
					TargetRules TargetRulesObject = Combination.ProjectTarget.TargetRules;

					if ((Platform == UnrealTargetPlatform.Win32) || (Platform == UnrealTargetPlatform.Win64) || (Platform == UnrealTargetPlatform.UWP))
					{
						VCUserFileContent.Append(
							"	<PropertyGroup " + ConditionString + ">" + ProjectFileGenerator.NewLine);
						if (TargetRulesObject.Type != TargetRules.TargetType.Game)
						{
							string DebugOptions = "";
							
							if(IsForeignProject)
							{
								DebugOptions += UProjectPath;
							}
							else if(TargetRulesObject.Type == TargetRules.TargetType.Editor && ProjectName != "UE4")
							{
								DebugOptions += ProjectName;
							}

							if (Configuration == UnrealTargetConfiguration.Debug || Configuration == UnrealTargetConfiguration.DebugGame)
							{
								DebugOptions += " -debug";
							}
							else if (Configuration == UnrealTargetConfiguration.Shipping)
							{
								DebugOptions += " -shipping";
							}

							VCUserFileContent.Append(
								"		<LocalDebuggerCommandArguments>" + DebugOptions + "</LocalDebuggerCommandArguments>" + ProjectFileGenerator.NewLine
								);
						}
						VCUserFileContent.Append(
							"		<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>" + ProjectFileGenerator.NewLine
							);
						VCUserFileContent.Append(
							"	</PropertyGroup>" + ProjectFileGenerator.NewLine
							);
					}

					string PlatformUserFileStrings = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioUserFileStrings(Platform, Configuration, ConditionString, TargetRulesObject, Combination.ProjectTarget.TargetFilePath, ProjectFilePath) : "";
					VCUserFileContent.Append(PlatformUserFileStrings);
				}
			}
		}
Esempio n. 2
0
        // Anonymous function that writes pre-Default.props configuration data
        private void WritePreDefaultPropsConfiguration(ProjectConfigAndTargetCombination Combination, StringBuilder VCProjectFileContent)
        {
            STPlatformProjectGenerator ProjGenerator = STPlatformProjectGenerator.GetPlatformProjectGenerator(Combination.Platform, true);
            if (((ProjGenerator == null) && (Combination.Platform != STTargetPlatform.Unknown)))
            {
                return;
            }

            string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + Combination.ProjectConfigurationAndPlatformName + "'\"";

            string PlatformToolsetString = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioPlatformToolsetString(Combination.Platform, Combination.Configuration, this) : "";
            if (String.IsNullOrEmpty(PlatformToolsetString))
            {
                if (VCProjectFileGenerator.ProjectFileFormat == VCProjectFileGenerator.VCProjectFileFormat.VisualStudio2013)
                {
                    PlatformToolsetString = "		<PlatformToolset>v120</PlatformToolset>" + ProjectFileGenerator.NewLine;
                }
                else if (VCProjectFileGenerator.ProjectFileFormat == VCProjectFileGenerator.VCProjectFileFormat.VisualStudio2012)
                {
                    PlatformToolsetString = "		<PlatformToolset>v110</PlatformToolset>" + ProjectFileGenerator.NewLine;
                }
            }

            string PlatformConfigurationType = (ProjGenerator == null) ? "Makefile" : ProjGenerator.GetVisualStudioPlatformConfigurationType(Combination.Platform);
            VCProjectFileContent.Append(
                "	<PropertyGroup " + ConditionString + " Label=\"Configuration\">" + ProjectFileGenerator.NewLine +
                "		<ConfigurationType>" + PlatformConfigurationType + "</ConfigurationType>" + ProjectFileGenerator.NewLine +
                        PlatformToolsetString +
                "	</PropertyGroup>" + ProjectFileGenerator.NewLine
                );
        }
Esempio n. 3
0
		/// Implements Project interface
		public override bool WriteProjectFile(List<UnrealTargetPlatform> InPlatforms, List<UnrealTargetConfiguration> InConfigurations)
		{
			string ProjectName = Path.GetFileNameWithoutExtension(ProjectFilePath);

			bool bSuccess = true;

			// NOTE: We intentionally do not SORT the source file list, as we want the order they're written to disk to be consistent
			//       with how they are stored in memory.  This makes for more consistent Unity compiles when alternating between
			//       using "auto" projects and on-disk projects for builds.
			var ShouldSortSourceFiles = false;
			if( ShouldSortSourceFiles )
			{
				// Source our list of source files
				Comparison<SourceFile> SourceFileComparer = ( FileA, FileB ) => { return FileA.FilePath.CompareTo( FileB.FilePath ); };
				SourceFiles.Sort( SourceFileComparer );
			}

			// Build up the new include search path string
			var VCIncludeSearchPaths = new StringBuilder();
			{
				foreach (var CurPath in IntelliSenseIncludeSearchPaths)
				{
					VCIncludeSearchPaths.Append(CurPath + ";");
				}
				foreach (var CurPath in IntelliSenseSystemIncludeSearchPaths)
				{
					VCIncludeSearchPaths.Append(CurPath + ";");
				}
				if (InPlatforms.Contains(UnrealTargetPlatform.UWP))
				{
					VCIncludeSearchPaths.Append(UWPToolChain.GetVCIncludePaths(CPPTargetPlatform.UWP) + ";");
				}
				else if (InPlatforms.Contains(UnrealTargetPlatform.Win64))
				{
					VCIncludeSearchPaths.Append(VCToolChain.GetVCIncludePaths(CPPTargetPlatform.Win64) + ";");
				}
				else if (InPlatforms.Contains(UnrealTargetPlatform.Win32))
				{
					VCIncludeSearchPaths.Append(VCToolChain.GetVCIncludePaths(CPPTargetPlatform.Win32) + ";");
				}
			}

			var VCPreprocessorDefinitions = new StringBuilder();
			foreach( var CurDef in IntelliSensePreprocessorDefinitions )
			{
				if( VCPreprocessorDefinitions.Length > 0 )
				{
					VCPreprocessorDefinitions.Append( ';' );
				}
				VCPreprocessorDefinitions.Append( CurDef );
			}

			// Setup VC project file content
			var VCProjectFileContent = new StringBuilder();
			var VCFiltersFileContent = new StringBuilder();
			var VCUserFileContent = new StringBuilder();

			// Visual Studio doesn't require a *.vcxproj.filters file to even exist alongside the project unless 
			// it actually has something of substance in it.  We'll avoid saving it out unless we need to.
			var FiltersFileIsNeeded = false;

			// Project file header
			VCProjectFileContent.Append(
				"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator.NewLine +
				ProjectFileGenerator.NewLine +
				"<Project DefaultTargets=\"Build\" ToolsVersion=\"" + VCProjectFileGenerator.ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator.NewLine);

			bool bGenerateUserFileContent = UEPlatformProjectGenerator.PlatformRequiresVSUserFileGeneration(InPlatforms, InConfigurations);
			if (bGenerateUserFileContent)
			{
				VCUserFileContent.Append(
					"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator.NewLine + 
					ProjectFileGenerator.NewLine +
					"<Project ToolsVersion=\"" + VCProjectFileGenerator.ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator.NewLine
					);
			}

			// Build up a list of platforms and configurations this project will support.  In this list, Unknown simply
			// means that we should use the default "stub" project platform and configuration name.
			var ProjectConfigAndTargetCombinations = new List< ProjectConfigAndTargetCombination >();

			// If this is a "stub" project, then only add a single configuration to the project
			if( IsStubProject )
			{
				ProjectConfigAndTargetCombination StubCombination = new ProjectConfigAndTargetCombination(UnrealTargetPlatform.Unknown, UnrealTargetConfiguration.Unknown, StubProjectPlatformName, StubProjectConfigurationName, null);
				ProjectConfigAndTargetCombinations.Add(StubCombination);
			}
			else
			{
				// Figure out all the desired configurations
				foreach (var Configuration in InConfigurations)
				{
					//@todo.Rocket: Put this in a commonly accessible place?
					if (UnrealBuildTool.IsValidConfiguration(Configuration) == false)
					{
						continue;
					}
					foreach (var Platform in InPlatforms)
					{
						if (UnrealBuildTool.IsValidPlatform(Platform) == false)
						{
							continue;
						}
						var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform, true);
						if ((BuildPlatform != null) && (BuildPlatform.HasRequiredSDKsInstalled() == SDKStatus.Valid))
						{
							// Now go through all of the target types for this project
							if( ProjectTargets.Count == 0 )
							{
								throw new BuildException( "Expecting at least one ProjectTarget to be associated with project '{0}' in the TargetProjects list ", ProjectFilePath );
							}

							foreach( var ProjectTarget in ProjectTargets )
							{
								if(IsValidProjectPlatformAndConfiguration( ProjectTarget, Platform, Configuration ))
								{
									string ProjectPlatformName, ProjectConfigurationName;
									MakeProjectPlatformAndConfigurationNames(Platform, Configuration, ProjectTarget.TargetRules.ConfigurationName, out ProjectPlatformName, out ProjectConfigurationName);

									ProjectConfigAndTargetCombination Combination = new ProjectConfigAndTargetCombination(Platform, Configuration, ProjectPlatformName, ProjectConfigurationName, ProjectTarget);
									ProjectConfigAndTargetCombinations.Add( Combination );
								}
							}
						}
					}
				}
			}

			VCProjectFileContent.Append(
				"	<ItemGroup Label=\"ProjectConfigurations\">" + ProjectFileGenerator.NewLine);

			// Make a list of the platforms and configs as project-format names
			var ProjectPlatforms = new List<UnrealTargetPlatform>();
			var ProjectPlatformNameAndPlatforms = new List<Tuple<string, UnrealTargetPlatform>>();	// ProjectPlatformName, Platform
			var ProjectConfigurationNameAndConfigurations = new List<Tuple<string, UnrealTargetConfiguration>>();	// ProjectConfigurationName, Configuration
			foreach ( var Combination in ProjectConfigAndTargetCombinations )
			{
				if( !ProjectPlatforms.Contains( Combination.Platform ) )
				{
					ProjectPlatforms.Add( Combination.Platform );
				}
				if( !ProjectPlatformNameAndPlatforms.Any( ProjectPlatformNameAndPlatformTuple => ProjectPlatformNameAndPlatformTuple.Item1 == Combination.ProjectPlatformName ) )
				{
					ProjectPlatformNameAndPlatforms.Add( Tuple.Create( Combination.ProjectPlatformName, Combination.Platform ) );
				}
				if( !ProjectConfigurationNameAndConfigurations.Any( ProjectConfigurationNameAndConfigurationTuple => ProjectConfigurationNameAndConfigurationTuple.Item1 == Combination.ProjectConfigurationName ) )
				{
					ProjectConfigurationNameAndConfigurations.Add( Tuple.Create( Combination.ProjectConfigurationName, Combination.Configuration ) ); 
				}
            }

			// Output ALL the project's config-platform permutations (project files MUST do this)
			foreach( var ConfigurationTuple in ProjectConfigurationNameAndConfigurations )
			{
				var ProjectConfigurationName = ConfigurationTuple.Item1;
				foreach( var PlatformTuple in ProjectPlatformNameAndPlatforms )
				{
					var ProjectPlatformName = PlatformTuple.Item1;
                    VCProjectFileContent.Append(
							"		<ProjectConfiguration Include=\"" + ProjectConfigurationName + "|" + ProjectPlatformName + "\">" + ProjectFileGenerator.NewLine +
							"			<Configuration>" + ProjectConfigurationName + "</Configuration>" + ProjectFileGenerator.NewLine +
							"			<Platform>" + ProjectPlatformName + "</Platform>" + ProjectFileGenerator.NewLine +
							"		</ProjectConfiguration>" + ProjectFileGenerator.NewLine);
				}              
			}

			VCProjectFileContent.Append(
				"	</ItemGroup>" + ProjectFileGenerator.NewLine);

			VCFiltersFileContent.Append(
				"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator.NewLine +
				ProjectFileGenerator.NewLine +
				"<Project ToolsVersion=\"" + VCProjectFileGenerator.ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator.NewLine);

			// Platform specific PropertyGroups, etc.
			StringBuilder AdditionalPropertyGroups = new StringBuilder();
			if (!IsStubProject)
			{
				foreach (var Platform in ProjectPlatforms)
				{
					UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
					if (ProjGenerator != null && ProjGenerator.HasVisualStudioSupport(Platform, UnrealTargetConfiguration.Development))
					{
						AdditionalPropertyGroups.Append(ProjGenerator.GetAdditionalVisualStudioPropertyGroups(Platform));
					}
				}

				VCProjectFileContent.Append( AdditionalPropertyGroups );
			}

			// Project globals (project GUID, project type, SCC bindings, etc)
			{
				VCProjectFileContent.Append(
					"	<PropertyGroup Label=\"Globals\">" + ProjectFileGenerator.NewLine +
					"		<ProjectGuid>" + ProjectGUID.ToString("B").ToUpperInvariant() + "</ProjectGuid>" + ProjectFileGenerator.NewLine +
					"		<Keyword>MakeFileProj</Keyword>" + ProjectFileGenerator.NewLine +
					"		<RootNamespace>" + ProjectName + "</RootNamespace>" + ProjectFileGenerator.NewLine);

				VCProjectFileContent.Append(
					"	</PropertyGroup>" + ProjectFileGenerator.NewLine);
			}

			// Write each project configuration PreDefaultProps section
			foreach (var ConfigurationTuple in ProjectConfigurationNameAndConfigurations)
			{
				var ProjectConfigurationName = ConfigurationTuple.Item1;
				var TargetConfiguration = ConfigurationTuple.Item2;
				foreach (var PlatformTuple in ProjectPlatformNameAndPlatforms)
				{
					var ProjectPlatformName = PlatformTuple.Item1;
					var TargetPlatform = PlatformTuple.Item2;
					WritePreDefaultPropsConfiguration(TargetPlatform, TargetConfiguration, ProjectPlatformName, ProjectConfigurationName, VCProjectFileContent);
				}
			}

			VCProjectFileContent.Append(
				"	<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />" + ProjectFileGenerator.NewLine);


			VCProjectFileContent.Append(
				"	<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />" + ProjectFileGenerator.NewLine +
				"	<ImportGroup Label=\"ExtensionSettings\" />" + ProjectFileGenerator.NewLine +
				"	<PropertyGroup Label=\"UserMacros\" />" + ProjectFileGenerator.NewLine
				);

			// Write each project configuration
			foreach( var Combination in ProjectConfigAndTargetCombinations )
			{
				WriteConfiguration( ProjectName, Combination, VCProjectFileContent, bGenerateUserFileContent? VCUserFileContent : null );
			}

			// Source folders and files
			{
				var LocalAliasedFiles = new List<AliasedFile>(AliasedFiles);

				foreach (var CurFile in SourceFiles)
				{
					if (CurFile.FilePath.Contains(".svn")){
						continue;
					}
					// We want all source file and directory paths in the project files to be relative to the project file's
					// location on the disk.  Convert the path to be relative to the project file directory
					var ProjectRelativeSourceFile = Utils.MakePathRelativeTo(CurFile.FilePath, Path.GetDirectoryName(ProjectFilePath));

					// By default, files will appear relative to the project file in the solution.  This is kind of the normal Visual
					// Studio way to do things, but because our generated project files are emitted to intermediate folders, if we always
					// did this it would yield really ugly paths int he solution explorer
					string FilterRelativeSourceDirectory = Path.GetDirectoryName(ProjectRelativeSourceFile);

					// Use the specified relative base folder
					if (CurFile.RelativeBaseFolder != null)	// NOTE: We are looking for null strings, not empty strings!
					{
						FilterRelativeSourceDirectory = Path.GetDirectoryName(Utils.MakePathRelativeTo(CurFile.FilePath, CurFile.RelativeBaseFolder));
					}

					LocalAliasedFiles.Add(new AliasedFile(ProjectRelativeSourceFile, FilterRelativeSourceDirectory));
				}

				VCFiltersFileContent.Append(
					"	<ItemGroup>" + ProjectFileGenerator.NewLine);

				VCProjectFileContent.Append(
					"	<ItemGroup>" + ProjectFileGenerator.NewLine);

				// Add all file directories to the filters file as solution filters
				var FilterDirectories = new HashSet<string>();
				foreach (var AliasedFile in LocalAliasedFiles)
				{
					// No need to add the root directory relative to the project (it would just be an empty string!)
					if (!String.IsNullOrWhiteSpace(AliasedFile.ProjectPath))
					{
						FiltersFileIsNeeded = EnsureFilterPathExists(AliasedFile.ProjectPath, VCFiltersFileContent, FilterDirectories);
					}

					var VCFileType = GetVCFileType(AliasedFile.FileSystemPath);

					VCProjectFileContent.Append(
						"		<" + VCFileType + " Include=\"" + AliasedFile.FileSystemPath + "\" />" + ProjectFileGenerator.NewLine);

					if (!String.IsNullOrWhiteSpace(AliasedFile.ProjectPath))
					{
						VCFiltersFileContent.Append(
							"		<" + VCFileType + " Include=\"" + AliasedFile.FileSystemPath + "\">" + ProjectFileGenerator.NewLine +
							"			<Filter>" + Utils.CleanDirectorySeparators(AliasedFile.ProjectPath) + "</Filter>" + ProjectFileGenerator.NewLine +
							"		</" + VCFileType + " >" + ProjectFileGenerator.NewLine);

						FiltersFileIsNeeded = true;
					}
					else
					{
						// No need to specify the root directory relative to the project (it would just be an empty string!)
						VCFiltersFileContent.Append(
							"		<" + VCFileType + " Include=\"" + AliasedFile.FileSystemPath + "\" />" + ProjectFileGenerator.NewLine);
					}
				}

				VCProjectFileContent.Append(
					"	</ItemGroup>" + ProjectFileGenerator.NewLine);

				VCFiltersFileContent.Append(
					"	</ItemGroup>" + ProjectFileGenerator.NewLine);
			}

			// For Rocket, include engine source in the source search paths. We never build it locally, so the debugger can't find it.
			if(UnrealBuildTool.RunningRocket() && !IsStubProject)
			{
				VCProjectFileContent.Append("	<PropertyGroup>" + ProjectFileGenerator.NewLine);
				VCProjectFileContent.Append("		<SourcePath>");
				foreach(string DirectoryName in Directory.EnumerateDirectories(Path.GetFullPath(Path.Combine(ProjectFileGenerator.EngineRelativePath, "Source")), "*", SearchOption.AllDirectories))
				{
					if(Directory.EnumerateFiles(DirectoryName, "*.cpp").Any())
					{
						VCProjectFileContent.Append(DirectoryName);
						VCProjectFileContent.Append(";");
					}
				}
				VCProjectFileContent.Append("</SourcePath>" + ProjectFileGenerator.NewLine);
				VCProjectFileContent.Append("	</PropertyGroup>" + ProjectFileGenerator.NewLine);
			}

			// Write IntelliSense info
			{
				// @todo projectfiles: Currently we are storing defines/include paths for ALL configurations rather than using ConditionString and storing
				//      this data uniquely for each target configuration.  IntelliSense may behave better if we did that, but it will result in a LOT more
				//      data being stored into the project file, and might make the IDE perform worse when switching configurations!
				VCProjectFileContent.Append(
					"	<PropertyGroup>" + ProjectFileGenerator.NewLine +
					"		<NMakePreprocessorDefinitions>$(NMakePreprocessorDefinitions)" + ( VCPreprocessorDefinitions.Length > 0 ? ( ";" + VCPreprocessorDefinitions ) : "" ) + "</NMakePreprocessorDefinitions>" + ProjectFileGenerator.NewLine +
					"		<NMakeIncludeSearchPath>$(NMakeIncludeSearchPath)" + ( VCIncludeSearchPaths.Length > 0 ? ( ";" + VCIncludeSearchPaths ) : "" ) + "</NMakeIncludeSearchPath>" + ProjectFileGenerator.NewLine +
					"		<NMakeForcedIncludes>$(NMakeForcedIncludes)</NMakeForcedIncludes>" + ProjectFileGenerator.NewLine +
					"		<NMakeAssemblySearchPath>$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>" + ProjectFileGenerator.NewLine +
					"		<NMakeForcedUsingAssemblies>$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>" + ProjectFileGenerator.NewLine +
					"	</PropertyGroup>" + ProjectFileGenerator.NewLine );
			}

			// look for additional import lines for all platforms for non stub projects
			StringBuilder AdditionalImportSettings = new StringBuilder();
			if (!IsStubProject)
			{
				foreach (var Platform in ProjectPlatforms)
				{
					UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
					if (ProjGenerator != null && ProjGenerator.HasVisualStudioSupport(Platform, UnrealTargetConfiguration.Development))
					{
						AdditionalImportSettings.Append(ProjGenerator.GetAdditionalVisualStudioImportSettings(Platform));
					}
				}
			}

			string OutputManifestString = "";
			if (!IsStubProject)
			{
				foreach (var Platform in ProjectPlatforms)
				{
					UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
					if (ProjGenerator != null && ProjGenerator.HasVisualStudioSupport(Platform, UnrealTargetConfiguration.Development))
					{
						// @todo projectfiles: Serious hacks here because we are trying to emit one-time platform-specific sections that need information
						//    about a target type, but the project file may contain many types of targets!  Some of this logic will need to move into
						//    the per-target configuration writing code.
						var HackTargetType = TargetRules.TargetType.Game;
						string HackTargetFilePath = null;
						foreach( var Combination in ProjectConfigAndTargetCombinations )
						{
							if( Combination.Platform == Platform &&
								Combination.ProjectTarget.TargetRules != null && 
								Combination.ProjectTarget.TargetRules.Type == HackTargetType )
							{
								HackTargetFilePath = Combination.ProjectTarget.TargetFilePath;// ProjectConfigAndTargetCombinations[0].ProjectTarget.TargetFilePath;
								break;										
							}
						}

						if( !String.IsNullOrEmpty( HackTargetFilePath ) )
						{
							OutputManifestString += ProjGenerator.GetVisualStudioOutputManifestSection(Platform, HackTargetType, HackTargetFilePath, ProjectFilePath);
						}
					}
				}
			}

			VCProjectFileContent.Append(
					OutputManifestString +	// output manifest must come before the Cpp.targets file.
					"	<ItemDefinitionGroup>" + ProjectFileGenerator.NewLine +
					"	</ItemDefinitionGroup>" + ProjectFileGenerator.NewLine +
					"	<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />" + ProjectFileGenerator.NewLine +
					AdditionalImportSettings.ToString() +
					"	<ImportGroup Label=\"ExtensionTargets\">" + ProjectFileGenerator.NewLine +
					"	</ImportGroup>" + ProjectFileGenerator.NewLine +
					"</Project>" + ProjectFileGenerator.NewLine );

			VCFiltersFileContent.Append(
				"</Project>" + ProjectFileGenerator.NewLine );

			if (bGenerateUserFileContent)
			{
				VCUserFileContent.Append(
					"</Project>" + ProjectFileGenerator.NewLine
					);
			}

			// Save the project file
			if( bSuccess )
			{
				bSuccess = ProjectFileGenerator.WriteFileIfChanged( ProjectFilePath, VCProjectFileContent.ToString() );
			}


			// Save the filters file
			if( bSuccess )
			{
				// Create a path to the project file's filters file
				var VCFiltersFilePath = ProjectFilePath + ".filters";
				if( FiltersFileIsNeeded )
				{
					bSuccess = ProjectFileGenerator.WriteFileIfChanged( VCFiltersFilePath, VCFiltersFileContent.ToString() );
				}
				else
				{
					Log.TraceVerbose( "Deleting Visual C++ filters file which is no longer needed: " + VCFiltersFilePath );

					// Delete the filters file, if one exists.  We no longer need it
					try
					{
						File.Delete( VCFiltersFilePath );
					}
					catch( Exception )
					{
						Log.TraceInformation( "Error deleting filters file (file may not be writable): " + VCFiltersFilePath );
					}
				}
			}

			// Save the user file, if required
			if (VCUserFileContent.Length > 0)
			{
				// Create a path to the project file's user file
				var VCUserFilePath = ProjectFilePath + ".user";
				// Never overwrite the existing user path as it will cause them to lose their settings
				if (File.Exists(VCUserFilePath) == false)
				{
					bSuccess = ProjectFileGenerator.WriteFileIfChanged(VCUserFilePath, VCUserFileContent.ToString());
				}
			}

			return bSuccess;
		}
Esempio n. 4
0
		/// Implements Project interface
		public override bool WriteProjectFile(List<UnrealTargetPlatform> InPlatforms, List<UnrealTargetConfiguration> InConfigurations)
		{
			string ProjectName = ProjectFilePath.GetFileNameWithoutExtension();

			bool bSuccess = true;

			// Build up the new include search path string
			StringBuilder VCIncludeSearchPaths = new StringBuilder();
			{
				foreach (string CurPath in IntelliSenseIncludeSearchPaths)
				{
					VCIncludeSearchPaths.Append(CurPath + ";");
				}
				foreach (string CurPath in IntelliSenseSystemIncludeSearchPaths)
				{
					VCIncludeSearchPaths.Append(CurPath + ";");
				}
				if (InPlatforms.Contains(UnrealTargetPlatform.Win64))
				{
					VCIncludeSearchPaths.Append(VCToolChain.GetVCIncludePaths(CPPTargetPlatform.Win64, false) + ";");
				}
				else if (InPlatforms.Contains(UnrealTargetPlatform.Win32))
				{
					VCIncludeSearchPaths.Append(VCToolChain.GetVCIncludePaths(CPPTargetPlatform.Win32, false) + ";");
				}
			}

			StringBuilder VCPreprocessorDefinitions = new StringBuilder();
			foreach (string CurDef in IntelliSensePreprocessorDefinitions)
			{
				if (VCPreprocessorDefinitions.Length > 0)
				{
					VCPreprocessorDefinitions.Append(';');
				}
				VCPreprocessorDefinitions.Append(CurDef);
			}

			// Setup VC project file content
			StringBuilder VCProjectFileContent = new StringBuilder();
			StringBuilder VCFiltersFileContent = new StringBuilder();
			StringBuilder VCUserFileContent = new StringBuilder();

			// Visual Studio doesn't require a *.vcxproj.filters file to even exist alongside the project unless 
			// it actually has something of substance in it.  We'll avoid saving it out unless we need to.
			bool FiltersFileIsNeeded = false;

			// Project file header
			VCProjectFileContent.Append(
				"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator.NewLine +
				ProjectFileGenerator.NewLine +
				"<Project DefaultTargets=\"Build\" ToolsVersion=\"" + VCProjectFileGenerator.ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator.NewLine);

			bool bGenerateUserFileContent = UEPlatformProjectGenerator.PlatformRequiresVSUserFileGeneration(InPlatforms, InConfigurations);
			if (bGenerateUserFileContent)
			{
				VCUserFileContent.Append(
					"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator.NewLine +
					ProjectFileGenerator.NewLine +
					"<Project ToolsVersion=\"" + VCProjectFileGenerator.ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator.NewLine
					);
			}

			// Build up a list of platforms and configurations this project will support.  In this list, Unknown simply
			// means that we should use the default "stub" project platform and configuration name.
			List<ProjectConfigAndTargetCombination> ProjectConfigAndTargetCombinations = new List<ProjectConfigAndTargetCombination>();

			// If this is a "stub" project, then only add a single configuration to the project
			if (IsStubProject)
			{
				ProjectConfigAndTargetCombination StubCombination = new ProjectConfigAndTargetCombination(UnrealTargetPlatform.Unknown, UnrealTargetConfiguration.Unknown, StubProjectPlatformName, StubProjectConfigurationName, null);
				ProjectConfigAndTargetCombinations.Add(StubCombination);
			}
			else
			{
				// Figure out all the desired configurations
				foreach (UnrealTargetConfiguration Configuration in InConfigurations)
				{
					//@todo.Rocket: Put this in a commonly accessible place?
					if (UnrealBuildTool.IsValidConfiguration(Configuration) == false)
					{
						continue;
					}
					foreach (UnrealTargetPlatform Platform in InPlatforms)
					{
						if (UnrealBuildTool.IsValidPlatform(Platform) == false)
						{
							continue;
						}
						UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform, true);
						if ((BuildPlatform != null) && (BuildPlatform.HasRequiredSDKsInstalled() == SDKStatus.Valid))
						{
							// Now go through all of the target types for this project
							if (ProjectTargets.Count == 0)
							{
								throw new BuildException("Expecting at least one ProjectTarget to be associated with project '{0}' in the TargetProjects list ", ProjectFilePath);
							}

							foreach (ProjectTarget ProjectTarget in ProjectTargets)
							{
								if (IsValidProjectPlatformAndConfiguration(ProjectTarget, Platform, Configuration))
								{
									string ProjectPlatformName, ProjectConfigurationName;
									MakeProjectPlatformAndConfigurationNames(Platform, Configuration, ProjectTarget.TargetRules.ConfigurationName, out ProjectPlatformName, out ProjectConfigurationName);

									ProjectConfigAndTargetCombination Combination = new ProjectConfigAndTargetCombination(Platform, Configuration, ProjectPlatformName, ProjectConfigurationName, ProjectTarget);
									ProjectConfigAndTargetCombinations.Add(Combination);
								}
							}
						}
					}
				}
			}

			VCProjectFileContent.Append(
				"	<ItemGroup Label=\"ProjectConfigurations\">" + ProjectFileGenerator.NewLine);

			// Make a list of the platforms and configs as project-format names
			List<UnrealTargetPlatform> ProjectPlatforms = new List<UnrealTargetPlatform>();
			List<Tuple<string, UnrealTargetPlatform>> ProjectPlatformNameAndPlatforms = new List<Tuple<string, UnrealTargetPlatform>>();	// ProjectPlatformName, Platform
			List<Tuple<string, UnrealTargetConfiguration>> ProjectConfigurationNameAndConfigurations = new List<Tuple<string, UnrealTargetConfiguration>>();	// ProjectConfigurationName, Configuration
			foreach (ProjectConfigAndTargetCombination Combination in ProjectConfigAndTargetCombinations)
			{
				if (!ProjectPlatforms.Contains(Combination.Platform))
				{
					ProjectPlatforms.Add(Combination.Platform);
				}
				if (!ProjectPlatformNameAndPlatforms.Any(ProjectPlatformNameAndPlatformTuple => ProjectPlatformNameAndPlatformTuple.Item1 == Combination.ProjectPlatformName))
				{
					ProjectPlatformNameAndPlatforms.Add(Tuple.Create(Combination.ProjectPlatformName, Combination.Platform));
				}
				if (!ProjectConfigurationNameAndConfigurations.Any(ProjectConfigurationNameAndConfigurationTuple => ProjectConfigurationNameAndConfigurationTuple.Item1 == Combination.ProjectConfigurationName))
				{
					ProjectConfigurationNameAndConfigurations.Add(Tuple.Create(Combination.ProjectConfigurationName, Combination.Configuration));
				}
			}

			// Output ALL the project's config-platform permutations (project files MUST do this)
			foreach (Tuple<string, UnrealTargetConfiguration> ConfigurationTuple in ProjectConfigurationNameAndConfigurations)
			{
				string ProjectConfigurationName = ConfigurationTuple.Item1;
				foreach (Tuple<string, UnrealTargetPlatform> PlatformTuple in ProjectPlatformNameAndPlatforms)
				{
					string ProjectPlatformName = PlatformTuple.Item1;
					VCProjectFileContent.Append(
							"		<ProjectConfiguration Include=\"" + ProjectConfigurationName + "|" + ProjectPlatformName + "\">" + ProjectFileGenerator.NewLine +
							"			<Configuration>" + ProjectConfigurationName + "</Configuration>" + ProjectFileGenerator.NewLine +
							"			<Platform>" + ProjectPlatformName + "</Platform>" + ProjectFileGenerator.NewLine +
							"		</ProjectConfiguration>" + ProjectFileGenerator.NewLine);
				}
			}

			VCProjectFileContent.Append(
				"	</ItemGroup>" + ProjectFileGenerator.NewLine);

			VCFiltersFileContent.Append(
				"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator.NewLine +
				ProjectFileGenerator.NewLine +
				"<Project ToolsVersion=\"" + VCProjectFileGenerator.ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator.NewLine);

			// Platform specific PropertyGroups, etc.
			StringBuilder AdditionalPropertyGroups = new StringBuilder();
			if (!IsStubProject)
			{
				foreach (UnrealTargetPlatform Platform in ProjectPlatforms)
				{
					UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
					if (ProjGenerator != null && ProjGenerator.HasVisualStudioSupport(Platform, UnrealTargetConfiguration.Development))
					{
						AdditionalPropertyGroups.Append(ProjGenerator.GetAdditionalVisualStudioPropertyGroups(Platform));
					}
				}

				VCProjectFileContent.Append(AdditionalPropertyGroups);
			}

			// Project globals (project GUID, project type, SCC bindings, etc)
			{
				VCProjectFileContent.Append(
					"	<PropertyGroup Label=\"Globals\">" + ProjectFileGenerator.NewLine +
					"		<ProjectGuid>" + ProjectGUID.ToString("B").ToUpperInvariant() + "</ProjectGuid>" + ProjectFileGenerator.NewLine +
					"		<Keyword>MakeFileProj</Keyword>" + ProjectFileGenerator.NewLine +
					"		<RootNamespace>" + ProjectName + "</RootNamespace>" + ProjectFileGenerator.NewLine +
                    "       <PlatformToolset>" + VCProjectFileGenerator.ProjectFilePlatformToolsetVersionString + "</PlatformToolset>" + ProjectFileGenerator.NewLine +
                    "       <MinimumVisualStudioVersion>" + VCProjectFileGenerator.ProjectFileToolVersionString + "</MinimumVisualStudioVersion>" + ProjectFileGenerator.NewLine +
                    "       <TargetRuntime>Native</TargetRuntime>" + ProjectFileGenerator.NewLine +
                    "	</PropertyGroup>" + ProjectFileGenerator.NewLine);
			}

			// Write each project configuration PreDefaultProps section
			foreach (Tuple<string, UnrealTargetConfiguration> ConfigurationTuple in ProjectConfigurationNameAndConfigurations)
			{
				string ProjectConfigurationName = ConfigurationTuple.Item1;
				UnrealTargetConfiguration TargetConfiguration = ConfigurationTuple.Item2;
				foreach (Tuple<string, UnrealTargetPlatform> PlatformTuple in ProjectPlatformNameAndPlatforms)
				{
					string ProjectPlatformName = PlatformTuple.Item1;
					UnrealTargetPlatform TargetPlatform = PlatformTuple.Item2;
					WritePreDefaultPropsConfiguration(TargetPlatform, TargetConfiguration, ProjectPlatformName, ProjectConfigurationName, VCProjectFileContent);
				}
			}

			VCProjectFileContent.Append(
				"	<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />" + ProjectFileGenerator.NewLine);

			// Write each project configuration PreDefaultProps section
			foreach (Tuple<string, UnrealTargetConfiguration> ConfigurationTuple in ProjectConfigurationNameAndConfigurations)
			{
				string ProjectConfigurationName = ConfigurationTuple.Item1;
				UnrealTargetConfiguration TargetConfiguration = ConfigurationTuple.Item2;
				foreach (Tuple<string, UnrealTargetPlatform> PlatformTuple in ProjectPlatformNameAndPlatforms)
				{
					string ProjectPlatformName = PlatformTuple.Item1;
					UnrealTargetPlatform TargetPlatform = PlatformTuple.Item2;
					WritePostDefaultPropsConfiguration(TargetPlatform, TargetConfiguration, ProjectPlatformName, ProjectConfigurationName, VCProjectFileContent);
				}
			}
			
			VCProjectFileContent.Append(
				"	<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />" + ProjectFileGenerator.NewLine +
				"	<ImportGroup Label=\"ExtensionSettings\" />" + ProjectFileGenerator.NewLine +
				"	<PropertyGroup Label=\"UserMacros\" />" + ProjectFileGenerator.NewLine
				);

			// Write each project configuration
			foreach (ProjectConfigAndTargetCombination Combination in ProjectConfigAndTargetCombinations)
			{
				WriteConfiguration(ProjectName, Combination, VCProjectFileContent, bGenerateUserFileContent ? VCUserFileContent : null);
			}

			// Source folders and files
			{
				List<AliasedFile> LocalAliasedFiles = new List<AliasedFile>(AliasedFiles);

				foreach (SourceFile CurFile in SourceFiles)
				{
					// We want all source file and directory paths in the project files to be relative to the project file's
					// location on the disk.  Convert the path to be relative to the project file directory
					string ProjectRelativeSourceFile = CurFile.Reference.MakeRelativeTo(ProjectFilePath.Directory);

					// By default, files will appear relative to the project file in the solution.  This is kind of the normal Visual
					// Studio way to do things, but because our generated project files are emitted to intermediate folders, if we always
					// did this it would yield really ugly paths int he solution explorer
					string FilterRelativeSourceDirectory;
					if (CurFile.BaseFolder == null)
					{
						FilterRelativeSourceDirectory = ProjectRelativeSourceFile;
					}
					else
					{
						FilterRelativeSourceDirectory = CurFile.Reference.MakeRelativeTo(CurFile.BaseFolder);
					}

					// Manually remove the filename for the filter. We run through this code path a lot, so just do it manually.
					int LastSeparatorIdx = FilterRelativeSourceDirectory.LastIndexOf(Path.DirectorySeparatorChar);
					if (LastSeparatorIdx == -1)
					{
						FilterRelativeSourceDirectory = "";
					}
					else
					{
						FilterRelativeSourceDirectory = FilterRelativeSourceDirectory.Substring(0, LastSeparatorIdx);
					}

					LocalAliasedFiles.Add(new AliasedFile(ProjectRelativeSourceFile, FilterRelativeSourceDirectory));
				}

				VCFiltersFileContent.Append(
					"	<ItemGroup>" + ProjectFileGenerator.NewLine);

				VCProjectFileContent.Append(
					"	<ItemGroup>" + ProjectFileGenerator.NewLine);

				// Add all file directories to the filters file as solution filters
				HashSet<string> FilterDirectories = new HashSet<string>();
				UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(BuildHostPlatform.Current.Platform);
				bool bWritePerFilePCHInfo = false;
				if (BuildConfiguration.bUsePerFileIntellisense && VCProjectFileGenerator.ProjectFileFormat >= VCProjectFileGenerator.VCProjectFileFormat.VisualStudio2015)
				{
					string UpdateRegistryLoc = string.Format(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\DevDiv\vs\Servicing\{0}\devenv", VCProjectFileGenerator.ProjectFileToolVersionString);
					object Result = Microsoft.Win32.Registry.GetValue(UpdateRegistryLoc, "UpdateVersion", null);
					if (Result != null)
					{
						int UpdateVersion = 0;
						if (Int32.TryParse(Result.ToString().Split('.').Last(), out UpdateVersion) && UpdateVersion >= 25420)
						{
							bWritePerFilePCHInfo = true;
						}
					}
				}

				foreach (AliasedFile AliasedFile in LocalAliasedFiles)
				{
					// No need to add the root directory relative to the project (it would just be an empty string!)
					if (!String.IsNullOrWhiteSpace(AliasedFile.ProjectPath))
					{
						FiltersFileIsNeeded = EnsureFilterPathExists(AliasedFile.ProjectPath, VCFiltersFileContent, FilterDirectories);
					}

					string VCFileType = GetVCFileType(AliasedFile.FileSystemPath);
					string PCHFileName = null;
					
					if (bWritePerFilePCHInfo && VCFileType == "ClCompile")
					{
						FileReference TruePath = FileReference.Combine(ProjectFilePath.Directory, AliasedFile.FileSystemPath);
						FileItem SourceFile = FileItem.GetItemByFileReference(TruePath);
						List <DependencyInclude> DirectlyIncludedFilenames = CPPEnvironment.GetUncachedDirectIncludeDependencies(SourceFile, BuildPlatform);
						if (DirectlyIncludedFilenames.Count > 0)
						{
							PCHFileName = DirectlyIncludedFilenames[0].IncludeName;
						}
					}

					if (!string.IsNullOrEmpty(PCHFileName))
					{
						VCProjectFileContent.Append(
							"		<" + VCFileType + " Include=\"" + EscapeFileName(AliasedFile.FileSystemPath) + "\">" + ProjectFileGenerator.NewLine +
							"			<AdditionalOptions>$(AdditionalOptions) /Yu" + PCHFileName + "</AdditionalOptions>" + ProjectFileGenerator.NewLine +
							"		</" + VCFileType + " >" + ProjectFileGenerator.NewLine);
					}
					else
					{
						VCProjectFileContent.Append(
							"		<" + VCFileType + " Include=\"" + EscapeFileName(AliasedFile.FileSystemPath) + "\" />" + ProjectFileGenerator.NewLine);
					}

					if (!String.IsNullOrWhiteSpace(AliasedFile.ProjectPath))
					{
						VCFiltersFileContent.Append(
							"		<" + VCFileType + " Include=\"" + EscapeFileName(AliasedFile.FileSystemPath) + "\">" + ProjectFileGenerator.NewLine +
							"			<Filter>" + Utils.CleanDirectorySeparators(AliasedFile.ProjectPath) + "</Filter>" + ProjectFileGenerator.NewLine +
							"		</" + VCFileType + " >" + ProjectFileGenerator.NewLine);

						FiltersFileIsNeeded = true;
					}
					else
					{
						// No need to specify the root directory relative to the project (it would just be an empty string!)
						VCFiltersFileContent.Append(
							"		<" + VCFileType + " Include=\"" + EscapeFileName(AliasedFile.FileSystemPath) + "\" />" + ProjectFileGenerator.NewLine);
					}
				}

				VCProjectFileContent.Append(
					"	</ItemGroup>" + ProjectFileGenerator.NewLine);

				VCFiltersFileContent.Append(
					"	</ItemGroup>" + ProjectFileGenerator.NewLine);
			}

			// For Installed engine builds, include engine source in the source search paths if it exists. We never build it locally, so the debugger can't find it.
			if (UnrealBuildTool.IsEngineInstalled() && !IsStubProject)
			{
				VCProjectFileContent.Append("	<PropertyGroup>" + ProjectFileGenerator.NewLine);
				VCProjectFileContent.Append("		<SourcePath>");
				foreach (string DirectoryName in Directory.EnumerateDirectories(Path.GetFullPath(Path.Combine(ProjectFileGenerator.EngineRelativePath, "Source")), "*", SearchOption.AllDirectories))
				{
					if (Directory.EnumerateFiles(DirectoryName, "*.cpp").Any())
					{
						VCProjectFileContent.Append(DirectoryName);
						VCProjectFileContent.Append(";");
					}
				}
				VCProjectFileContent.Append("</SourcePath>" + ProjectFileGenerator.NewLine);
				VCProjectFileContent.Append("	</PropertyGroup>" + ProjectFileGenerator.NewLine);
			}

			// Write IntelliSense info
			{
				// @todo projectfiles: Currently we are storing defines/include paths for ALL configurations rather than using ConditionString and storing
				//      this data uniquely for each target configuration.  IntelliSense may behave better if we did that, but it will result in a LOT more
				//      data being stored into the project file, and might make the IDE perform worse when switching configurations!
				VCProjectFileContent.Append(
					"	<PropertyGroup>" + ProjectFileGenerator.NewLine +
					"		<NMakePreprocessorDefinitions>$(NMakePreprocessorDefinitions)" + (VCPreprocessorDefinitions.Length > 0 ? (";" + VCPreprocessorDefinitions) : "") + "</NMakePreprocessorDefinitions>" + ProjectFileGenerator.NewLine +
					"		<NMakeIncludeSearchPath>$(NMakeIncludeSearchPath)" + (VCIncludeSearchPaths.Length > 0 ? (";" + VCIncludeSearchPaths) : "") + "</NMakeIncludeSearchPath>" + ProjectFileGenerator.NewLine +
					"		<NMakeForcedIncludes>$(NMakeForcedIncludes)</NMakeForcedIncludes>" + ProjectFileGenerator.NewLine +
					"		<NMakeAssemblySearchPath>$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>" + ProjectFileGenerator.NewLine +
					"		<NMakeForcedUsingAssemblies>$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>" + ProjectFileGenerator.NewLine +
					"	</PropertyGroup>" + ProjectFileGenerator.NewLine);
			}

			// look for additional import lines for all platforms for non stub projects
			StringBuilder AdditionalImportSettings = new StringBuilder();
			if (!IsStubProject)
			{
				foreach (UnrealTargetPlatform Platform in ProjectPlatforms)
				{
					UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
					if (ProjGenerator != null && ProjGenerator.HasVisualStudioSupport(Platform, UnrealTargetConfiguration.Development))
					{
						AdditionalImportSettings.Append(ProjGenerator.GetAdditionalVisualStudioImportSettings(Platform));
					}
				}
			}

			string OutputManifestString = "";
			if (!IsStubProject)
			{
				foreach (UnrealTargetPlatform Platform in ProjectPlatforms)
				{
					UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true);
					if (ProjGenerator != null && ProjGenerator.HasVisualStudioSupport(Platform, UnrealTargetConfiguration.Development))
					{
						// @todo projectfiles: Serious hacks here because we are trying to emit one-time platform-specific sections that need information
						//    about a target type, but the project file may contain many types of targets!  Some of this logic will need to move into
						//    the per-target configuration writing code.
						TargetRules.TargetType HackTargetType = TargetRules.TargetType.Game;
						FileReference HackTargetFilePath = null;
						foreach (ProjectConfigAndTargetCombination Combination in ProjectConfigAndTargetCombinations)
						{
							if (Combination.Platform == Platform &&
								Combination.ProjectTarget.TargetRules != null &&
								Combination.ProjectTarget.TargetRules.Type == HackTargetType)
							{
								HackTargetFilePath = Combination.ProjectTarget.TargetFilePath;// ProjectConfigAndTargetCombinations[0].ProjectTarget.TargetFilePath;
								break;
							}
						}

						if (HackTargetFilePath != null)
						{
							OutputManifestString += ProjGenerator.GetVisualStudioOutputManifestSection(Platform, HackTargetType, HackTargetFilePath, ProjectFilePath);
						}
					}
				}
			}

			VCProjectFileContent.Append(
					OutputManifestString +	// output manifest must come before the Cpp.targets file.
					"	<ItemDefinitionGroup>" + ProjectFileGenerator.NewLine +
					"	</ItemDefinitionGroup>" + ProjectFileGenerator.NewLine +
					"	<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />" + ProjectFileGenerator.NewLine +
					AdditionalImportSettings.ToString() +
					"	<ImportGroup Label=\"ExtensionTargets\">" + ProjectFileGenerator.NewLine +
					"	</ImportGroup>" + ProjectFileGenerator.NewLine +
					"</Project>" + ProjectFileGenerator.NewLine);

			VCFiltersFileContent.Append(
				"</Project>" + ProjectFileGenerator.NewLine);

			if (bGenerateUserFileContent)
			{
				VCUserFileContent.Append(
					"</Project>" + ProjectFileGenerator.NewLine
					);
			}

			// Save the project file
			if (bSuccess)
			{
				bSuccess = ProjectFileGenerator.WriteFileIfChanged(ProjectFilePath.FullName, VCProjectFileContent.ToString());
			}


			// Save the filters file
			if (bSuccess)
			{
				// Create a path to the project file's filters file
				string VCFiltersFilePath = ProjectFilePath.FullName + ".filters";
				if (FiltersFileIsNeeded)
				{
					bSuccess = ProjectFileGenerator.WriteFileIfChanged(VCFiltersFilePath, VCFiltersFileContent.ToString());
				}
				else
				{
					Log.TraceVerbose("Deleting Visual C++ filters file which is no longer needed: " + VCFiltersFilePath);

					// Delete the filters file, if one exists.  We no longer need it
					try
					{
						File.Delete(VCFiltersFilePath);
					}
					catch (Exception)
					{
						Log.TraceInformation("Error deleting filters file (file may not be writable): " + VCFiltersFilePath);
					}
				}
			}

			// Save the user file, if required
			if (VCUserFileContent.Length > 0)
			{
				// Create a path to the project file's user file
				string VCUserFilePath = ProjectFilePath.FullName + ".user";
				// Never overwrite the existing user path as it will cause them to lose their settings
				if (File.Exists(VCUserFilePath) == false)
				{
					bSuccess = ProjectFileGenerator.WriteFileIfChanged(VCUserFilePath, VCUserFileContent.ToString());
				}
			}

			return bSuccess;
		}