2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Xml ;
using System.Xml.XPath ;
using System.Xml.Linq ;
using System.Linq ;
using System.Text ;
using System.Diagnostics ;
2015-08-27 12:46:47 -04:00
using System.Security ;
2014-03-14 14:13:41 -04:00
namespace UnrealBuildTool
{
public abstract class MSBuildProjectFile : ProjectFile
{
/// The project file version string
static public readonly string VCProjectFileVersionString = "10.0.30319.1" ;
/// The build configuration name to use for stub project configurations. These are projects whose purpose
/// is to make it easier for developers to find source files and to provide IntelliSense data for the module
/// to Visual Studio
static public readonly string StubProjectConfigurationName = "BuiltWithUnrealBuildTool" ;
/// The name of the Visual C++ platform to use for stub project configurations
/// NOTE: We always use Win32 for the stub project's platform, since that is guaranteed to be supported by Visual Studio
static public readonly string StubProjectPlatformName = "Win32" ;
/// override project configuration name for platforms visual studio doesn't natively support
public string ProjectConfigurationNameOverride = "" ;
/// override project platform for platforms visual studio doesn't natively support
public string ProjectPlatformNameOverride = "" ;
/// <summary>
/// The Guid representing the project type e.g. C# or C++
/// </summary>
public virtual string ProjectTypeGUID
{
2015-09-24 12:37:21 -04:00
get { throw new BuildException ( "Unrecognized type of project file for Visual Studio solution" ) ; }
2014-03-14 14:13:41 -04:00
}
/// <summary>
/// Constructs a new project file object
/// </summary>
/// <param name="InitFilePath">The path to the project file on disk</param>
2015-09-03 08:47:24 -04:00
public MSBuildProjectFile ( FileReference InitFilePath )
2014-03-14 14:13:41 -04:00
: base ( InitFilePath )
{
// Each project gets its own GUID. This is stored in the project file and referenced in the solution file.
// First, check to see if we have an existing file on disk. If we do, then we'll try to preserve the
// GUID by loading it from the existing file.
2015-09-03 08:47:24 -04:00
if ( ProjectFilePath . Exists ( ) )
2014-03-14 14:13:41 -04:00
{
try
{
LoadGUIDFromExistingProject ( ) ;
}
catch ( Exception )
{
// Failed to find GUID, so just create a new one
ProjectGUID = Guid . NewGuid ( ) ;
}
}
if ( ProjectGUID = = Guid . Empty )
{
// Generate a brand new GUID
ProjectGUID = Guid . NewGuid ( ) ;
}
}
/// <summary>
/// Attempts to load the project's GUID from an existing project file on disk
/// </summary>
public override void LoadGUIDFromExistingProject ( )
{
// Only load GUIDs if we're in project generation mode. Regular builds don't need GUIDs for anything.
2015-09-24 12:37:21 -04:00
if ( ProjectFileGenerator . bGenerateProjectFiles )
2014-03-14 14:13:41 -04:00
{
var Doc = new XmlDocument ( ) ;
2015-09-24 12:37:21 -04:00
Doc . Load ( ProjectFilePath . FullName ) ;
2014-03-14 14:13:41 -04:00
// @todo projectfiles: Ideally we could do a better job about preserving GUIDs when only minor changes are made
// to the project (such as adding a single new file.) It would make diffing changes much easier!
// @todo projectfiles: Can we "seed" a GUID based off the project path and generate consistent GUIDs each time?
2015-09-24 12:37:21 -04:00
var Elements = Doc . GetElementsByTagName ( "ProjectGuid" ) ;
foreach ( XmlElement Element in Elements )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
ProjectGUID = Guid . ParseExact ( Element . InnerText . Trim ( "{}" . ToCharArray ( ) ) , "D" ) ;
2014-03-14 14:13:41 -04:00
}
}
}
/// <summary>
/// Given a target platform and configuration, generates a platform and configuration name string to use in Visual Studio projects.
/// Unlike with solution configurations, Visual Studio project configurations only support certain types of platforms, so we'll
/// generate a configuration name that has the platform "built in", and use a default platform type
/// </summary>
/// <param name="Platform">Actual platform</param>
/// <param name="Configuration">Actual configuration</param>
/// <param name="TargetConfigurationName">The configuration name from the target rules, or null if we don't have one</param>
/// <param name="ProjectPlatformName">Name of platform string to use for Visual Studio project</param>
/// <param name="ProjectConfigurationName">Name of configuration string to use for Visual Studio project</param>
public void MakeProjectPlatformAndConfigurationNames ( UnrealTargetPlatform Platform , UnrealTargetConfiguration Configuration , string TargetConfigurationName , out string ProjectPlatformName , out string ProjectConfigurationName )
{
if ( IsStubProject )
{
if ( Platform ! = UnrealTargetPlatform . Unknown | | Configuration ! = UnrealTargetConfiguration . Unknown )
{
throw new BuildException ( "Stub project was expecting platform and configuration type to be set to Unknown" ) ;
}
ProjectPlatformName = StubProjectPlatformName ;
ProjectConfigurationName = StubProjectConfigurationName ;
}
else
{
// If this is a C# project, then the project platform name must always be "Any CPU"
if ( this is VCSharpProjectFile )
{
ProjectConfigurationName = Configuration . ToString ( ) ;
ProjectPlatformName = VCProjectFileGenerator . DotNetPlatformName ;
}
else
{
var PlatformProjectGenerator = UEPlatformProjectGenerator . GetPlatformProjectGenerator ( Platform , bInAllowFailure : true ) ;
// Check to see if this platform is supported directly by Visual Studio projects.
bool HasActualVSPlatform = ( PlatformProjectGenerator ! = null ) ? PlatformProjectGenerator . HasVisualStudioSupport ( Platform , Configuration ) : false ;
if ( HasActualVSPlatform )
{
// Great! Visual Studio supports this platform natively, so we don't need to make up
// a fake project configuration name.
// Allow the platform to specify the name used in VisualStudio.
// Note that the actual name of the platform on the Visual Studio side may be different than what
// UnrealBuildTool calls it (e.g. "Win64" -> "x64".) GetVisualStudioPlatformName() will figure this out.
ProjectConfigurationName = Configuration . ToString ( ) ;
ProjectPlatformName = PlatformProjectGenerator . GetVisualStudioPlatformName ( Platform , Configuration ) ;
}
else
{
// Visual Studio doesn't natively support this platform, so we fake it by mapping it to
// a project configuration that has the platform name in that configuration as a suffix,
// and then using "Win32" as the actual VS platform name
ProjectConfigurationName = ProjectConfigurationNameOverride = = "" ? Platform . ToString ( ) + "_" + Configuration . ToString ( ) : ProjectConfigurationNameOverride ;
ProjectPlatformName = ProjectPlatformNameOverride = = "" ? VCProjectFileGenerator . DefaultPlatformName : ProjectPlatformNameOverride ;
}
2015-09-24 12:37:21 -04:00
if ( ! String . IsNullOrEmpty ( TargetConfigurationName ) )
2014-03-14 14:13:41 -04:00
{
ProjectConfigurationName + = "_" + TargetConfigurationName ;
}
}
}
}
/// <summary>
/// Checks to see if the specified solution platform and configuration is able to map to this project
/// </summary>
/// <param name="ProjectTarget">The target that we're checking for a valid platform/config combination</param>
/// <param name="Platform">Platform</param>
/// <param name="Configuration">Configuration</param>
/// <returns>True if this is a valid combination for this project, otherwise false</returns>
public static bool IsValidProjectPlatformAndConfiguration ( ProjectTarget ProjectTarget , UnrealTargetPlatform Platform , UnrealTargetConfiguration Configuration )
{
var PlatformProjectGenerator = UEPlatformProjectGenerator . GetPlatformProjectGenerator ( Platform , true ) ;
if ( PlatformProjectGenerator = = null )
{
return false ;
}
2014-05-21 06:09:37 -04:00
var BuildPlatform = UEBuildPlatform . GetBuildPlatform ( Platform , true ) ;
2014-03-14 14:13:41 -04:00
if ( BuildPlatform = = null )
{
return false ;
}
2014-05-21 06:09:37 -04:00
if ( BuildPlatform . HasRequiredSDKsInstalled ( ) ! = SDKStatus . Valid )
2014-03-14 14:13:41 -04:00
{
return false ;
}
var SupportedConfigurations = new List < UnrealTargetConfiguration > ( ) ;
var SupportedPlatforms = new List < UnrealTargetPlatform > ( ) ;
2015-05-26 16:04:12 -04:00
if ( ! ProjectFileGenerator . bCreateDummyConfigsForUnsupportedPlatforms )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ProjectTarget . TargetRules ! = null )
2014-03-14 14:13:41 -04:00
{
2015-03-13 10:52:15 -04:00
ProjectTarget . TargetRules . GetSupportedPlatforms ( ref SupportedPlatforms ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
2015-03-13 10:52:15 -04:00
UnrealBuildTool . GetAllPlatforms ( ref SupportedPlatforms ) ;
2014-03-14 14:13:41 -04:00
}
bool bIncludeTestAndShippingConfigs = ProjectFileGenerator . bIncludeTestAndShippingConfigs | | ProjectFileGenerator . bGeneratingRocketProjectFiles ;
2015-09-24 12:37:21 -04:00
if ( ProjectTarget . TargetRules ! = null )
2014-03-14 14:13:41 -04:00
{
// Rocket projects always get shipping configs
2015-09-24 12:37:21 -04:00
ProjectTarget . TargetRules . GetSupportedConfigurations ( ref SupportedConfigurations , bIncludeTestAndShippingConfigs : bIncludeTestAndShippingConfigs ) ;
2014-03-14 14:13:41 -04:00
}
// Add all of the extra platforms/configurations for this target
{
2015-09-24 12:37:21 -04:00
foreach ( var ExtraPlatform in ProjectTarget . ExtraSupportedPlatforms )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ! SupportedPlatforms . Contains ( ExtraPlatform ) )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
SupportedPlatforms . Add ( ExtraPlatform ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-09-24 12:37:21 -04:00
foreach ( var ExtraConfig in ProjectTarget . ExtraSupportedConfigurations )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( bIncludeTestAndShippingConfigs | | ( ExtraConfig ! = UnrealTargetConfiguration . Shipping & & ExtraConfig ! = UnrealTargetConfiguration . Test ) )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ! SupportedConfigurations . Contains ( ExtraConfig ) )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
SupportedConfigurations . Add ( ExtraConfig ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
// Only build for supported platforms
if ( SupportedPlatforms . Contains ( Platform ) = = false )
{
return false ;
}
// Only build for supported configurations
if ( SupportedConfigurations . Contains ( Configuration ) = = false )
{
return false ;
}
return true ;
}
2015-08-27 12:46:47 -04:00
/// <summary>
/// Escapes characters in a filename so they can be stored in an XML attribute
/// </summary>
/// <param name="FileName">The filename to escape</param>
/// <returns>The escaped filename</returns>
public static string EscapeFileName ( string FileName )
{
return SecurityElement . Escape ( FileName ) ;
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// GUID for this Visual C++ project file
/// </summary>
public Guid ProjectGUID
{
get ;
protected set ;
}
}
2015-09-24 12:37:21 -04:00
2014-03-14 14:13:41 -04:00
public class VCProjectFile : MSBuildProjectFile
{
2015-09-17 09:15:44 -04:00
FileReference OnlyGameProject ;
2014-03-14 14:13:41 -04:00
// This is the GUID that Visual Studio uses to identify a C++ project file in the solution
public override string ProjectTypeGUID
{
get { return "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" ; }
}
/// <summary>
/// Constructs a new project file object
/// </summary>
/// <param name="InitFilePath">The path to the project file on disk</param>
2015-09-17 09:15:44 -04:00
public VCProjectFile ( FileReference InFilePath , FileReference InOnlyGameProject )
2015-09-24 12:37:21 -04:00
: base ( InFilePath )
2014-03-14 14:13:41 -04:00
{
2015-09-17 09:15:44 -04:00
OnlyGameProject = InOnlyGameProject ;
2014-03-14 14:13:41 -04:00
}
2015-01-30 11:52:22 -05:00
class ProjectConfigAndTargetCombination
2014-03-14 14:13:41 -04:00
{
public UnrealTargetPlatform Platform ;
public UnrealTargetConfiguration Configuration ;
2015-01-30 11:52:22 -05:00
public string ProjectPlatformName ;
public string ProjectConfigurationName ;
2014-03-14 14:13:41 -04:00
public ProjectTarget ProjectTarget ;
2015-01-30 11:52:22 -05:00
public ProjectConfigAndTargetCombination ( UnrealTargetPlatform InPlatform , UnrealTargetConfiguration InConfiguration , string InProjectPlatformName , string InProjectConfigurationName , ProjectTarget InProjectTarget )
{
Platform = InPlatform ;
Configuration = InConfiguration ;
ProjectPlatformName = InProjectPlatformName ;
ProjectConfigurationName = InProjectConfigurationName ;
ProjectTarget = InProjectTarget ;
}
public string ProjectConfigurationAndPlatformName
{
2015-09-24 12:37:21 -04:00
get { return ( ProjectPlatformName = = null ) ? null : ( ProjectConfigurationName + "|" + ProjectPlatformName ) ; }
2015-01-30 11:52:22 -05:00
}
2014-03-14 14:13:41 -04:00
public override string ToString ( )
{
return String . Format ( "{0} {1} {2}" , ProjectTarget , Platform , Configuration ) ;
}
}
/// Implements Project interface
public override bool WriteProjectFile ( List < UnrealTargetPlatform > InPlatforms , List < UnrealTargetConfiguration > InConfigurations )
{
2015-09-03 08:47:24 -04:00
string ProjectName = ProjectFilePath . GetFileNameWithoutExtension ( ) ;
2014-03-14 14:13:41 -04:00
bool bSuccess = true ;
// Build up the new include search path string
var VCIncludeSearchPaths = new StringBuilder ( ) ;
2015-05-05 15:32:10 -04:00
{
foreach ( var CurPath in IntelliSenseIncludeSearchPaths )
2014-04-02 18:09:23 -04:00
{
2015-05-05 15:32:10 -04:00
VCIncludeSearchPaths . Append ( CurPath + ";" ) ;
2014-04-02 18:09:23 -04:00
}
2015-05-05 15:32:10 -04:00
foreach ( var CurPath in IntelliSenseSystemIncludeSearchPaths )
2014-03-14 14:13:41 -04:00
{
2015-05-05 15:32:10 -04:00
VCIncludeSearchPaths . Append ( CurPath + ";" ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-12 12:00:23 -04:00
if ( InPlatforms . Contains ( UnrealTargetPlatform . UWP ) )
2015-05-05 15:32:10 -04:00
{
2015-05-12 12:00:23 -04:00
VCIncludeSearchPaths . Append ( UWPToolChain . GetVCIncludePaths ( CPPTargetPlatform . UWP ) + ";" ) ;
2015-05-05 15:32:10 -04:00
}
else if ( InPlatforms . Contains ( UnrealTargetPlatform . Win64 ) )
2014-03-14 14:13:41 -04:00
{
VCIncludeSearchPaths . Append ( VCToolChain . GetVCIncludePaths ( CPPTargetPlatform . Win64 ) + ";" ) ;
}
2015-05-05 15:32:10 -04:00
else if ( InPlatforms . Contains ( UnrealTargetPlatform . Win32 ) )
2014-03-14 14:13:41 -04:00
{
VCIncludeSearchPaths . Append ( VCToolChain . GetVCIncludePaths ( CPPTargetPlatform . Win32 ) + ";" ) ;
}
}
var VCPreprocessorDefinitions = new StringBuilder ( ) ;
2015-09-24 12:37:21 -04:00
foreach ( var CurDef in IntelliSensePreprocessorDefinitions )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( VCPreprocessorDefinitions . Length > 0 )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
VCPreprocessorDefinitions . Append ( ';' ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-24 12:37:21 -04:00
VCPreprocessorDefinitions . Append ( CurDef ) ;
2014-03-14 14:13:41 -04:00
}
// 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 +
2015-05-05 15:32:10 -04:00
"<Project DefaultTargets=\"Build\" ToolsVersion=\"" + VCProjectFileGenerator . ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
2014-12-11 15:44:40 -05:00
bool bGenerateUserFileContent = UEPlatformProjectGenerator . PlatformRequiresVSUserFileGeneration ( InPlatforms , InConfigurations ) ;
2014-03-14 14:13:41 -04:00
if ( bGenerateUserFileContent )
{
VCUserFileContent . Append (
2015-09-24 12:37:21 -04:00
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator . NewLine +
2014-03-14 14:13:41 -04:00
ProjectFileGenerator . NewLine +
2015-05-05 15:32:10 -04:00
"<Project ToolsVersion=\"" + VCProjectFileGenerator . ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator . NewLine
2014-03-14 14:13:41 -04:00
) ;
}
// 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.
2015-09-24 12:37:21 -04:00
var ProjectConfigAndTargetCombinations = new List < ProjectConfigAndTargetCombination > ( ) ;
2014-03-14 14:13:41 -04:00
// If this is a "stub" project, then only add a single configuration to the project
2015-09-24 12:37:21 -04:00
if ( IsStubProject )
2014-03-14 14:13:41 -04:00
{
2015-01-30 11:52:22 -05:00
ProjectConfigAndTargetCombination StubCombination = new ProjectConfigAndTargetCombination ( UnrealTargetPlatform . Unknown , UnrealTargetConfiguration . Unknown , StubProjectPlatformName , StubProjectConfigurationName , null ) ;
ProjectConfigAndTargetCombinations . Add ( StubCombination ) ;
2014-03-14 14:13:41 -04:00
}
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 ;
}
2014-05-21 06:09:37 -04:00
var BuildPlatform = UEBuildPlatform . GetBuildPlatform ( Platform , true ) ;
if ( ( BuildPlatform ! = null ) & & ( BuildPlatform . HasRequiredSDKsInstalled ( ) = = SDKStatus . Valid ) )
2014-03-14 14:13:41 -04:00
{
// Now go through all of the target types for this project
2015-09-24 12:37:21 -04:00
if ( ProjectTargets . Count = = 0 )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
throw new BuildException ( "Expecting at least one ProjectTarget to be associated with project '{0}' in the TargetProjects list " , ProjectFilePath ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-24 12:37:21 -04:00
foreach ( var ProjectTarget in ProjectTargets )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( IsValidProjectPlatformAndConfiguration ( ProjectTarget , Platform , Configuration ) )
2015-01-30 11:52:22 -05:00
{
string ProjectPlatformName , ProjectConfigurationName ;
MakeProjectPlatformAndConfigurationNames ( Platform , Configuration , ProjectTarget . TargetRules . ConfigurationName , out ProjectPlatformName , out ProjectConfigurationName ) ;
ProjectConfigAndTargetCombination Combination = new ProjectConfigAndTargetCombination ( Platform , Configuration , ProjectPlatformName , ProjectConfigurationName , ProjectTarget ) ;
2015-09-24 12:37:21 -04:00
ProjectConfigAndTargetCombinations . Add ( Combination ) ;
2015-01-30 11:52:22 -05:00
}
2014-03-14 14:13:41 -04:00
}
}
}
}
}
VCProjectFileContent . Append (
" <ItemGroup Label=\"ProjectConfigurations\">" + ProjectFileGenerator . NewLine ) ;
// Make a list of the platforms and configs as project-format names
var ProjectPlatforms = new List < UnrealTargetPlatform > ( ) ;
2015-05-06 15:03:25 -04:00
var ProjectPlatformNameAndPlatforms = new List < Tuple < string , UnrealTargetPlatform > > ( ) ; // ProjectPlatformName, Platform
var ProjectConfigurationNameAndConfigurations = new List < Tuple < string , UnrealTargetConfiguration > > ( ) ; // ProjectConfigurationName, Configuration
2015-09-24 12:37:21 -04:00
foreach ( var Combination in ProjectConfigAndTargetCombinations )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ! ProjectPlatforms . Contains ( Combination . Platform ) )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
ProjectPlatforms . Add ( Combination . Platform ) ;
2015-01-30 11:52:22 -05:00
}
2015-09-24 12:37:21 -04:00
if ( ! ProjectPlatformNameAndPlatforms . Any ( ProjectPlatformNameAndPlatformTuple = > ProjectPlatformNameAndPlatformTuple . Item1 = = Combination . ProjectPlatformName ) )
2015-01-30 11:52:22 -05:00
{
2015-09-24 12:37:21 -04:00
ProjectPlatformNameAndPlatforms . Add ( Tuple . Create ( Combination . ProjectPlatformName , Combination . Platform ) ) ;
2015-01-30 11:52:22 -05:00
}
2015-09-24 12:37:21 -04:00
if ( ! ProjectConfigurationNameAndConfigurations . Any ( ProjectConfigurationNameAndConfigurationTuple = > ProjectConfigurationNameAndConfigurationTuple . Item1 = = Combination . ProjectConfigurationName ) )
2015-01-30 11:52:22 -05:00
{
2015-09-24 12:37:21 -04:00
ProjectConfigurationNameAndConfigurations . Add ( Tuple . Create ( Combination . ProjectConfigurationName , Combination . Configuration ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-24 12:37:21 -04:00
}
2014-03-14 14:13:41 -04:00
// Output ALL the project's config-platform permutations (project files MUST do this)
2015-09-24 12:37:21 -04:00
foreach ( var ConfigurationTuple in ProjectConfigurationNameAndConfigurations )
2014-03-14 14:13:41 -04:00
{
2015-05-06 15:03:25 -04:00
var ProjectConfigurationName = ConfigurationTuple . Item1 ;
2015-09-24 12:37:21 -04:00
foreach ( var PlatformTuple in ProjectPlatformNameAndPlatforms )
2014-03-14 14:13:41 -04:00
{
2015-05-06 15:03:25 -04:00
var ProjectPlatformName = PlatformTuple . Item1 ;
2015-09-24 12:37:21 -04:00
VCProjectFileContent . Append (
2015-05-06 15:03:25 -04:00
" <ProjectConfiguration Include=\"" + ProjectConfigurationName + "|" + ProjectPlatformName + "\">" + ProjectFileGenerator . NewLine +
" <Configuration>" + ProjectConfigurationName + "</Configuration>" + ProjectFileGenerator . NewLine +
2014-03-14 14:13:41 -04:00
" <Platform>" + ProjectPlatformName + "</Platform>" + ProjectFileGenerator . NewLine +
" </ProjectConfiguration>" + ProjectFileGenerator . NewLine ) ;
2015-09-24 12:37:21 -04:00
}
2014-03-14 14:13:41 -04:00
}
VCProjectFileContent . Append (
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
VCFiltersFileContent . Append (
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator . NewLine +
ProjectFileGenerator . NewLine +
2015-05-06 11:53:12 -04:00
"<Project ToolsVersion=\"" + VCProjectFileGenerator . ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
// 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 ) ) ;
}
}
2015-09-24 12:37:21 -04:00
VCProjectFileContent . Append ( AdditionalPropertyGroups ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-22 19:46:46 -04:00
// 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 ) ;
}
VCProjectFileContent . Append (
" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />" + 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.props\" />" + ProjectFileGenerator . NewLine +
" <ImportGroup Label=\"ExtensionSettings\" />" + ProjectFileGenerator . NewLine +
" <PropertyGroup Label=\"UserMacros\" />" + ProjectFileGenerator . NewLine
) ;
// Write each project configuration
2015-09-24 12:37:21 -04:00
foreach ( var Combination in ProjectConfigAndTargetCombinations )
2015-06-22 19:46:46 -04:00
{
2015-09-24 12:37:21 -04:00
WriteConfiguration ( ProjectName , Combination , VCProjectFileContent , bGenerateUserFileContent ? VCUserFileContent : null ) ;
2015-06-22 19:46:46 -04:00
}
2014-03-14 14:13:41 -04:00
// Source folders and files
{
2014-04-24 04:43:16 -04:00
var LocalAliasedFiles = new List < AliasedFile > ( AliasedFiles ) ;
2014-03-14 14:13:41 -04:00
2015-06-22 19:46:46 -04:00
foreach ( var CurFile in SourceFiles )
2014-03-14 14:13:41 -04:00
{
// 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
2015-09-03 08:47:24 -04:00
var ProjectRelativeSourceFile = CurFile . Reference . MakeRelativeTo ( ProjectFilePath . Directory ) ;
2014-03-14 14:13:41 -04:00
// 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
2015-09-03 11:41:30 -04:00
string FilterRelativeSourceDirectory ;
2015-09-24 12:37:21 -04:00
if ( CurFile . BaseFolder = = null )
2014-03-14 14:13:41 -04:00
{
2015-09-03 11:41:30 -04:00
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 ) ;
2015-09-24 12:37:21 -04:00
if ( LastSeparatorIdx = = - 1 )
2015-09-03 11:41:30 -04:00
{
FilterRelativeSourceDirectory = "" ;
}
else
{
FilterRelativeSourceDirectory = FilterRelativeSourceDirectory . Substring ( 0 , LastSeparatorIdx ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-24 04:43:16 -04:00
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 )
{
2014-03-14 14:13:41 -04:00
// No need to add the root directory relative to the project (it would just be an empty string!)
2014-04-24 04:43:16 -04:00
if ( ! String . IsNullOrWhiteSpace ( AliasedFile . ProjectPath ) )
2014-03-14 14:13:41 -04:00
{
2014-04-24 04:43:16 -04:00
FiltersFileIsNeeded = EnsureFilterPathExists ( AliasedFile . ProjectPath , VCFiltersFileContent , FilterDirectories ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-24 04:43:16 -04:00
var VCFileType = GetVCFileType ( AliasedFile . FileSystemPath ) ;
2014-03-14 14:13:41 -04:00
VCProjectFileContent . Append (
2015-08-27 12:46:47 -04:00
" <" + VCFileType + " Include=\"" + EscapeFileName ( AliasedFile . FileSystemPath ) + "\" />" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
2014-04-24 04:43:16 -04:00
if ( ! String . IsNullOrWhiteSpace ( AliasedFile . ProjectPath ) )
2014-03-14 14:13:41 -04:00
{
VCFiltersFileContent . Append (
2015-08-27 12:46:47 -04:00
" <" + VCFileType + " Include=\"" + EscapeFileName ( AliasedFile . FileSystemPath ) + "\">" + ProjectFileGenerator . NewLine +
2014-04-24 04:43:16 -04:00
" <Filter>" + Utils . CleanDirectorySeparators ( AliasedFile . ProjectPath ) + "</Filter>" + ProjectFileGenerator . NewLine +
" </" + VCFileType + " >" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
FiltersFileIsNeeded = true ;
}
else
{
// No need to specify the root directory relative to the project (it would just be an empty string!)
VCFiltersFileContent . Append (
2015-08-27 12:46:47 -04:00
" <" + VCFileType + " Include=\"" + EscapeFileName ( AliasedFile . FileSystemPath ) + "\" />" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
}
VCProjectFileContent . Append (
2015-06-22 19:46:46 -04:00
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
VCFiltersFileContent . Append (
2015-06-22 19:46:46 -04:00
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-05 09:13:03 -05:00
// For Rocket, include engine source in the source search paths. We never build it locally, so the debugger can't find it.
2015-09-24 12:37:21 -04:00
if ( UnrealBuildTool . RunningRocket ( ) & & ! IsStubProject )
2015-02-05 09:13:03 -05:00
{
VCProjectFileContent . Append ( " <PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
VCProjectFileContent . Append ( " <SourcePath>" ) ;
2015-09-24 12:37:21 -04:00
foreach ( string DirectoryName in Directory . EnumerateDirectories ( Path . GetFullPath ( Path . Combine ( ProjectFileGenerator . EngineRelativePath , "Source" ) ) , "*" , SearchOption . AllDirectories ) )
2015-02-05 09:13:03 -05:00
{
2015-09-24 12:37:21 -04:00
if ( Directory . EnumerateFiles ( DirectoryName , "*.cpp" ) . Any ( ) )
2015-02-05 09:13:03 -05:00
{
VCProjectFileContent . Append ( DirectoryName ) ;
VCProjectFileContent . Append ( ";" ) ;
}
}
VCProjectFileContent . Append ( "</SourcePath>" + ProjectFileGenerator . NewLine ) ;
VCProjectFileContent . Append ( " </PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
}
2014-03-14 14:13:41 -04:00
// 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 +
2015-09-24 12:37:21 -04:00
" <NMakePreprocessorDefinitions>$(NMakePreprocessorDefinitions)" + ( VCPreprocessorDefinitions . Length > 0 ? ( ";" + VCPreprocessorDefinitions ) : "" ) + "</NMakePreprocessorDefinitions>" + ProjectFileGenerator . NewLine +
" <NMakeIncludeSearchPath>$(NMakeIncludeSearchPath)" + ( VCIncludeSearchPaths . Length > 0 ? ( ";" + VCIncludeSearchPaths ) : "" ) + "</NMakeIncludeSearchPath>" + ProjectFileGenerator . NewLine +
2014-03-14 14:13:41 -04:00
" <NMakeForcedIncludes>$(NMakeForcedIncludes)</NMakeForcedIncludes>" + ProjectFileGenerator . NewLine +
" <NMakeAssemblySearchPath>$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>" + ProjectFileGenerator . NewLine +
" <NMakeForcedUsingAssemblies>$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>" + ProjectFileGenerator . NewLine +
2015-09-24 12:37:21 -04:00
" </PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
// 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 ;
2015-09-03 08:47:24 -04:00
FileReference HackTargetFilePath = null ;
2015-09-24 12:37:21 -04:00
foreach ( var Combination in ProjectConfigAndTargetCombinations )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
if ( Combination . Platform = = Platform & &
Combination . ProjectTarget . TargetRules ! = null & &
Combination . ProjectTarget . TargetRules . Type = = HackTargetType )
2014-03-14 14:13:41 -04:00
{
2015-01-30 11:52:22 -05:00
HackTargetFilePath = Combination . ProjectTarget . TargetFilePath ; // ProjectConfigAndTargetCombinations[0].ProjectTarget.TargetFilePath;
2015-09-24 12:37:21 -04:00
break ;
2014-03-14 14:13:41 -04:00
}
}
2015-09-24 12:37:21 -04:00
if ( HackTargetFilePath ! = null )
2014-03-14 14:13:41 -04:00
{
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 +
2015-09-24 12:37:21 -04:00
"</Project>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
VCFiltersFileContent . Append (
2015-09-24 12:37:21 -04:00
"</Project>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
if ( bGenerateUserFileContent )
{
VCUserFileContent . Append (
"</Project>" + ProjectFileGenerator . NewLine
) ;
}
// Save the project file
2015-09-24 12:37:21 -04:00
if ( bSuccess )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
bSuccess = ProjectFileGenerator . WriteFileIfChanged ( ProjectFilePath . FullName , VCProjectFileContent . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
// Save the filters file
2015-09-24 12:37:21 -04:00
if ( bSuccess )
2014-03-14 14:13:41 -04:00
{
// Create a path to the project file's filters file
2015-09-03 08:47:24 -04:00
var VCFiltersFilePath = ProjectFilePath . FullName + ".filters" ;
2015-09-24 12:37:21 -04:00
if ( FiltersFileIsNeeded )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
bSuccess = ProjectFileGenerator . WriteFileIfChanged ( VCFiltersFilePath , VCFiltersFileContent . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-09-24 12:37:21 -04:00
Log . TraceVerbose ( "Deleting Visual C++ filters file which is no longer needed: " + VCFiltersFilePath ) ;
2014-03-14 14:13:41 -04:00
// Delete the filters file, if one exists. We no longer need it
try
{
2015-09-24 12:37:21 -04:00
File . Delete ( VCFiltersFilePath ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-24 12:37:21 -04:00
catch ( Exception )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
Log . TraceInformation ( "Error deleting filters file (file may not be writable): " + VCFiltersFilePath ) ;
2014-03-14 14:13:41 -04:00
}
}
}
// Save the user file, if required
if ( VCUserFileContent . Length > 0 )
{
// Create a path to the project file's user file
2015-09-03 08:47:24 -04:00
var VCUserFilePath = ProjectFilePath . FullName + ".user" ;
2014-03-14 14:13:41 -04:00
// 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 ;
}
2014-04-24 04:43:16 -04:00
private static bool EnsureFilterPathExists ( string FilterRelativeSourceDirectory , StringBuilder VCFiltersFileContent , HashSet < string > FilterDirectories )
{
// We only want each directory to appear once in the filters file
2015-09-24 12:37:21 -04:00
var PathRemaining = Utils . CleanDirectorySeparators ( FilterRelativeSourceDirectory ) ;
2014-04-24 04:43:16 -04:00
var FiltersFileIsNeeded = false ;
2015-09-24 12:37:21 -04:00
if ( ! FilterDirectories . Contains ( PathRemaining ) )
2014-04-24 04:43:16 -04:00
{
// Make sure all subdirectories leading up to this directory each have their own filter, too!
var AllDirectoriesInPath = new List < string > ( ) ;
var PathSoFar = "" ;
2015-09-24 12:37:21 -04:00
for ( ; ; )
2014-04-24 04:43:16 -04:00
{
2015-09-24 12:37:21 -04:00
if ( PathRemaining . Length > 0 )
2014-04-24 04:43:16 -04:00
{
2015-09-24 12:37:21 -04:00
var SlashIndex = PathRemaining . IndexOf ( Path . DirectorySeparatorChar ) ;
2014-04-24 04:43:16 -04:00
string SplitDirectory ;
2015-09-24 12:37:21 -04:00
if ( SlashIndex ! = - 1 )
2014-04-24 04:43:16 -04:00
{
2015-09-24 12:37:21 -04:00
SplitDirectory = PathRemaining . Substring ( 0 , SlashIndex ) ;
PathRemaining = PathRemaining . Substring ( SplitDirectory . Length + 1 ) ;
2014-04-24 04:43:16 -04:00
}
else
{
SplitDirectory = PathRemaining ;
PathRemaining = "" ;
}
2015-09-24 12:37:21 -04:00
if ( ! String . IsNullOrEmpty ( PathSoFar ) )
2014-04-24 04:43:16 -04:00
{
PathSoFar + = Path . DirectorySeparatorChar ;
}
PathSoFar + = SplitDirectory ;
2015-09-24 12:37:21 -04:00
AllDirectoriesInPath . Add ( PathSoFar ) ;
2014-04-24 04:43:16 -04:00
}
else
{
break ;
}
}
2015-09-24 12:37:21 -04:00
foreach ( var LeadingDirectory in AllDirectoriesInPath )
2014-04-24 04:43:16 -04:00
{
2015-09-24 12:37:21 -04:00
if ( ! FilterDirectories . Contains ( LeadingDirectory ) )
2014-04-24 04:43:16 -04:00
{
2015-09-24 12:37:21 -04:00
FilterDirectories . Add ( LeadingDirectory ) ;
2014-04-24 04:43:16 -04:00
// Generate a unique GUID for this folder
// NOTE: When saving generated project files, we ignore differences in GUIDs if every other part of the file
// matches identically with the pre-existing file
2015-09-24 12:37:21 -04:00
var FilterGUID = Guid . NewGuid ( ) . ToString ( "B" ) . ToUpperInvariant ( ) ;
2014-04-24 04:43:16 -04:00
VCFiltersFileContent . Append (
" <Filter Include=\"" + LeadingDirectory + "\">" + ProjectFileGenerator . NewLine +
" <UniqueIdentifier>" + FilterGUID + "</UniqueIdentifier>" + ProjectFileGenerator . NewLine +
" </Filter>" + ProjectFileGenerator . NewLine ) ;
FiltersFileIsNeeded = true ;
}
}
}
return FiltersFileIsNeeded ;
}
/// <summary>
/// Returns the VCFileType element name based on the file path.
/// </summary>
/// <param name="Path">The path of the file to return type for.</param>
/// <returns>Name of the element in MSBuild project file for this file.</returns>
private string GetVCFileType ( string Path )
{
// What type of file is this?
if ( Path . EndsWith ( ".h" , StringComparison . InvariantCultureIgnoreCase ) | |
Path . EndsWith ( ".inl" , StringComparison . InvariantCultureIgnoreCase ) )
{
return "ClInclude" ;
}
else if ( Path . EndsWith ( ".cpp" , StringComparison . InvariantCultureIgnoreCase ) )
{
return "ClCompile" ;
}
else if ( Path . EndsWith ( ".rc" , StringComparison . InvariantCultureIgnoreCase ) )
{
return "ResourceCompile" ;
}
else if ( Path . EndsWith ( ".manifest" , StringComparison . InvariantCultureIgnoreCase ) )
{
return "Manifest" ;
}
else
{
return "None" ;
}
}
2014-03-14 14:13:41 -04:00
2015-01-30 11:32:24 -05:00
// Anonymous function that writes pre-Default.props configuration data
2015-05-06 15:03:25 -04:00
private void WritePreDefaultPropsConfiguration ( UnrealTargetPlatform TargetPlatform , UnrealTargetConfiguration TargetConfiguration , string ProjectPlatformName , string ProjectConfigurationName , StringBuilder VCProjectFileContent )
2015-01-30 11:32:24 -05:00
{
2015-05-06 15:03:25 -04:00
UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator . GetPlatformProjectGenerator ( TargetPlatform , true ) ;
if ( ( ( ProjGenerator = = null ) & & ( TargetPlatform ! = UnrealTargetPlatform . Unknown ) ) )
2015-01-30 11:32:24 -05:00
{
return ;
}
2015-05-06 15:03:25 -04:00
var ProjectConfigurationAndPlatformName = ProjectConfigurationName + "|" + ProjectPlatformName ;
2015-09-24 12:37:21 -04:00
string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + ProjectConfigurationAndPlatformName + "'\"" ;
2015-01-30 11:32:24 -05:00
2015-05-06 15:03:25 -04:00
string PlatformToolsetString = ( ProjGenerator ! = null ) ? ProjGenerator . GetVisualStudioPlatformToolsetString ( TargetPlatform , TargetConfiguration , this ) : "" ;
2015-09-24 12:37:21 -04:00
if ( String . IsNullOrEmpty ( PlatformToolsetString ) )
2015-01-30 11:32:24 -05:00
{
2015-05-05 15:32:10 -04:00
PlatformToolsetString = " <PlatformToolset>" + VCProjectFileGenerator . ProjectFilePlatformToolsetVersionString + "</PlatformToolset>" + ProjectFileGenerator . NewLine ;
2015-01-30 11:32:24 -05:00
}
2015-01-30 11:52:22 -05:00
2015-09-24 12:37:21 -04:00
string PlatformConfigurationType = ( ProjGenerator = = null ) ? "Makefile" : ProjGenerator . GetVisualStudioPlatformConfigurationType ( TargetPlatform ) ;
2015-01-30 11:32:24 -05:00
VCProjectFileContent . Append (
" <PropertyGroup " + ConditionString + " Label=\"Configuration\">" + ProjectFileGenerator . NewLine +
" <ConfigurationType>" + PlatformConfigurationType + "</ConfigurationType>" + ProjectFileGenerator . NewLine +
PlatformToolsetString +
2015-09-24 12:37:21 -04:00
" </PropertyGroup>" + ProjectFileGenerator . NewLine
2015-01-30 11:32:24 -05:00
) ;
}
2014-03-14 14:13:41 -04:00
// Anonymous function that writes project configuration data
2015-01-30 11:52:22 -05:00
private void WriteConfiguration ( string ProjectName , ProjectConfigAndTargetCombination Combination , StringBuilder VCProjectFileContent , StringBuilder VCUserFileContent )
2014-03-14 14:13:41 -04:00
{
2015-01-30 11:52:22 -05:00
UnrealTargetPlatform Platform = Combination . Platform ;
UnrealTargetConfiguration Configuration = Combination . Configuration ;
2014-03-14 14:13:41 -04:00
UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator . GetPlatformProjectGenerator ( Platform , true ) ;
if ( ( ( ProjGenerator = = null ) & & ( Platform ! = UnrealTargetPlatform . Unknown ) ) )
{
return ;
}
2015-09-24 12:37:21 -04:00
2014-03-14 14:13:41 -04:00
string UProjectPath = "" ;
2014-06-24 17:33:20 -04:00
if ( IsForeignProject )
2014-03-14 14:13:41 -04:00
{
2014-08-18 08:18:27 -04:00
UProjectPath = "\"$(SolutionDir)$(ProjectName).uproject\"" ;
2014-03-14 14:13:41 -04:00
}
2015-01-30 11:52:22 -05:00
string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + Combination . ProjectConfigurationAndPlatformName + "'\"" ;
2014-03-14 14:13:41 -04:00
{
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 ) ;
2015-09-03 08:47:24 -04:00
DirectoryReference ProjectDirectory = ProjectFilePath . Directory ;
2014-03-14 14:13:41 -04:00
if ( IsStubProject )
{
string ProjectRelativeUnusedDirectory = NormalizeProjectPath ( Path . Combine ( ProjectFileGenerator . EngineRelativePath , BuildConfiguration . BaseIntermediateFolder , "Unused" ) ) ;
VCProjectFileContent . Append (
2015-05-05 15:32:10 -04:00
" <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator . NewLine +
2015-01-30 11:52:22 -05:00
" <OutDir>" + ProjectRelativeUnusedDirectory + Path . DirectorySeparatorChar + "</OutDir>" + ProjectFileGenerator . NewLine +
2014-03-14 14:13:41 -04:00
" <IntDir>" + ProjectRelativeUnusedDirectory + Path . DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator . NewLine +
2015-01-30 11:52:22 -05:00
" <NMakeBuildCommandLine>@rem Nothing to do.</NMakeBuildCommandLine>" + ProjectFileGenerator . NewLine +
" <NMakeReBuildCommandLine>@rem Nothing to do.</NMakeReBuildCommandLine>" + ProjectFileGenerator . NewLine +
" <NMakeCleanCommandLine>@rem Nothing to do.</NMakeCleanCommandLine>" + ProjectFileGenerator . NewLine +
2015-04-22 17:05:11 -04:00
" <NMakeOutput/>" + ProjectFileGenerator . NewLine +
2015-05-05 15:32:10 -04:00
" </PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
}
2015-09-24 12:37:21 -04:00
else if ( ProjectFileGenerator . bGeneratingRocketProjectFiles & & Combination . ProjectTarget ! = null & & Combination . ProjectTarget . TargetRules ! = null & & ! Combination . ProjectTarget . TargetRules . SupportsPlatform ( Combination . Platform ) )
2015-05-26 16:04:12 -04:00
{
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 +
2015-09-03 08:47:24 -04:00
" </PropertyGroup>" + ProjectFileGenerator . NewLine , Combination . Platform , Combination . ProjectTarget . TargetFilePath . GetFileNameWithoutAnyExtensions ( ) , String . Join ( ", " , SupportedPlatforms . Select ( x = > x . ToString ( ) ) ) ) ;
2015-05-26 16:04:12 -04:00
}
2014-03-14 14:13:41 -04:00
else
{
2015-01-30 11:52:22 -05:00
TargetRules TargetRulesObject = Combination . ProjectTarget . TargetRules ;
2015-09-03 08:47:24 -04:00
FileReference TargetFilePath = Combination . ProjectTarget . TargetFilePath ;
string TargetName = TargetFilePath . GetFileNameWithoutAnyExtensions ( ) ;
2014-03-14 14:13:41 -04:00
var UBTPlatformName = IsStubProject ? StubProjectPlatformName : Platform . ToString ( ) ;
var UBTConfigurationName = IsStubProject ? StubProjectConfigurationName : Configuration . ToString ( ) ;
// Setup output path
2014-05-21 06:09:37 -04:00
var BuildPlatform = UEBuildPlatform . GetBuildPlatform ( Platform ) ;
2014-03-14 14:13:41 -04:00
// Figure out if this is a monolithic build
bool bShouldCompileMonolithic = BuildPlatform . ShouldCompileMonolithicBinary ( Platform ) ;
bShouldCompileMonolithic | = TargetRulesObject . ShouldCompileMonolithic ( Platform , Configuration ) ;
// Get the output directory
2015-09-03 08:47:24 -04:00
DirectoryReference RootDirectory = UnrealBuildTool . EngineDirectory ;
2015-05-05 15:32:10 -04:00
if ( ( TargetRules . IsAGame ( TargetRulesObject . Type ) | | TargetRulesObject . Type = = TargetRules . TargetType . Server ) & & bShouldCompileMonolithic & & ! TargetRulesObject . bOutputToEngineBinaries )
2014-03-14 14:13:41 -04:00
{
2015-09-17 09:15:44 -04:00
if ( OnlyGameProject ! = null & & TargetFilePath . IsUnderDirectory ( OnlyGameProject . Directory ) )
2014-03-14 14:13:41 -04:00
{
2015-09-17 09:15:44 -04:00
RootDirectory = OnlyGameProject . Directory ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-09-03 08:47:24 -04:00
FileReference ProjectFileName ;
2015-09-24 12:37:21 -04:00
if ( UProjectInfo . TryGetProjectFileName ( ProjectName , out ProjectFileName ) )
2014-03-14 14:13:41 -04:00
{
2015-09-03 08:47:24 -04:00
RootDirectory = ProjectFileName . Directory ;
2014-03-14 14:13:41 -04:00
}
}
}
2015-09-24 12:37:21 -04:00
if ( TargetRulesObject . Type = = TargetRules . TargetType . Program & & ! TargetRulesObject . bOutputToEngineBinaries )
2014-09-16 15:16:32 -04:00
{
2015-09-03 08:47:24 -04:00
FileReference ProjectFileName ;
2015-09-24 12:37:21 -04:00
if ( UProjectInfo . TryGetProjectForTarget ( TargetName , out ProjectFileName ) )
2014-09-16 15:16:32 -04:00
{
2015-09-03 08:47:24 -04:00
RootDirectory = ProjectFileName . Directory ;
2014-09-16 15:16:32 -04:00
}
}
2014-03-14 14:13:41 -04:00
// Get the output directory
2015-09-03 08:47:24 -04:00
DirectoryReference OutputDirectory = DirectoryReference . Combine ( RootDirectory , "Binaries" , UBTPlatformName ) ;
2014-03-14 14:13:41 -04:00
// 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 ;
2014-09-29 09:35:05 -04:00
if ( TargetConfigurationName ! = TargetRules . TargetType . Game . ToString ( ) & & TargetConfigurationName ! = TargetRules . TargetType . Program . ToString ( ) )
2014-03-14 14:13:41 -04:00
{
BaseExeName = "UE4" + TargetConfigurationName ;
}
}
// Make the output file path
2015-09-03 08:47:24 -04:00
FileReference NMakePath = FileReference . Combine ( OutputDirectory , BaseExeName ) ;
2014-03-14 14:13:41 -04:00
if ( Configuration ! = UnrealTargetConfiguration . Development & & ( Configuration ! = UnrealTargetConfiguration . DebugGame | | bShouldCompileMonolithic ) )
{
NMakePath + = "-" + UBTPlatformName + "-" + UBTConfigurationName ;
}
NMakePath + = BuildPlatform . GetActiveArchitecture ( ) ;
NMakePath + = BuildPlatform . GetBinaryExtension ( UEBuildBinaryType . Executable ) ;
2014-05-21 06:09:37 -04:00
NMakePath = ( BuildPlatform as UEBuildPlatform ) . ModifyNMakeOutput ( NMakePath ) ;
2014-03-14 14:13:41 -04:00
2015-05-05 15:32:10 -04:00
VCProjectFileContent . Append (
" <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator . NewLine ) ;
2015-04-22 17:05:11 -04:00
2014-03-14 14:13:41 -04:00
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 ) ;
}
2014-04-23 19:16:11 -04:00
if ( TargetRules . IsGameType ( TargetRulesObject . Type ) & &
( TargetRules . IsEditorType ( TargetRulesObject . Type ) = = false ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 19:16:11 -04:00
// Allow platforms to add any special properties they require... like aumid override for Xbox One
UEPlatformProjectGenerator . GenerateGamePlatformSpecificProperties ( Platform , Configuration , TargetRulesObject . Type , VCProjectFileContent , RootDirectory , TargetFilePath ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-30 11:52:22 -05:00
// 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
2015-03-27 08:03:00 -04:00
string BuildArguments = " " + TargetName + " " + UBTPlatformName + " " + UBTConfigurationName ;
2015-09-24 12:37:21 -04:00
if ( ProjectFileGenerator . bUsePrecompiled )
2015-03-27 08:03:00 -04:00
{
2015-03-27 09:13:06 -04:00
BuildArguments + = " -useprecompiled" ;
2015-03-27 08:03:00 -04:00
}
if ( IsForeignProject )
{
BuildArguments + = " " + UProjectPath + ( UnrealBuildTool . RunningRocket ( ) ? " -rocket" : "" ) ;
}
2015-09-03 09:18:45 -04:00
// Always wait for the mutex between UBT invocations, so that building the whole solution doesn't fail.
BuildArguments + = " -waitmutex" ;
2015-09-03 08:47:24 -04:00
DirectoryReference BatchFilesDirectory = DirectoryReference . Combine ( UnrealBuildTool . EngineDirectory , "Build" , "BatchFiles" ) ;
2015-01-30 11:52:22 -05:00
2015-05-12 12:00:23 -04:00
// @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
2015-05-05 15:32:10 -04:00
string BuildToolOverride = "" ;
if ( UnrealBuildTool . CommandLineContains ( "-2012" ) )
{
BuildToolOverride = " -2012" ;
}
if ( UnrealBuildTool . CommandLineContains ( "-2013" ) )
{
BuildToolOverride = " -2013" ;
}
if ( UnrealBuildTool . CommandLineContains ( "-2015" ) )
{
BuildToolOverride = " -2015" ;
}
BuildArguments + = BuildToolOverride ;
2015-01-30 11:52:22 -05:00
// NMake Build command line
VCProjectFileContent . Append ( " <NMakeBuildCommandLine>" ) ;
2015-09-03 08:47:24 -04:00
VCProjectFileContent . Append ( EscapePath ( NormalizeProjectPath ( FileReference . Combine ( BatchFilesDirectory , "Build.bat" ) ) ) + BuildArguments . ToString ( ) ) ;
2015-01-30 11:52:22 -05:00
VCProjectFileContent . Append ( "</NMakeBuildCommandLine>" + ProjectFileGenerator . NewLine ) ;
// NMake ReBuild command line
VCProjectFileContent . Append ( " <NMakeReBuildCommandLine>" ) ;
2015-09-03 08:47:24 -04:00
VCProjectFileContent . Append ( EscapePath ( NormalizeProjectPath ( FileReference . Combine ( BatchFilesDirectory , "Rebuild.bat" ) ) ) + BuildArguments . ToString ( ) ) ;
2015-01-30 11:52:22 -05:00
VCProjectFileContent . Append ( "</NMakeReBuildCommandLine>" + ProjectFileGenerator . NewLine ) ;
// NMake Clean command line
VCProjectFileContent . Append ( " <NMakeCleanCommandLine>" ) ;
2015-09-03 08:47:24 -04:00
VCProjectFileContent . Append ( EscapePath ( NormalizeProjectPath ( FileReference . Combine ( BatchFilesDirectory , "Clean.bat" ) ) ) + BuildArguments . ToString ( ) ) ;
2015-01-30 11:52:22 -05:00
VCProjectFileContent . Append ( "</NMakeCleanCommandLine>" + ProjectFileGenerator . NewLine ) ;
2015-01-19 14:35:40 -05:00
2014-03-14 14:13:41 -04:00
VCProjectFileContent . Append ( " <NMakeOutput>" ) ;
2015-09-03 08:47:24 -04:00
VCProjectFileContent . Append ( NormalizeProjectPath ( NMakePath . FullName ) ) ;
2014-03-14 14:13:41 -04:00
VCProjectFileContent . Append ( "</NMakeOutput>" + ProjectFileGenerator . NewLine ) ;
2015-05-05 15:32:10 -04:00
VCProjectFileContent . Append ( " </PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
2015-04-22 17:05:11 -04:00
2015-05-05 15:32:10 -04:00
string LayoutDirString = ( ProjGenerator ! = null ) ? ProjGenerator . GetVisualStudioLayoutDirSection ( Platform , Configuration , ConditionString , Combination . ProjectTarget . TargetRules . Type , Combination . ProjectTarget . TargetFilePath , ProjectFilePath , NMakePath ) : "" ;
VCProjectFileContent . Append ( LayoutDirString ) ;
}
2014-03-14 14:13:41 -04:00
2015-01-30 11:52:22 -05:00
if ( VCUserFileContent ! = null & & Combination . ProjectTarget ! = null )
2014-03-14 14:13:41 -04:00
{
2015-01-30 11:52:22 -05:00
TargetRules TargetRulesObject = Combination . ProjectTarget . TargetRules ;
2015-05-12 12:00:23 -04:00
if ( ( Platform = = UnrealTargetPlatform . Win32 ) | | ( Platform = = UnrealTargetPlatform . Win64 ) | | ( Platform = = UnrealTargetPlatform . UWP ) )
2014-03-14 14:13:41 -04:00
{
2014-12-11 15:44:40 -05:00
VCUserFileContent . Append (
" <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator . NewLine ) ;
if ( TargetRulesObject . Type ! = TargetRules . TargetType . Game )
2014-03-14 14:13:41 -04:00
{
2014-12-11 15:44:40 -05:00
string DebugOptions = "" ;
2015-09-24 12:37:21 -04:00
if ( IsForeignProject )
2014-03-14 14:13:41 -04:00
{
2014-12-11 15:44:40 -05:00
DebugOptions + = UProjectPath ;
2014-03-14 14:13:41 -04:00
}
2015-09-24 12:37:21 -04:00
else if ( TargetRulesObject . Type = = TargetRules . TargetType . Editor & & ProjectName ! = "UE4" )
2014-12-11 15:44:40 -05:00
{
DebugOptions + = ProjectName ;
}
if ( Configuration = = UnrealTargetConfiguration . Debug | | Configuration = = UnrealTargetConfiguration . DebugGame )
{
DebugOptions + = " -debug" ;
}
else if ( Configuration = = UnrealTargetConfiguration . Shipping )
{
DebugOptions + = " -shipping" ;
}
2014-03-14 14:13:41 -04:00
VCUserFileContent . Append (
2014-12-11 15:44:40 -05:00
" <LocalDebuggerCommandArguments>" + DebugOptions + "</LocalDebuggerCommandArguments>" + ProjectFileGenerator . NewLine
2014-03-14 14:13:41 -04:00
) ;
}
2014-12-11 15:44:40 -05:00
VCUserFileContent . Append (
" <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>" + ProjectFileGenerator . NewLine
) ;
VCUserFileContent . Append (
" </PropertyGroup>" + ProjectFileGenerator . NewLine
) ;
2014-03-14 14:13:41 -04:00
}
2015-01-30 11:52:22 -05:00
string PlatformUserFileStrings = ( ProjGenerator ! = null ) ? ProjGenerator . GetVisualStudioUserFileStrings ( Platform , Configuration , ConditionString , TargetRulesObject , Combination . ProjectTarget . TargetFilePath , ProjectFilePath ) : "" ;
2014-03-14 14:13:41 -04:00
VCUserFileContent . Append ( PlatformUserFileStrings ) ;
}
}
}
}
2015-09-24 13:47:13 -04:00
/// <summary>
/// A Visual C# project.
/// </summary>
2014-03-14 14:13:41 -04:00
public class VCSharpProjectFile : MSBuildProjectFile
{
// This is the GUID that Visual Studio uses to identify a C# project file in the solution
public override string ProjectTypeGUID
{
get { return "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" ; }
}
/// <summary>
/// Constructs a new project file object
/// </summary>
/// <param name="InitFilePath">The path to the project file on disk</param>
2015-09-24 12:37:21 -04:00
public VCSharpProjectFile ( FileReference InitFilePath )
: base ( InitFilePath )
2014-03-14 14:13:41 -04:00
{
}
2015-09-24 13:47:13 -04:00
/// <summary>
/// Reads the list of dependencies from the specified project file.
/// </summary>
2014-03-14 14:13:41 -04:00
public List < string > GetCSharpDependencies ( )
{
var RelativeFilePaths = new List < string > ( ) ;
var Doc = new XmlDocument ( ) ;
2015-09-24 12:37:21 -04:00
Doc . Load ( ProjectFilePath . FullName ) ;
2014-03-14 14:13:41 -04:00
var Tags = new string [ ] { "Compile" , "Page" , "Resource" } ;
2015-09-24 12:37:21 -04:00
foreach ( var Tag in Tags )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
var Elements = Doc . GetElementsByTagName ( Tag ) ;
foreach ( XmlElement Element in Elements )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
RelativeFilePaths . Add ( Element . GetAttribute ( "Include" ) ) ;
2014-03-14 14:13:41 -04:00
}
}
return RelativeFilePaths ;
}
2015-09-24 13:47:13 -04:00
/// <summary>
/// Adds a C# dot net (system) assembly reference to this project
/// </summary>
/// <param name="AssemblyReference">The full path to the assembly file on disk</param>
2014-03-14 14:13:41 -04:00
public void AddDotNetAssemblyReference ( string AssemblyReference )
{
if ( ! DotNetAssemblyReferences . Contains ( AssemblyReference ) )
{
DotNetAssemblyReferences . Add ( AssemblyReference ) ;
}
}
2015-09-24 13:47:13 -04:00
/// <summary>
/// Adds a C# assembly reference to this project, such as a third party assembly needed for this project to compile
/// </summary>
/// <param name="AssemblyReference">The full path to the assembly file on disk</param>
2015-09-24 12:37:21 -04:00
public void AddAssemblyReference ( FileReference AssemblyReference )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
AssemblyReferences . Add ( AssemblyReference ) ;
2014-03-14 14:13:41 -04:00
}
/// <summary>
/// Basic csproj file support. Generates C# library project with one build config.
/// </summary>
/// <param name="InPlatforms">Not used.</param>
/// <param name="InConfigurations">Not Used.</param>
/// <returns>true if the opration was successful, false otherwise</returns>
public override bool WriteProjectFile ( List < UnrealTargetPlatform > InPlatforms , List < UnrealTargetConfiguration > InConfigurations )
{
bool bSuccess = true ;
// Setup C# project file content.
var ProjectFileContent = new StringBuilder ( ) ;
// Project file header.
ProjectFileContent . Append (
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator . NewLine +
2015-05-06 11:53:12 -04:00
"<Project DefaultTargets=\"Build\" ToolsVersion=\"" + VCProjectFileGenerator . ProjectFileToolVersionString + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
ProjectFileContent . Append (
"<Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />" +
2015-05-05 15:32:10 -04:00
ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
// Support single configuration only (for now).
ProjectFileContent . Append (
"<PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Development|AnyCPU' \">" + ProjectFileGenerator . NewLine +
"\t<DebugType>pdbonly</DebugType>" + ProjectFileGenerator . NewLine +
"\t<Optimize>true</Optimize>" + ProjectFileGenerator . NewLine +
"\t<OutputPath>bin\\Release\\</OutputPath>" + ProjectFileGenerator . NewLine +
"\t<DefineConstants>TRACE</DefineConstants>" + ProjectFileGenerator . NewLine +
"\t<ErrorReport>prompt</ErrorReport>" + ProjectFileGenerator . NewLine +
"\t<WarningLevel>4</WarningLevel>" + ProjectFileGenerator . NewLine +
2015-05-05 15:32:10 -04:00
"\t<TreatWarningsAsErrors>true</TreatWarningsAsErrors>" + ProjectFileGenerator . NewLine +
2014-03-14 14:13:41 -04:00
"</PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append (
"<PropertyGroup>" + ProjectFileGenerator . NewLine +
"\t<OutputType>Library</OutputType>" + ProjectFileGenerator . NewLine +
"\t<ProjectGuid>" + ProjectGUID . ToString ( "B" ) . ToUpperInvariant ( ) + "</ProjectGuid>" + ProjectFileGenerator . NewLine +
"\t<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>" + ProjectFileGenerator . NewLine +
"\t</PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
// Basic .Net references
if ( DotNetAssemblyReferences . Count > 0 )
{
ProjectFileContent . Append ( "<ItemGroup>" + ProjectFileGenerator . NewLine ) ;
foreach ( var CurReference in DotNetAssemblyReferences )
{
2015-08-27 12:46:47 -04:00
ProjectFileContent . Append ( "\t<Reference Include=\"" + EscapeFileName ( CurReference ) + "\" />" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
ProjectFileContent . Append ( "</ItemGroup>" + ProjectFileGenerator . NewLine ) ;
}
// External or third party assembly references
2015-09-24 12:37:21 -04:00
if ( AssemblyReferences . Count > 0 )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
ProjectFileContent . Append ( "<ItemGroup>" + ProjectFileGenerator . NewLine ) ;
foreach ( var CurReference in AssemblyReferences )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
ProjectFileContent . Append ( "\t<Reference Include=\"" + EscapeFileName ( CurReference . GetFileNameWithoutExtension ( ) ) + "\" >" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append ( "\t\t<HintPath>" + CurReference . MakeRelativeTo ( ProjectFilePath . Directory ) + "</HintPath>" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append ( "\t</Reference>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-24 12:37:21 -04:00
ProjectFileContent . Append ( "</ItemGroup>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
// Other references (note it's assumed all references here are at least of MSBuildProjectFile type.
foreach ( var Project in DependsOnProjects )
{
2015-09-03 08:47:24 -04:00
var RelativePath = Project . ProjectFilePath . Directory . MakeRelativeTo ( ProjectFilePath . Directory ) ;
RelativePath = Path . Combine ( RelativePath , Project . ProjectFilePath . GetFileName ( ) ) ;
2014-03-14 14:13:41 -04:00
ProjectFileContent . Append (
"<ItemGroup>" + ProjectFileGenerator . NewLine +
2015-08-27 12:46:47 -04:00
"<ProjectReference Include=\"" + EscapeFileName ( RelativePath ) + "\">" + ProjectFileGenerator . NewLine +
2014-03-14 14:13:41 -04:00
"<Project>" + ( ( MSBuildProjectFile ) Project ) . ProjectGUID . ToString ( "B" ) . ToUpperInvariant ( ) + "</Project>" + ProjectFileGenerator . NewLine +
"<Name>" + Path . GetFileNameWithoutExtension ( RelativePath ) + "</Name>" + ProjectFileGenerator . NewLine +
"</ProjectReference>" + ProjectFileGenerator . NewLine +
"</ItemGroup>" + ProjectFileGenerator . NewLine ) ;
}
// Source files.
ProjectFileContent . Append (
2015-09-24 12:37:21 -04:00
" <ItemGroup>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
// Add all files to the project.
2015-09-24 12:37:21 -04:00
foreach ( var CurFile in SourceFiles )
2014-03-14 14:13:41 -04:00
{
2015-09-24 12:37:21 -04:00
var ProjectRelativeSourceFile = CurFile . Reference . MakeRelativeTo ( ProjectFilePath . Directory ) ;
2014-03-14 14:13:41 -04:00
ProjectFileContent . Append (
2015-08-27 12:46:47 -04:00
" <Compile Include=\"" + EscapeFileName ( ProjectRelativeSourceFile ) + "\" />" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
ProjectFileContent . Append (
2015-09-24 12:37:21 -04:00
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
ProjectFileContent . Append (
"<Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append (
2015-09-24 12:37:21 -04:00
"</Project>" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
// Save the project file
if ( bSuccess )
{
2015-09-03 08:47:24 -04:00
bSuccess = ProjectFileGenerator . WriteFileIfChanged ( ProjectFilePath . FullName , ProjectFileContent . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
return bSuccess ;
}
/// Assemblies this project is dependent on
2015-09-03 08:47:24 -04:00
protected readonly List < FileReference > AssemblyReferences = new List < FileReference > ( ) ;
2014-03-14 14:13:41 -04:00
/// System assemblies this project is dependent on
protected readonly List < string > DotNetAssemblyReferences = new List < string > ( ) { "System" , "System.Core" , "System.Data" , "System.Xml" } ;
}
/// <summary>
/// A Sandcastle Help File Builder project
/// </summary>
public class VSHFBProjectFile : MSBuildProjectFile
{
// This is the GUID that Visual Studio uses to identify a Sandcastle Help File project file in the solution - note the lack of {}
public override string ProjectTypeGUID
{
get { return "0074e5b6-dd35-4f2c-9ede-f6259f61e92c" ; }
}
/// <summary>
/// Constructs a new project file object
/// </summary>
/// <param name="InitFilePath">The path to the project file on disk</param>
2015-09-24 12:37:21 -04:00
public VSHFBProjectFile ( FileReference InitFilePath )
: base ( InitFilePath )
2014-03-14 14:13:41 -04:00
{
}
}
}