Ejemplo n.º 1
0
        protected void AddPrerequisiteSourceFile(UEBuildTarget Target, IUEBuildPlatform BuildPlatform, CPPEnvironment CompileEnvironment, FileItem SourceFile, List <FileItem> PrerequisiteItems)
        {
            PrerequisiteItems.Add(SourceFile);

            var  RemoteThis      = this as RemoteToolChain;
            bool bAllowUploading = RemoteThis != null && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac;                // Don't use remote features when compiling from a Mac

            if (bAllowUploading)
            {
                RemoteThis.QueueFileForBatchUpload(SourceFile);
            }

            if (!BuildConfiguration.bUseExperimentalFastBuildIteration)                 // In fast build iteration mode, we'll gather includes later on
            {
                // @todo fastubt: What if one of the prerequisite files has become missing since it was updated in our cache? (usually, because a coder eliminated the source file)
                //		-> Two CASES:
                //				1) NOT WORKING: Non-unity file went away (SourceFile in this context).  That seems like an existing old use case.  Compile params or Response file should have changed?
                //				2) WORKING: Indirect file went away (unity'd original source file or include).  This would return a file that no longer exists and adds to the prerequiteitems list
                var IncludedFileList = CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CompileEnvironment.Config.CPPIncludeInfo, bOnlyCachedDependencies: BuildConfiguration.bUseExperimentalFastDependencyScan);
                foreach (FileItem IncludedFile in IncludedFileList)
                {
                    PrerequisiteItems.Add(IncludedFile);

                    if (bAllowUploading &&
                        !BuildConfiguration.bUseExperimentalFastDependencyScan)                                 // With fast dependency scanning, we will not have an exhaustive list of dependencies here.  We rely on PostCodeGeneration() to upload these files.
                    {
                        RemoteThis.QueueFileForBatchUpload(IncludedFile);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        private static FileItem CachePCHUsageForCPPFile(UEBuildTarget Target, FileItem CPPFile, IUEBuildPlatform BuildPlatform, List<string> IncludePathsToSearch, Dictionary<string, FileItem> IncludeFileSearchDictionary)
        {
            // @todo ubtmake: We don't really need to scan every file looking for PCH headers, just need one.  The rest is just for error checking.
            // @todo ubtmake: We don't need all of the direct includes either.  We just need the first, unless we want to check for errors.
            List<DependencyInclude> DirectIncludeFilenames = CPPEnvironment.GetDirectIncludeDependencies(Target, CPPFile, BuildPlatform, bOnlyCachedDependencies:false);
            if (BuildConfiguration.bPrintDebugInfo)
            {
                Log.TraceVerbose("Found direct includes for {0}: {1}", Path.GetFileName(CPPFile.AbsolutePath), string.Join(", ", DirectIncludeFilenames.Select(F => F.IncludeName)));
            }

            if (DirectIncludeFilenames.Count == 0)
            {
                return null;
            }

            var FirstInclude = DirectIncludeFilenames[0];

            // The pch header should always be the first include in the source file.
            // NOTE: This is not an absolute path.  This is just the literal include string from the source file!
            CPPFile.PCHHeaderNameInCode = FirstInclude.IncludeName;

            // Resolve the PCH header to an absolute path.
            // Check NullOrEmpty here because if the file could not be resolved we need to throw an exception
            if (!string.IsNullOrEmpty(FirstInclude.IncludeResolvedName) &&
                // ignore any preexisting resolve cache if we are not configured to use it.
                BuildConfiguration.bUseIncludeDependencyResolveCache &&
                // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                !BuildConfiguration.bTestIncludeDependencyResolveCache)
            {
                CPPFile.PrecompiledHeaderIncludeFilename = FirstInclude.IncludeResolvedName;
                return FileItem.GetItemByFullPath(CPPFile.PrecompiledHeaderIncludeFilename);
            }

            // search the include paths to resolve the file.
            FileItem PrecompiledHeaderIncludeFile = CPPEnvironment.FindIncludedFile(CPPFile.PCHHeaderNameInCode, !BuildConfiguration.bCheckExternalHeadersForModification, IncludePathsToSearch, IncludeFileSearchDictionary );
            if (PrecompiledHeaderIncludeFile == null)
            {
                throw new BuildException("The first include statement in source file '{0}' is trying to include the file '{1}' as the precompiled header, but that file could not be located in any of the module's include search paths.", CPPFile.AbsolutePath, CPPFile.PCHHeaderNameInCode);
            }

            CPPEnvironment.IncludeDependencyCache[Target].CacheResolvedIncludeFullPath(CPPFile, 0, PrecompiledHeaderIncludeFile.AbsolutePath);
            CPPFile.PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFile.AbsolutePath;

            return PrecompiledHeaderIncludeFile;
        }
Ejemplo n.º 3
0
        private static bool RequiresTempTarget(string RawProjectPath, List <UnrealTargetPlatform> ClientTargetPlatforms)
        {
            // check to see if we already have a Target.cs file
            // @todo: Target.cs may not be the same name as the project in the future, so look at a better way to determine this
            if (File.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath), "Source", Path.GetFileNameWithoutExtension(RawProjectPath) + ".Target.cs")))
            {
                return(false);
            }

            // no Target file, now check to see if build settings have changed
            List <UnrealTargetPlatform> TargetPlatforms = ClientTargetPlatforms;

            if (ClientTargetPlatforms == null || ClientTargetPlatforms.Count < 1)
            {
                // No client target platforms, add all in
                TargetPlatforms = new List <UnrealTargetPlatform>();
                foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform)))
                {
                    if (TargetPlatformType != UnrealTargetPlatform.Unknown)
                    {
                        TargetPlatforms.Add(TargetPlatformType);
                    }
                }
            }

            // check the target platforms for any differences in build settings or additional plugins
            foreach (UnrealTargetPlatform TargetPlatformType in TargetPlatforms)
            {
                IUEBuildPlatform BuildPlat = UEBuildPlatform.GetBuildPlatform(TargetPlatformType, true);
                if (BuildPlat != null && !(BuildPlat as UEBuildPlatform).HasDefaultBuildConfig(TargetPlatformType, Path.GetDirectoryName(RawProjectPath)))
                {
                    return(true);
                }
                // find if there are any plugins
                List <string> PluginList = new List <string>();
                // Use the project settings to update the plugin list for this target
                PluginList = UProjectInfo.GetEnabledPlugins(RawProjectPath, PluginList, TargetPlatformType);
                if (PluginList.Count > 0)
                {
                    foreach (var PluginName in PluginList)
                    {
                        // check the plugin info for this plugin itself
                        foreach (var Plugin in Plugins.AllPlugins)
                        {
                            if (Plugin.Name == PluginName)
                            {
                                foreach (var Module in Plugin.Modules)
                                {
                                    if (Module.Platforms.Count > 0 && Module.Platforms.Contains(TargetPlatformType))
                                    {
                                        return(true);
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
            return(false);
        }
Ejemplo n.º 4
0
		protected void AddPrerequisiteSourceFile( UEBuildTarget Target, IUEBuildPlatform BuildPlatform, CPPEnvironment CompileEnvironment, FileItem SourceFile, List<FileItem> PrerequisiteItems )
		{
			PrerequisiteItems.Add( SourceFile );

			var RemoteThis = this as RemoteToolChain;
			bool bAllowUploading = RemoteThis != null && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac;	// Don't use remote features when compiling from a Mac
			if( bAllowUploading )
			{
				RemoteThis.QueueFileForBatchUpload(SourceFile);
			}

			if( !BuildConfiguration.bUseUBTMakefiles )	// In fast build iteration mode, we'll gather includes later on
			{
				// @todo ubtmake: What if one of the prerequisite files has become missing since it was updated in our cache? (usually, because a coder eliminated the source file)
				//		-> Two CASES:
				//				1) NOT WORKING: Non-unity file went away (SourceFile in this context).  That seems like an existing old use case.  Compile params or Response file should have changed?
				//				2) WORKING: Indirect file went away (unity'd original source file or include).  This would return a file that no longer exists and adds to the prerequiteitems list
				var IncludedFileList = CPPEnvironment.FindAndCacheAllIncludedFiles( Target, SourceFile, BuildPlatform, CompileEnvironment.Config.CPPIncludeInfo, bOnlyCachedDependencies:BuildConfiguration.bUseUBTMakefiles );
				if( IncludedFileList != null )
				{
					foreach (FileItem IncludedFile in IncludedFileList)
					{
						PrerequisiteItems.Add( IncludedFile );

						if( bAllowUploading &&
							!BuildConfiguration.bUseUBTMakefiles )	// With fast dependency scanning, we will not have an exhaustive list of dependencies here.  We rely on PostCodeGeneration() to upload these files.
						{
							RemoteThis.QueueFileForBatchUpload(IncludedFile);
						}
					}
				}
			}
		}
Ejemplo n.º 5
0
        /** Finds the names of files directly included by the given C++ file. */
        public static List <DependencyInclude> GetDirectIncludeDependencies(UEBuildTarget Target, FileItem CPPFile, IUEBuildPlatform BuildPlatform, bool bOnlyCachedDependencies, out bool HasUObjects)
        {
            // Try to fulfill request from cache first.
            List <DependencyInclude> Result;

            if (IncludeDependencyCache[Target].GetCachedDirectDependencies(CPPFile, out Result, out HasUObjects))
            {
                return(Result);
            }
            else if (bOnlyCachedDependencies)
            {
                return(new List <DependencyInclude>());
            }

            var TimerStartTime = DateTime.UtcNow;

            ++CPPEnvironment.TotalDirectIncludeCacheMisses;

            // Get the adjusted filename
            string FileToRead = CPPFile.AbsolutePath;

            if (BuildPlatform.RequiresExtraUnityCPPWriter() == true &&
                Path.GetFileName(FileToRead).StartsWith("Module."))
            {
                FileToRead += ".ex";
            }

            // Read lines from the C++ file.
            string FileContents = Utils.ReadAllText(FileToRead);

            if (string.IsNullOrEmpty(FileContents))
            {
                return(new List <DependencyInclude>());
            }

            HasUObjects = CPPEnvironment.UObjectRegex.IsMatch(FileContents);

            // Note: This depends on UBT executing w/ a working directory of the Engine/Source folder!
            string EngineSourceFolder = Directory.GetCurrentDirectory();
            string InstalledFolder    = EngineSourceFolder;
            Int32  EngineSourceIdx    = EngineSourceFolder.IndexOf("\\Engine\\Source");

            if (EngineSourceIdx != -1)
            {
                InstalledFolder = EngineSourceFolder.Substring(0, EngineSourceIdx);
            }

            Result = new List <DependencyInclude>();
            if (Utils.IsRunningOnMono)
            {
                // Mono crashes when running a regex on a string longer than about 5000 characters, so we parse the file in chunks
                int       StartIndex     = 0;
                const int SafeTextLength = 4000;
                while (StartIndex < FileContents.Length)
                {
                    int EndIndex = StartIndex + SafeTextLength < FileContents.Length ? FileContents.IndexOf("\n", StartIndex + SafeTextLength) : FileContents.Length;
                    if (EndIndex == -1)
                    {
                        EndIndex = FileContents.Length;
                    }

                    CollectHeaders(CPPFile, Result, FileToRead, FileContents, InstalledFolder, StartIndex, EndIndex);

                    StartIndex = EndIndex + 1;
                }
            }
            else
            {
                CollectHeaders(CPPFile, Result, FileToRead, FileContents, InstalledFolder, 0, FileContents.Length);
            }

            // Populate cache with results.
            IncludeDependencyCache[Target].SetDependencyInfo(CPPFile, Result, HasUObjects);

            CPPEnvironment.DirectIncludeCacheMissesTotalTime += (DateTime.UtcNow - TimerStartTime).TotalSeconds;

            return(Result);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Finds the files directly or indirectly included by the given C++ file.
        /// </summary>
        /// <param name="CPPFile">C++ file to get the dependencies for.</param>
        /// <param name="Result">List of CPPFile dependencies.</param>
        /// <returns>false if CPPFile is still being processed further down the callstack, true otherwise.</returns>
        public static bool FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem CPPFile, IUEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, ref IncludedFilesSet Result, bool bOnlyCachedDependencies)
        {
            IncludedFilesSet IncludedFileList;
            var IncludedFilesMap = bOnlyCachedDependencies ? OnlyCachedIncludedFilesMap : ExhaustiveIncludedFilesMap;

            if (!IncludedFilesMap.TryGetValue(CPPFile, out IncludedFileList))
            {
                var TimerStartTime = DateTime.UtcNow;

                IncludedFileList = new IncludedFilesSet();

                // Add an uninitialized entry for the include file to avoid infinitely recursing on include file loops.
                IncludedFilesMap.Add(CPPFile, IncludedFileList);

                // Gather a list of names of files directly included by this C++ file.
                bool HasUObjects;
                List <DependencyInclude> DirectIncludes = GetDirectIncludeDependencies(Target, CPPFile, BuildPlatform, bOnlyCachedDependencies: bOnlyCachedDependencies, HasUObjects: out HasUObjects);

                // Build a list of the unique set of files that are included by this file.
                var DirectlyIncludedFiles = new HashSet <FileItem>();
                // require a for loop here because we need to keep track of the index in the list.
                for (int DirectlyIncludedFileNameIndex = 0; DirectlyIncludedFileNameIndex < DirectIncludes.Count; ++DirectlyIncludedFileNameIndex)
                {
                    // Resolve the included file name to an actual file.
                    DependencyInclude DirectInclude = DirectIncludes[DirectlyIncludedFileNameIndex];
                    if (DirectInclude.IncludeResolvedName == null ||
                        // ignore any preexisting resolve cache if we are not configured to use it.
                        !BuildConfiguration.bUseIncludeDependencyResolveCache ||
                        // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                        BuildConfiguration.bTestIncludeDependencyResolveCache
                        )
                    {
                        ++TotalDirectIncludeResolveCacheMisses;

                        // search the include paths to resolve the file
                        FileItem DirectIncludeResolvedFile = CPPEnvironment.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, CPPIncludeInfo.GetIncludesPathsToSearch(CPPFile), CPPIncludeInfo.IncludeFileSearchDictionary);
                        if (DirectIncludeResolvedFile != null)
                        {
                            DirectlyIncludedFiles.Add(DirectIncludeResolvedFile);
                        }
                        IncludeDependencyCache[Target].CacheResolvedIncludeFullPath(CPPFile, DirectlyIncludedFileNameIndex, DirectIncludeResolvedFile != null ? DirectIncludeResolvedFile.AbsolutePath : "");
                    }
                    else
                    {
                        // we might have cached an attempt to resolve the file, but couldn't actually find the file (system headers, etc).
                        if (DirectInclude.IncludeResolvedName != string.Empty)
                        {
                            DirectlyIncludedFiles.Add(FileItem.GetItemByFullPath(DirectInclude.IncludeResolvedName));
                        }
                    }
                }
                TotalDirectIncludeResolves += DirectIncludes.Count;

                // Convert the dictionary of files included by this file into a list.
                foreach (var DirectlyIncludedFile in DirectlyIncludedFiles)
                {
                    // Add the file we're directly including
                    IncludedFileList.Add(DirectlyIncludedFile);

                    // Also add all of the indirectly included files!
                    if (FindAndCacheAllIncludedFiles(Target, DirectlyIncludedFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies:bOnlyCachedDependencies) == false)
                    {
                        // DirectlyIncludedFile is a circular dependency which is still being processed
                        // further down the callstack. Add this file to its circular dependencies list
                        // so that it can update its dependencies later.
                        IncludedFilesSet DirectlyIncludedFileIncludedFileList;
                        if (IncludedFilesMap.TryGetValue(DirectlyIncludedFile, out DirectlyIncludedFileIncludedFileList))
                        {
                            DirectlyIncludedFileIncludedFileList.CircularDependencies.Add(CPPFile);
                        }
                    }
                }

                // All dependencies have been processed by now so update all circular dependencies
                // with the full list.
                foreach (var CircularDependency in IncludedFileList.CircularDependencies)
                {
                    IncludedFilesSet CircularDependencyIncludedFiles = IncludedFilesMap[CircularDependency];
                    foreach (FileItem IncludedFile in IncludedFileList)
                    {
                        CircularDependencyIncludedFiles.Add(IncludedFile);
                    }
                }
                // No need to keep this around anymore.
                IncludedFileList.CircularDependencies.Clear();

                // Done collecting files.
                IncludedFileList.bIsInitialized = true;

                var TimerDuration = DateTime.UtcNow - TimerStartTime;
                TotalTimeSpentGettingIncludes += TimerDuration.TotalSeconds;
            }

            if (IncludedFileList.bIsInitialized)
            {
                // Copy the list of files included by this file into the result list.
                foreach (FileItem IncludedFile in IncludedFileList)
                {
                    // If the result list doesn't contain this file yet, add the file and the files it includes.
                    // NOTE: For some reason in .NET 4, Add() is over twice as fast as calling UnionWith() on the set
                    Result.Add(IncludedFile);
                }

                return(true);
            }
            else
            {
                // The IncludedFileList.bIsInitialized was false because we added a dummy entry further down the call stack.  We're already processing
                // the include list for this header elsewhere in the stack frame, so we don't need to add anything here.
                return(false);
            }
        }
Ejemplo n.º 7
0
        public static List <FileItem> FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem SourceFile, IUEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, bool bOnlyCachedDependencies)
        {
            List <FileItem> Result = null;

            if (CPPIncludeInfo.IncludeFileSearchDictionary == null)
            {
                CPPIncludeInfo.IncludeFileSearchDictionary = new Dictionary <string, FileItem>();
            }

            bool bUseFlatCPPIncludeDependencyCache = BuildConfiguration.bUseUBTMakefiles && UnrealBuildTool.IsAssemblingBuild;

            if (bOnlyCachedDependencies && bUseFlatCPPIncludeDependencyCache)
            {
                Result = FlatCPPIncludeDependencyCache[Target].GetDependenciesForFile(SourceFile.AbsolutePath);
                if (Result == null)
                {
                    // Nothing cached for this file!  It is new to us.  This is the expected flow when our CPPIncludeDepencencyCache is missing.
                }
            }
            else
            {
                // @todo ubtmake: HeaderParser.h is missing from the include set for Module.UnrealHeaderTool.cpp (failed to find include using:  FileItem DirectIncludeResolvedFile = CPPEnvironment.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, IncludePathsToSearch, IncludeFileSearchDictionary );)

                // If we're doing an exhaustive include scan, make sure that we have our include dependency cache loaded and ready
                if (!bOnlyCachedDependencies)
                {
                    if (!IncludeDependencyCache.ContainsKey(Target))
                    {
                        IncludeDependencyCache.Add(Target, DependencyCache.Create(DependencyCache.GetDependencyCachePathForTarget(Target)));
                    }
                }

                Result = new List <FileItem>();

                var IncludedFileList = new IncludedFilesSet();
                CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies: bOnlyCachedDependencies);
                foreach (FileItem IncludedFile in IncludedFileList)
                {
                    Result.Add(IncludedFile);
                }

                // Update cache
                if (bUseFlatCPPIncludeDependencyCache && !bOnlyCachedDependencies)
                {
                    var Dependencies = new List <string>();
                    foreach (var IncludedFile in Result)
                    {
                        Dependencies.Add(IncludedFile.AbsolutePath);
                    }
                    string PCHName = SourceFile.PrecompiledHeaderIncludeFilename;
                    FlatCPPIncludeDependencyCache[Target].SetDependenciesForFile(SourceFile.AbsolutePath, PCHName, Dependencies);
                }
            }

            return(Result);
        }
Ejemplo n.º 8
0
        public static List <FileItem> FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem SourceFile, IUEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, bool bOnlyCachedDependencies)
        {
            var Result = new List <FileItem>();

            if (CPPIncludeInfo.IncludeFileSearchDictionary == null)
            {
                CPPIncludeInfo.IncludeFileSearchDictionary = new Dictionary <string, FileItem>();
            }

            bool bUseFlatCPPIncludeDependencyCache =
                (BuildConfiguration.bUseExperimentalFastDependencyScan &&
                 (!BuildConfiguration.bUseExperimentalFastBuildIteration || UnrealBuildTool.IsAssemblingBuild));

            if (bUseFlatCPPIncludeDependencyCache && bOnlyCachedDependencies)
            {
                var Dependencies = FlatCPPIncludeDependencyCache[Target].GetDependenciesForFile(SourceFile.AbsolutePath);
                if (Dependencies != null)
                {
                    foreach (string Dependency in Dependencies)
                    {
                        Result.Add(FileItem.GetItemByFullPath(Dependency));                             // @todo fastubt: Make sure this is as fast as possible (convert to FileItem)
                    }
                }
                else
                {
                    // Nothing cached for this file!  It is new to us.  This is the expected flow when our CPPIncludeDepencencyCache is missing.
                }
            }
            else
            {
                // @todo fastubt: HeaderParser.h is missing from the include set for Module.UnrealHeaderTool.cpp (failed to find include using:  FileItem DirectIncludeResolvedFile = CPPEnvironment.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, IncludePathsToSearch, IncludeFileSearchDictionary );)

                var IncludedFileList = new IncludedFilesSet();
                CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies: bOnlyCachedDependencies);
                foreach (FileItem IncludedFile in IncludedFileList)
                {
                    Result.Add(IncludedFile);
                }

                // Update cache
                if (bUseFlatCPPIncludeDependencyCache && !bOnlyCachedDependencies)
                {
                    var Dependencies = new List <string>();
                    foreach (var IncludedFile in Result)
                    {
                        Dependencies.Add(IncludedFile.AbsolutePath);
                    }
                    string PCHName = SourceFile.PrecompiledHeaderIncludeFilename;
                    FlatCPPIncludeDependencyCache[Target].SetDependenciesForFile(SourceFile.AbsolutePath, PCHName, Dependencies);
                }
            }

            return(Result);
        }
Ejemplo n.º 9
0
        private static bool RequiresTempTarget(string RawProjectPath, List <UnrealTargetPlatform> ClientTargetPlatforms)
        {
            // check to see if we already have a Target.cs file
            if (File.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath), "Source", Path.GetFileNameWithoutExtension(RawProjectPath) + ".Target.cs")))
            {
                return(false);
            }
            else if (Directory.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath), "Source")))
            {
                // wasn't one in the main Source directory, let's check all sub-directories
                //@todo: may want to read each target.cs to see if it has a target corresponding to the project name as a final check
                FileInfo[] Files = (new DirectoryInfo(Path.Combine(Path.GetDirectoryName(RawProjectPath), "Source")).GetFiles("*.Target.cs", SearchOption.AllDirectories));
                if (Files.Length > 0)
                {
                    return(false);
                }
            }

            // no Target file, now check to see if build settings have changed
            List <UnrealTargetPlatform> TargetPlatforms = ClientTargetPlatforms;

            if (ClientTargetPlatforms == null || ClientTargetPlatforms.Count < 1)
            {
                // No client target platforms, add all in
                TargetPlatforms = new List <UnrealTargetPlatform>();
                foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform)))
                {
                    if (TargetPlatformType != UnrealTargetPlatform.Unknown)
                    {
                        TargetPlatforms.Add(TargetPlatformType);
                    }
                }
            }

            // Change the working directory to be the Engine/Source folder. We are running from Engine/Binaries/DotNET
            string oldCWD = Directory.GetCurrentDirectory();

            if (BuildConfiguration.RelativeEnginePath == "../../Engine/")
            {
                string EngineSourceDirectory = Path.Combine(UnrealBuildTool.Utils.GetExecutingAssemblyDirectory(), "..", "..", "..", "Engine", "Source");
                if (!Directory.Exists(EngineSourceDirectory))                 // only set the directory if it exists, this should only happen if we are launching the editor from an artist sync
                {
                    EngineSourceDirectory = Path.Combine(UnrealBuildTool.Utils.GetExecutingAssemblyDirectory(), "..", "..", "..", "Engine", "Binaries");
                }
                Directory.SetCurrentDirectory(EngineSourceDirectory);
            }

            // Read the project descriptor, and find all the plugins available to this project
            ProjectDescriptor Project          = ProjectDescriptor.FromFile(RawProjectPath);
            List <PluginInfo> AvailablePlugins = Plugins.ReadAvailablePlugins(RawProjectPath);

            // check the target platforms for any differences in build settings or additional plugins
            bool RetVal = false;

            foreach (UnrealTargetPlatform TargetPlatformType in TargetPlatforms)
            {
                IUEBuildPlatform BuildPlat = UEBuildPlatform.GetBuildPlatform(TargetPlatformType, true);
                if (!GlobalCommandLine.Rocket && BuildPlat != null && !(BuildPlat as UEBuildPlatform).HasDefaultBuildConfig(TargetPlatformType, Path.GetDirectoryName(RawProjectPath)))
                {
                    RetVal = true;
                    break;
                }

                // find if there are any plugins enabled or disabled which differ from the default
                foreach (PluginInfo Plugin in AvailablePlugins)
                {
                    bool bPluginEnabledForProject = UProjectInfo.IsPluginEnabledForProject(Plugin, Project, TargetPlatformType);
                    if ((bPluginEnabledForProject && !Plugin.Descriptor.bEnabledByDefault) || (bPluginEnabledForProject && Plugin.Descriptor.bInstalled))
                    {
                        if (Plugin.Descriptor.Modules.Any(Module => Module.IsCompiledInConfiguration(TargetPlatformType, TargetRules.TargetType.Game, bBuildDeveloperTools: false, bBuildEditor: false)))
                        {
                            RetVal = true;
                            break;
                        }
                    }
                }
            }

            // Change back to the original directory
            Directory.SetCurrentDirectory(oldCWD);
            return(RetVal);
        }