2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
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 ;
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
{
get { throw new BuildException ( "Unrecognized type of project file for Visual Studio solution" ) ; }
}
/// <summary>
/// Constructs a new project file object
/// </summary>
/// <param name="InitFilePath">The path to the project file on disk</param>
public MSBuildProjectFile ( string InitFilePath )
: 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.
if ( File . Exists ( ProjectFilePath ) )
{
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.
if ( ProjectFileGenerator . bGenerateProjectFiles )
{
var Doc = new XmlDocument ( ) ;
Doc . Load ( ProjectFilePath ) ;
// @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?
var Elements = Doc . GetElementsByTagName ( "ProjectGuid" ) ;
foreach ( XmlElement Element in Elements )
{
ProjectGUID = Guid . ParseExact ( Element . InnerText . Trim ( "{}" . ToCharArray ( ) ) , "D" ) ;
}
}
}
/// <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 ;
}
if ( ! String . IsNullOrEmpty ( TargetConfigurationName ) )
{
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 > ( ) ;
if ( ! ProjectFileGenerator . bCreateDummyConfigsForUnsupportedPlatforms | | ProjectFileGenerator . bGeneratingRocketProjectFiles )
{
if ( ProjectTarget . TargetRules ! = null )
{
ProjectTarget . TargetRules . GetSupportedPlatforms ( ref SupportedPlatforms ) ;
}
}
else
{
UnrealBuildTool . GetAllPlatforms ( ref SupportedPlatforms ) ;
}
bool bIncludeTestAndShippingConfigs = ProjectFileGenerator . bIncludeTestAndShippingConfigs | | ProjectFileGenerator . bGeneratingRocketProjectFiles ;
if ( ProjectTarget . TargetRules ! = null )
{
// Rocket projects always get shipping configs
ProjectTarget . TargetRules . GetSupportedConfigurations ( ref SupportedConfigurations , bIncludeTestAndShippingConfigs : bIncludeTestAndShippingConfigs ) ;
}
// Add all of the extra platforms/configurations for this target
{
foreach ( var ExtraPlatform in ProjectTarget . ExtraSupportedPlatforms )
{
if ( ! SupportedPlatforms . Contains ( ExtraPlatform ) )
{
SupportedPlatforms . Add ( ExtraPlatform ) ;
}
}
foreach ( var ExtraConfig in ProjectTarget . ExtraSupportedConfigurations )
{
if ( bIncludeTestAndShippingConfigs | | ( ExtraConfig ! = UnrealTargetConfiguration . Shipping & & ExtraConfig ! = UnrealTargetConfiguration . Test ) )
{
if ( ! SupportedConfigurations . Contains ( ExtraConfig ) )
{
SupportedConfigurations . Add ( ExtraConfig ) ;
}
}
}
}
// Only build for supported platforms
if ( SupportedPlatforms . Contains ( Platform ) = = false )
{
return false ;
}
// Only build for supported configurations
if ( SupportedConfigurations . Contains ( Configuration ) = = false )
{
return false ;
}
// For Rocket projects, we currently only allow 64-bit versions of Debug and Development binaries to be compiled
// and only 32-bit versions of Shipping binaries to be compiled. This has to do with our choice of which build
// configurations we want to ship with that product. So to simplify things, we're merging Win32 and Win64
// configurations together in the IDE under "Windows". In order for this to work properly, we need to make
// sure that Rocket projects only report the respective Windows platform that is valid for each configuration
if ( UnrealBuildTool . RunningRocket ( ) & & ProjectTarget . TargetRules ! = null )
{
if ( Platform = = UnrealTargetPlatform . Win32 | | Platform = = UnrealTargetPlatform . Win64 )
{
// In Rocket, shipping game targets are always 32-bit
if ( Configuration = = UnrealTargetConfiguration . Shipping & & ProjectTarget . TargetRules . Type = = TargetRules . TargetType . RocketGame )
{
if ( Platform ! = UnrealTargetPlatform . Win32 )
{
return false ;
}
}
else
{
// Everything else is expecting to be 64-bit
if ( Platform ! = UnrealTargetPlatform . Win64 )
{
return false ;
}
}
}
}
return true ;
}
/// <summary>
/// GUID for this Visual C++ project file
/// </summary>
public Guid ProjectGUID
{
get ;
protected set ;
}
}
public class VCProjectFile : MSBuildProjectFile
{
// 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>
public VCProjectFile ( string InitFilePath )
: base ( InitFilePath )
{
}
struct ProjectConfigAndTargetCombination
{
public UnrealTargetPlatform Platform ;
public UnrealTargetConfiguration Configuration ;
public ProjectTarget ProjectTarget ;
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 )
{
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 )
2014-04-02 18:09:23 -04:00
{
VCIncludeSearchPaths . Append ( CurPath + ";" ) ;
}
foreach ( var CurPath in IntelliSenseSystemIncludeSearchPaths )
2014-03-14 14:13:41 -04:00
{
VCIncludeSearchPaths . Append ( CurPath + ";" ) ;
}
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
var ToolsVersion = VCProjectFileGenerator . ProjectFileFormat = = VCProjectFileGenerator . VCProjectFileFormat . VisualStudio2013 ? "12.0" : "4.0" ;
VCProjectFileContent . Append (
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator . NewLine +
ProjectFileGenerator . NewLine +
"<Project DefaultTargets=\"Build\" ToolsVersion=\"" + ToolsVersion + "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator . NewLine ) ;
bool bGenerateUserFileContent = UnrealBuildTool . HasUProjectFile ( ) | |
UEPlatformProjectGenerator . PlatformRequiresVSUserFileGeneration ( InPlatforms , InConfigurations ) ;
if ( bGenerateUserFileContent )
{
VCUserFileContent . Append (
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" + ProjectFileGenerator . NewLine +
ProjectFileGenerator . NewLine +
"<Project ToolsVersion=\"" + ToolsVersion + "\" 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 )
{
ProjectConfigAndTargetCombinations . Add ( new ProjectConfigAndTargetCombination ( ) { Platform = UnrealTargetPlatform . Unknown , Configuration = UnrealTargetConfiguration . Unknown , ProjectTarget = null } ) ;
}
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
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 )
{
ProjectConfigAndTargetCombinations . Add ( new ProjectConfigAndTargetCombination ( )
{
Platform = Platform ,
Configuration = Configuration ,
ProjectTarget = ProjectTarget
} ) ;
}
}
}
}
}
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 ProjectPlatformNames = new List < string > ( ) ;
var ProjectConfigNames = new List < string > ( ) ;
foreach ( var Combination in ProjectConfigAndTargetCombinations )
{
var ProjectPlatform = Combination . Platform ;
var ProjectConfig = Combination . Configuration ;
var TargetRulesObject = Combination . ProjectTarget . TargetRules ;
// Only write config settings for valid permutations
if ( IsStubProject | | IsValidProjectPlatformAndConfiguration ( Combination . ProjectTarget , Combination . Platform , Combination . Configuration ) )
{
string ProjectPlatformName ;
string ProjectConfigName ;
MakeProjectPlatformAndConfigurationNames ( ProjectPlatform , ProjectConfig , TargetRulesObject . ConfigurationName , out ProjectPlatformName ,
out ProjectConfigName ) ;
if ( ! ProjectPlatforms . Contains ( Combination . Platform ) )
{
ProjectPlatforms . Add ( Combination . Platform ) ;
}
if ( ! ProjectPlatformNames . Contains ( ProjectPlatformName ) )
{
ProjectPlatformNames . Add ( ProjectPlatformName ) ;
}
if ( ! ProjectConfigNames . Contains ( ProjectConfigName ) )
{
ProjectConfigNames . Add ( ProjectConfigName ) ;
}
}
}
// Output ALL the project's config-platform permutations (project files MUST do this)
foreach ( var ProjectConfigName in ProjectConfigNames )
{
foreach ( var ProjectPlatformName in ProjectPlatformNames )
{
VCProjectFileContent . Append (
" <ProjectConfiguration Include=\"" + ProjectConfigName + "|" + ProjectPlatformName + "\">" + ProjectFileGenerator . NewLine +
" <Configuration>" + ProjectConfigName + "</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=\"4.0\" 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 ) ;
}
// 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
foreach ( var 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
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 ) ) ;
}
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 (
2014-04-24 04:43:16 -04:00
" <" + VCFileType + " Include=\"" + 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 (
2014-04-24 04:43:16 -04:00
" <" + VCFileType + " Include=\"" + AliasedFile . FileSystemPath + "\">" + ProjectFileGenerator . NewLine +
" <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 (
2014-04-24 04:43:16 -04:00
" <" + VCFileType + " Include=\"" + AliasedFile . FileSystemPath + "\" />" + ProjectFileGenerator . NewLine ) ;
2014-03-14 14:13:41 -04:00
}
}
VCProjectFileContent . Append (
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
VCFiltersFileContent . Append (
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
}
// 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 ) ;
}
// Anonymous function that writes pre-Default.props configuration data
System . Action < UnrealTargetConfiguration , UnrealTargetPlatform , string , TargetRules > PreDefaultPropsWriterFunc = ( Configuration , Platform , TargetFilePath , TargetRulesObject ) = >
{
UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator . GetPlatformProjectGenerator ( Platform , true ) ;
if ( ( ( ProjGenerator = = null ) & & ( Platform ! = UnrealTargetPlatform . Unknown ) ) )
{
return ;
}
string ProjectConfigName = StubProjectConfigurationName ;
string ProjectPlatformName = StubProjectPlatformName ;
MakeProjectPlatformAndConfigurationNames ( Platform , Configuration , TargetRulesObject . ConfigurationName , out ProjectPlatformName , out ProjectConfigName ) ;
var ConfigAndPlatformName = ProjectConfigName + "|" + ProjectPlatformName ;
string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + ConfigAndPlatformName + "'\"" ;
string PlatformToolsetString = ( ProjGenerator ! = null ) ? ProjGenerator . GetVisualStudioPlatformToolsetString ( Platform , 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 . GetVisualStudioPlatformConfigurationType ( Platform ) ;
VCProjectFileContent . Append (
" <PropertyGroup " + ConditionString + " Label=\"Configuration\">" + ProjectFileGenerator . NewLine +
" <ConfigurationType>" + PlatformConfigurationType + "</ConfigurationType>" + ProjectFileGenerator . NewLine +
PlatformToolsetString +
" </PropertyGroup>" + ProjectFileGenerator . NewLine
) ;
} ;
// Write each project configuration PreDefaultProps section
foreach ( var Combination in ProjectConfigAndTargetCombinations )
{
// Only write config settings for valid permutations
if ( IsStubProject | | IsValidProjectPlatformAndConfiguration ( Combination . ProjectTarget , Combination . Platform , Combination . Configuration ) )
{
PreDefaultPropsWriterFunc ( Combination . Configuration , Combination . Platform , Combination . ProjectTarget . TargetFilePath , Combination . ProjectTarget . TargetRules ) ;
}
}
VCProjectFileContent . Append (
" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />" + ProjectFileGenerator . NewLine +
" <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 )
{
// Only write config settings for valid permutations
if ( IsStubProject | | IsValidProjectPlatformAndConfiguration ( Combination . ProjectTarget , Combination . Platform , Combination . Configuration ) )
{
WriteConfiguration ( ProjectName , Combination . Configuration , Combination . Platform , Combination . ProjectTarget . TargetFilePath , Combination . ProjectTarget . TargetRules , VCProjectFileContent , bGenerateUserFileContent ? VCUserFileContent : null ) ;
}
}
// 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 )
{
// Only write config settings for valid permutations
if ( IsStubProject | | IsValidProjectPlatformAndConfiguration ( Combination . ProjectTarget , Combination . Platform , Combination . Configuration ) )
{
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 ;
}
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
var PathRemaining = Utils . CleanDirectorySeparators ( FilterRelativeSourceDirectory ) ;
var FiltersFileIsNeeded = false ;
if ( ! FilterDirectories . Contains ( PathRemaining ) )
{
// Make sure all subdirectories leading up to this directory each have their own filter, too!
var AllDirectoriesInPath = new List < string > ( ) ;
var PathSoFar = "" ;
for ( ; ; )
{
if ( PathRemaining . Length > 0 )
{
var SlashIndex = PathRemaining . IndexOf ( Path . DirectorySeparatorChar ) ;
string SplitDirectory ;
if ( SlashIndex ! = - 1 )
{
SplitDirectory = PathRemaining . Substring ( 0 , SlashIndex ) ;
PathRemaining = PathRemaining . Substring ( SplitDirectory . Length + 1 ) ;
}
else
{
SplitDirectory = PathRemaining ;
PathRemaining = "" ;
}
if ( ! String . IsNullOrEmpty ( PathSoFar ) )
{
PathSoFar + = Path . DirectorySeparatorChar ;
}
PathSoFar + = SplitDirectory ;
AllDirectoriesInPath . Add ( PathSoFar ) ;
}
else
{
break ;
}
}
foreach ( var LeadingDirectory in AllDirectoriesInPath )
{
if ( ! FilterDirectories . Contains ( LeadingDirectory ) )
{
FilterDirectories . Add ( LeadingDirectory ) ;
// 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
var FilterGUID = Guid . NewGuid ( ) . ToString ( "B" ) . ToUpperInvariant ( ) ;
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
// Anonymous function that writes project configuration data
private void WriteConfiguration ( string ProjectName , UnrealTargetConfiguration Configuration , UnrealTargetPlatform Platform , string TargetFilePath , TargetRules TargetRulesObject , StringBuilder VCProjectFileContent , StringBuilder VCUserFileContent )
{
UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator . GetPlatformProjectGenerator ( Platform , true ) ;
if ( ( ( ProjGenerator = = null ) & & ( Platform ! = UnrealTargetPlatform . Unknown ) ) )
{
return ;
}
string UProjectPath = "" ;
bool bIsProjectTarget = UnrealBuildTool . HasUProjectFile ( ) & & Utils . IsFileUnderDirectory ( TargetFilePath , UnrealBuildTool . GetUProjectPath ( ) ) ;
// @todo Rocket: HACK: Only use long project names on the UBT command-line for out-of-root projects for now. We need to revisit all uses of HasUProjectFile and short names in general to fix this.
if ( bIsProjectTarget & & ! UnrealBuildTool . RunningRocket ( ) & & Utils . IsFileUnderDirectory ( UnrealBuildTool . GetUProjectFile ( ) , ProjectFileGenerator . RootRelativePath ) )
{
bIsProjectTarget = false ;
}
if ( bIsProjectTarget )
{
UProjectPath = "\"$(SolutionDir)$(SolutionName).uproject\"" ;
}
string ProjectConfigName = StubProjectConfigurationName ;
string ProjectPlatformName = StubProjectPlatformName ;
MakeProjectPlatformAndConfigurationNames ( Platform , Configuration , TargetRulesObject . ConfigurationName , out ProjectPlatformName , out ProjectConfigName ) ;
var ConfigAndPlatformName = ProjectConfigName + "|" + ProjectPlatformName ;
string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + ConfigAndPlatformName + "'\"" ;
{
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 ) ;
VCProjectFileContent . Append (
" <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator . NewLine ) ;
if ( IsStubProject )
{
string ProjectRelativeUnusedDirectory = NormalizeProjectPath ( Path . Combine ( ProjectFileGenerator . EngineRelativePath , BuildConfiguration . BaseIntermediateFolder , "Unused" ) ) ;
VCProjectFileContent . Append (
" <OutDir></OutDir>" + ProjectFileGenerator . NewLine +
" <IntDir>" + ProjectRelativeUnusedDirectory + Path . DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator . NewLine +
" <NMakeBuildCommandLine/>" + ProjectFileGenerator . NewLine +
" <NMakeReBuildCommandLine/>" + ProjectFileGenerator . NewLine +
" <NMakeCleanCommandLine/>" + ProjectFileGenerator . NewLine +
" <NMakeOutput/>" + ProjectFileGenerator . NewLine ) ;
}
else
{
string TargetName = Utils . GetFilenameWithoutAnyExtensions ( TargetFilePath ) ;
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
string RootDirectory = Path . GetFullPath ( ProjectFileGenerator . EngineRelativePath ) ;
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 ) ) ;
}
}
}
// 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 . RocketGame . 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 ) ;
2014-05-21 06:09:37 -04:00
NMakePath = ( BuildPlatform as UEBuildPlatform ) . ModifyNMakeOutput ( NMakePath ) ;
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
}
// 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 ProjectPlatformConfiguration = " " + TargetName + " " + UBTPlatformName + " " + UBTConfigurationName ;
string BatchFilesDirectoryName = Path . Combine ( ProjectFileGenerator . EngineRelativePath , "Build" , "BatchFiles" ) ;
// NMake Build command line
VCProjectFileContent . Append ( " <NMakeBuildCommandLine>" ) ;
VCProjectFileContent . Append ( EscapePath ( NormalizeProjectPath ( Path . Combine ( BatchFilesDirectoryName , "Build.bat" ) ) ) + ProjectPlatformConfiguration . ToString ( ) ) ;
if ( bIsProjectTarget )
{
VCProjectFileContent . Append ( " " + UProjectPath + ( UnrealBuildTool . RunningRocket ( ) ? " -rocket" : "" ) ) ;
}
VCProjectFileContent . Append ( "</NMakeBuildCommandLine>" + ProjectFileGenerator . NewLine ) ;
// NMake ReBuild command line
VCProjectFileContent . Append ( " <NMakeReBuildCommandLine>" ) ;
VCProjectFileContent . Append ( EscapePath ( NormalizeProjectPath ( Path . Combine ( BatchFilesDirectoryName , "Rebuild.bat" ) ) ) + ProjectPlatformConfiguration . ToString ( ) ) ;
if ( bIsProjectTarget )
{
VCProjectFileContent . Append ( " " + UProjectPath + ( UnrealBuildTool . RunningRocket ( ) ? " -rocket" : "" ) ) ;
}
VCProjectFileContent . Append ( "</NMakeReBuildCommandLine>" + ProjectFileGenerator . NewLine ) ;
// NMake Clean command line
VCProjectFileContent . Append ( " <NMakeCleanCommandLine>" ) ;
VCProjectFileContent . Append ( EscapePath ( NormalizeProjectPath ( Path . Combine ( BatchFilesDirectoryName , "Clean.bat" ) ) ) + ProjectPlatformConfiguration . ToString ( ) ) ;
if ( bIsProjectTarget )
{
VCProjectFileContent . Append ( " " + UProjectPath + ( UnrealBuildTool . RunningRocket ( ) ? " -rocket" : "" ) ) ;
}
VCProjectFileContent . Append ( "</NMakeCleanCommandLine>" + ProjectFileGenerator . NewLine ) ;
VCProjectFileContent . Append ( " <NMakeOutput>" ) ;
VCProjectFileContent . Append ( NormalizeProjectPath ( NMakePath ) ) ;
VCProjectFileContent . Append ( "</NMakeOutput>" + ProjectFileGenerator . NewLine ) ;
}
VCProjectFileContent . Append ( " </PropertyGroup>" + ProjectFileGenerator . NewLine ) ;
if ( VCUserFileContent ! = null )
{
if ( UnrealBuildTool . HasUProjectFile ( ) )
{
if ( ( Platform = = UnrealTargetPlatform . Win32 ) | | ( Platform = = UnrealTargetPlatform . Win64 ) )
{
VCUserFileContent . Append (
" <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator . NewLine ) ;
if ( ( TargetRulesObject . Type ! = TargetRules . TargetType . RocketGame ) & & ( TargetRulesObject . Type ! = TargetRules . TargetType . Game ) )
{
string DebugOptions = UProjectPath ;
if ( DebugOptions . Length = = 0 & & 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 , TargetFilePath , ProjectFilePath ) : "" ;
VCUserFileContent . Append ( PlatformUserFileStrings ) ;
}
}
string LayoutDirString = ( ProjGenerator ! = null ) ? ProjGenerator . GetVisualStudioLayoutDirSection ( Platform , Configuration , ConditionString , TargetRulesObject . Type , TargetFilePath , ProjectFilePath ) : "" ;
VCProjectFileContent . Append ( LayoutDirString ) ;
}
}
/** A Visual C# project. */
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>
public VCSharpProjectFile ( string InitFilePath )
: base ( InitFilePath )
{
}
/** Reads the list of dependencies from the specified project file. */
public List < string > GetCSharpDependencies ( )
{
var RelativeFilePaths = new List < string > ( ) ;
var Doc = new XmlDocument ( ) ;
Doc . Load ( ProjectFilePath ) ;
var Tags = new string [ ] { "Compile" , "Page" , "Resource" } ;
foreach ( var Tag in Tags )
{
var Elements = Doc . GetElementsByTagName ( Tag ) ;
foreach ( XmlElement Element in Elements )
{
RelativeFilePaths . Add ( Element . GetAttribute ( "Include" ) ) ;
}
}
return RelativeFilePaths ;
}
/ * *
* Adds a C # dot net ( system ) assembly reference to this project
*
* @param AssemblyReference The full path to the assembly file on disk
* /
public void AddDotNetAssemblyReference ( string AssemblyReference )
{
if ( ! DotNetAssemblyReferences . Contains ( AssemblyReference ) )
{
DotNetAssemblyReferences . Add ( AssemblyReference ) ;
}
}
/ * *
* Adds a C # assembly reference to this project , such as a third party assembly needed for this project to compile
*
* @param AssemblyReference The full path to the assembly file on disk
* /
public void AddAssemblyReference ( string AssemblyReference )
{
AssemblyReferences . Add ( AssemblyReference ) ;
}
/// <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 +
"<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append (
"<Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />" +
ProjectFileGenerator . NewLine ) ;
// 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 +
"\t<TreatWarningsAsErrors>true</TreatWarningsAsErrors>" + ProjectFileGenerator . NewLine +
"</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 )
{
ProjectFileContent . Append ( "\t<Reference Include=\"" + CurReference + "\" />" + ProjectFileGenerator . NewLine ) ;
}
ProjectFileContent . Append ( "</ItemGroup>" + ProjectFileGenerator . NewLine ) ;
}
// External or third party assembly references
if ( AssemblyReferences . Count > 0 )
{
ProjectFileContent . Append ( "<ItemGroup>" + ProjectFileGenerator . NewLine ) ;
foreach ( var CurReference in AssemblyReferences )
{
ProjectFileContent . Append ( "\t<Reference Include=\"" + Path . GetFileNameWithoutExtension ( CurReference ) + "\" >" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append ( "\t\t<HintPath>" + Utils . MakePathRelativeTo ( CurReference , Path . GetDirectoryName ( ProjectFilePath ) ) + "</HintPath>" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append ( "\t</Reference>" + ProjectFileGenerator . NewLine ) ;
}
ProjectFileContent . Append ( "</ItemGroup>" + ProjectFileGenerator . NewLine ) ;
}
// Other references (note it's assumed all references here are at least of MSBuildProjectFile type.
foreach ( var Project in DependsOnProjects )
{
var RelativePath = Utils . MakePathRelativeTo ( Path . GetDirectoryName ( Project . ProjectFilePath ) , Path . GetDirectoryName ( ProjectFilePath ) ) ;
RelativePath = Path . Combine ( RelativePath , Path . GetFileName ( Project . ProjectFilePath ) ) ;
ProjectFileContent . Append (
"<ItemGroup>" + ProjectFileGenerator . NewLine +
"<ProjectReference Include=\"" + RelativePath + "\">" + ProjectFileGenerator . NewLine +
"<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 (
" <ItemGroup>" + ProjectFileGenerator . NewLine ) ;
// Add all files to the project.
foreach ( var CurFile in SourceFiles )
{
var ProjectRelativeSourceFile = Utils . MakePathRelativeTo ( CurFile . FilePath , Path . GetDirectoryName ( ProjectFilePath ) ) ;
ProjectFileContent . Append (
" <Compile Include=\"" + ProjectRelativeSourceFile + "\" />" + ProjectFileGenerator . NewLine ) ;
}
ProjectFileContent . Append (
" </ItemGroup>" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append (
"<Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />" + ProjectFileGenerator . NewLine ) ;
ProjectFileContent . Append (
"</Project>" + ProjectFileGenerator . NewLine ) ;
// Save the project file
if ( bSuccess )
{
bSuccess = ProjectFileGenerator . WriteFileIfChanged ( ProjectFilePath , ProjectFileContent . ToString ( ) ) ;
}
return bSuccess ;
}
/// Assemblies this project is dependent on
protected readonly List < string > AssemblyReferences = new List < string > ( ) ;
/// 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>
public VSHFBProjectFile ( string InitFilePath )
: base ( InitFilePath )
{
}
}
}