示例#1
0
        /**
         * Generates debug info for a given executable
         *
         * @param Executable FileItem describing the executable to generate debug info for
         */
        public static FileItem GenerateDebugInfo(FileItem Executable)
        {
            // Make a file item for the source and destination files
            string FullDestPathRoot = Executable.AbsolutePath + ".app.dSYM";
            string FullDestPath = FullDestPathRoot;
            FileItem DestFile = FileItem.GetRemoteItemByPath(FullDestPath, UnrealTargetPlatform.IOS);

            // Make the compile action
            Action GenDebugAction = new Action(ActionType.GenerateDebugInfo);
            if (!Utils.IsRunningOnMono)
            {
                GenDebugAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
            }
            GenDebugAction.WorkingDirectory = GetMacDevSrcRoot();
            GenDebugAction.CommandPath = "sh";

            // note that the source and dest are switched from a copy command
            GenDebugAction.CommandArguments = string.Format("-c '{0}/usr/bin/dsymutil {1} -o {2}; cd {2}/..; zip -r -y -1 {3}.app.dSYM.zip {3}.app.dSYM'",
                DeveloperDir,
                Executable.AbsolutePath,
                FullDestPathRoot,
                Path.GetFileName(Executable.AbsolutePath));
            GenDebugAction.PrerequisiteItems.Add(Executable);
            GenDebugAction.ProducedItems.Add(DestFile);
            GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath));
            GenDebugAction.bCanExecuteRemotely = false;

            return DestFile;
        }
		/// <summary>
		/// Loads the cache from disk
		/// </summary>
		/// <param name="Cache">The file to load</param>
		/// <returns>The loaded instance</returns>
		public static FlatCPPIncludeDependencyCache Load(FileItem Cache)
		{
			FlatCPPIncludeDependencyCache Result = null;
			try
			{
				using (FileStream Stream = new FileStream(Cache.AbsolutePath, FileMode.Open, FileAccess.Read))
				{	
					// @todo ubtmake: We can store the cache in a cheaper/smaller way using hash file names and indices into included headers, but it might actually slow down load times
					// @todo ubtmake: If we can index PCHs here, we can avoid storing all of the PCH's included headers (PCH's action should have been invalidated, so we shouldn't even have to report the PCH's includes as our indirect includes)
					BinaryFormatter Formatter = new BinaryFormatter();
					Result = Formatter.Deserialize(Stream) as FlatCPPIncludeDependencyCache;
					Result.CacheFileItem = Cache;
					Result.bIsDirty = false;
				}
			}
			catch (Exception Ex)
			{
				// Don't bother failing if the file format has changed, simply abort the cache load
				if (Ex.Message.Contains( "cannot be converted to type" ))	// To catch serialization differences added when we added the DependencyInfo struct
				{
					Console.Error.WriteLine("Failed to read FlatCPPIncludeDependencyCache: {0}", Ex.Message);
				}
			}
			return Result;
		}
示例#3
0
 public PrecompileHeaderEnvironment( string InitModuleName, string InitPCHHeaderNameInCode, FileItem InitPrecompiledHeaderIncludeFilename, CPPCLRMode InitCLRMode, ModuleRules.CodeOptimization InitOptimizeCode )
 {
     ModuleName = InitModuleName;
     PCHHeaderNameInCode = InitPCHHeaderNameInCode;
     PrecompiledHeaderIncludeFilename = InitPrecompiledHeaderIncludeFilename;
     CLRMode = InitCLRMode;
     OptimizeCode = InitOptimizeCode;
 }
示例#4
0
			public void AddFile(FileItem File)
			{
				Files.Add(File);

				long FileLength = File.Info.Length;
				TotalLength += FileLength;
				VirtualLength += FileLength;
			}
示例#5
0
			/// <summary>
			/// Adds a file to the current unity file.  If splitting is required and the total size of the
			/// unity file exceeds the split limit, then a new file is automatically started.
			/// </summary>
			/// <param name="File">The file to add.</param>
			public void AddFile(FileItem File)
			{
				CurrentCollection.AddFile(File);
				if (SplitLength != -1 && CurrentCollection.TotalLength > SplitLength)
				{
					EndCurrentUnityFile();
				}
			}
示例#6
0
 /**
  * Constructor
  *
  * @param	Cache	File associated with this cache
  */
 protected DependencyCache(FileItem Cache)
 {
     CacheCreateDate = DateTimeOffset.Now;
     CacheUpdateDate = DateTimeOffset.Now;
     CachePath = Cache.AbsolutePath;
     DependencyMap = new Dictionary<string, DependencyInfo>();
     bIsDirty = false;
     CreateFileExistsInfo();
 }
 /**
  * Constructor
  *
  * @param	Cache	File associated with this cache
  */
 protected DependencyCache(FileItem Cache)
 {
     CacheCreateDate = DateTimeOffset.Now;
     CacheUpdateDate = DateTimeOffset.Now;
     CachePath = Cache.AbsolutePath;
     DependencyMap = new Dictionary<string, DependencyInfo>(StringComparer.InvariantCultureIgnoreCase);
     bIsDirty = false;
     CreateFileExistsInfo();
 }
示例#8
0
文件: IOSToolChain.cs 项目: mymei/UE4
        /**
         * Generates debug info for a given executable
         *
         * @param Executable FileItem describing the executable to generate debug info for
         */
        public static FileItem GenerateDebugInfo(FileItem Executable)
        {
            // Make a file item for the source and destination files
            string FullDestPathRoot = Executable.AbsolutePath + ".dSYM";
            string FullDestPath = FullDestPathRoot;

            FileItem DestFile;
            if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                DestFile = FileItem.GetRemoteItemByPath (FullDestPath, UnrealTargetPlatform.IOS);
            }
            else
            {
                DestFile = FileItem.GetItemByPath (FullDestPath);
            }

            // Make the compile action
            Action GenDebugAction = new Action(ActionType.GenerateDebugInfo);
            if (!Utils.IsRunningOnMono)
            {
                GenDebugAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
            }

            IOSToolChain Toolchain = UEToolChain.GetPlatformToolChain(CPPTargetPlatform.IOS) as IOSToolChain;
            GenDebugAction.WorkingDirectory = Toolchain.GetMacDevSrcRoot();
            GenDebugAction.CommandPath = "sh";

            // note that the source and dest are switched from a copy command
            if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                GenDebugAction.CommandArguments = string.Format("-c '/usr/bin/dsymutil \"{0}\" -f -o \"{1}\"; cd \"{1}/..\"; zip -r -y -1 {2}.dSYM.zip {2}.dSYM'",
                    Executable.AbsolutePath,
                    FullDestPathRoot,
                    Path.GetFileName(Executable.AbsolutePath));
            }
            else
            {
                GenDebugAction.CommandArguments = string.Format("-c '/usr/bin/dsymutil \"{0}\" -f -o \"{1}\"'",
                    Executable.AbsolutePath,
                    FullDestPathRoot);
            }

            GenDebugAction.PrerequisiteItems.Add(Executable);
            GenDebugAction.ProducedItems.Add(DestFile);
            GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath));
            GenDebugAction.bCanExecuteRemotely = false;

            return DestFile;
        }
示例#9
0
        public static void BatchFileInfo(FileItem[] Files)
        {
            // build a list of file paths to get info about
            StringBuilder FileList = new StringBuilder();
            foreach (FileItem File in Files)
            {
                FileList.AppendFormat("{0}\n", File.AbsolutePath);
            }

            // execute the command!
            Int64[] FileSizeAndDates = RPCUtility.CommandHelper.RPCBatchFileInfo(GetSocket(), FileList.ToString());

            // now update the source times
            for (int Index = 0; Index < Files.Length; Index++)
            {
                Files[Index].Length = FileSizeAndDates[Index * 2 + 0];
                Files[Index].LastWriteTime = new DateTimeOffset(RPCUtility.CommandHelper.FromRemoteTime(FileSizeAndDates[Index * 2 + 1]));
                Files[Index].bExists = FileSizeAndDates[Index * 2 + 0] >= 0;
            }
        }
示例#10
0
        /// <summary>
        /// Get the name of the response file for the current linker environment and output file
        /// </summary>
        /// <param name="LinkEnvironment"></param>
        /// <param name="OutputFile"></param>
        /// <returns></returns>
        public static string GetResponseFileName( LinkEnvironment LinkEnvironment, FileItem OutputFile )
        {
            // Construct a relative path for the intermediate response file
            string ResponseFileName = Path.Combine( LinkEnvironment.Config.IntermediateDirectory, Path.GetFileName( OutputFile.AbsolutePath ) + ".response" );
            if (UnrealBuildTool.HasUProjectFile())
            {
                // If this is the uproject being built, redirect the intermediate
                if (Utils.IsFileUnderDirectory( OutputFile.AbsolutePath, UnrealBuildTool.GetUProjectPath() ))
                {
                    ResponseFileName = Path.Combine(
                        UnrealBuildTool.GetUProjectPath(),
                        BuildConfiguration.PlatformIntermediateFolder,
                        Path.GetFileNameWithoutExtension(UnrealBuildTool.GetUProjectFile()),
                        LinkEnvironment.Config.TargetConfiguration.ToString(),
                        Path.GetFileName(OutputFile.AbsolutePath) + ".response");
                }
            }
            // Convert the relative path to an absolute path
            ResponseFileName = Path.GetFullPath( ResponseFileName );

            return ResponseFileName;
        }
		/// <summary>
		/// Loads the cache from disk
		/// </summary>
		/// <param name="Cache">The file to load</param>
		/// <returns>The loaded instance</returns>
		public static FlatCPPIncludeDependencyCache Load(FileItem Cache)
		{
			FlatCPPIncludeDependencyCache Result = null;
			try
			{
				string CacheBuildMutexPath = Cache.AbsolutePath + ".buildmutex";

				// If the .buildmutex file for the cache is present, it means that something went wrong between loading
				// and saving the cache last time (most likely the UBT process being terminated), so we don't want to load
				// it.
				if (!File.Exists(CacheBuildMutexPath))
				{
					using (File.Create(CacheBuildMutexPath))
					{
					}

					using (FileStream Stream = new FileStream(Cache.AbsolutePath, FileMode.Open, FileAccess.Read))
					{
						// @todo ubtmake: We can store the cache in a cheaper/smaller way using hash file names and indices into included headers, but it might actually slow down load times
						// @todo ubtmake: If we can index PCHs here, we can avoid storing all of the PCH's included headers (PCH's action should have been invalidated, so we shouldn't even have to report the PCH's includes as our indirect includes)
						BinaryFormatter Formatter = new BinaryFormatter();
						Result = Formatter.Deserialize(Stream) as FlatCPPIncludeDependencyCache;
						Result.CacheFileItem = Cache;
						Result.bIsDirty = false;
					}
				}
			}
			catch (Exception Ex)
			{
				// Don't bother failing if the file format has changed, simply abort the cache load
				if (Ex.Message.Contains( "cannot be converted to type" ))	// To catch serialization differences added when we added the DependencyInfo struct
				{
					Console.Error.WriteLine("Failed to read FlatCPPIncludeDependencyCache: {0}", Ex.Message);
				}
			}
			return Result;
		}
示例#12
0
		/**
		 * Loads the cache from the passed in file.
		 * 
		 * @param	Cache	File to deserialize from
		 */
		public static DependencyCache Load(FileItem Cache)
		{
			DependencyCache Result = null;
			try
			{
				using (FileStream Stream = new FileStream(Cache.AbsolutePath, FileMode.Open, FileAccess.Read))
				{
					BinaryFormatter Formatter = new BinaryFormatter();
					Result = Formatter.Deserialize(Stream) as DependencyCache;
				}
				Result.CreateFileExistsInfo();
				Result.ResetUnresolvedDependencies();
			}
			catch (Exception Ex)
			{
				// Don't bother logging this expected error.
				// It's due to a change in the CacheCreateDate type.
				if (Ex.Message != "Object of type 'System.DateTime' cannot be converted to type 'System.DateTimeOffset'" &&
	Ex.Message != "Object of type 'System.Collections.Generic.Dictionary`2[System.String,System.Collections.Generic.List`1[System.String]]' cannot be converted to type 'System.Collections.Generic.Dictionary`2[System.String,UnrealBuildTool.DependencyInfo]'.")	// To catch serialization differences added when we added the DependencyInfo struct
				{
					Console.Error.WriteLine("Failed to read dependency cache: {0}", Ex.Message);
				}
			}
			return Result;
		}
示例#13
0
		/// <summary>
		/// Get the name of the response file for the current linker environment and output file
		/// </summary>
		/// <param name="LinkEnvironment"></param>
		/// <param name="OutputFile"></param>
		/// <returns></returns>
		public static FileReference GetResponseFileName(LinkEnvironment LinkEnvironment, FileItem OutputFile)
		{
			// Construct a relative path for the intermediate response file
			return FileReference.Combine(LinkEnvironment.Config.IntermediateDirectory, OutputFile.Reference.GetFileName() + ".response");
		}
示例#14
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);
                        }
                    }
                }
            }
        }
示例#15
0
 static public bool FileExists(FileReference File)
 {
     return(FileItem.GetItemByFileReference(File).Exists);
 }
示例#16
0
 /// <summary>
 /// Update cache with dependencies for the passed in file.
 /// </summary>
 /// <param name="File">  File to update dependencies for</param>
 /// <param name="Info">List of dependencies to cache for passed in file</param>
 public void SetDependencyInfo(FileItem File, List <DependencyInclude> Info)
 {
     DependencyMap[File.Location] = Info;
     bIsDirty = true;
 }
示例#17
0
 /// <summary>
 /// Doesn't actually add a file, but instead reserves space.  This is used with "bUseAdaptiveUnityBuild", to prevent
 /// other compiled unity blobs in the module's numbered set from having to be recompiled after we eject source files
 /// one of that module's unity blobs.  Basically, it can prevent dozens of files from being recompiled after the first
 /// time building after your working set of source files changes
 /// </summary>
 /// <param name="File">The virtual file to add to the collection</param>
 public void AddVirtualFile(FileItem File)
 {
     VirtualFiles.Add(File);
     VirtualLength += File.Length;
 }
		/**
		 * Generates debug info for a given executable
		 * 
		 * @param MachOBinary FileItem describing the executable or dylib to generate debug info for
		 */
		public FileItem GenerateDebugInfo(FileItem MachOBinary)
		{
			// Make a file item for the source and destination files
			string FullDestPath = Path.ChangeExtension(MachOBinary.AbsolutePath, ".dSYM");

			FileItem OutputFile = FileItem.GetItemByPath(FullDestPath);
			FileItem DestFile = LocalToRemoteFileItem(OutputFile, false);
			FileItem InputFile = LocalToRemoteFileItem(MachOBinary, false);

			// Delete on the local machine
			if(Directory.Exists(OutputFile.AbsolutePath))
			{
				Directory.Delete(OutputFile.AbsolutePath, true);
			}

			// Make the compile action
			Action GenDebugAction = new Action(ActionType.GenerateDebugInfo);
			if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
			{
				DebugOutputMap.Add (GenDebugAction, OutputFile.AbsolutePath);
				GenDebugAction.ActionHandler = new Action.BlockingActionHandler(MacToolChain.RPCDebugInfoActionHandler);
			}
			GenDebugAction.WorkingDirectory = Path.GetFullPath(".");
			GenDebugAction.CommandPath = "sh";

			// Deletes ay existing file on the building machine,
			// note that the source and dest are switched from a copy command
			GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{2}\"; \"{0}\"dsymutil -f \"{1}\" -o \"{2}\"'",
				ToolchainDir,
				InputFile.AbsolutePath,
				DestFile.AbsolutePath);
			GenDebugAction.PrerequisiteItems.Add(InputFile);
			GenDebugAction.ProducedItems.Add(DestFile);
			GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;
			GenDebugAction.bCanExecuteRemotely = false;

			return DestFile;
		}
示例#19
0
 public void SetProducingCommandLine(FileItem File, string CommandLine)
 {
     ProducedItemToPreviousActionCommandLine[File.AbsolutePath.ToUpperInvariant()] = CommandLine;
     bIsDirty = true;
 }
示例#20
0
 public bool GetProducingCommandLine(FileItem File, out string Result)
 {
     return(ProducedItemToPreviousActionCommandLine.TryGetValue(File.AbsolutePath.ToUpperInvariant(), out Result));
 }
示例#21
0
 /// <inheritdoc/>
 public void AddCandidateForWorkingSet(FileItem File)
 {
     CandidatesForWorkingSet.Add(File);
 }
示例#22
0
 /// <inheritdoc/>
 public void AddFileToWorkingSet(FileItem File)
 {
     WorkingSet.Add(File);
 }
示例#23
0
        /// <summary>
        /// Checks if the makefile is valid for the current set of source files. This is done separately to the Load() method to allow pre-build steps to modify source files.
        /// </summary>
        /// <param name="Makefile">The makefile that has been loaded</param>
        /// <param name="ProjectFile">Path to the project file</param>
        /// <param name="Platform">The platform being built</param>
        /// <param name="WorkingSet">The current working set of source files</param>
        /// <param name="ReasonNotLoaded">If the makefile is not valid, is set to a message describing why</param>
        /// <returns>True if the makefile is valid, false otherwise</returns>
        public static bool IsValidForSourceFiles(TargetMakefile Makefile, FileReference ProjectFile, UnrealTargetPlatform Platform, ISourceFileWorkingSet WorkingSet, out string ReasonNotLoaded)
        {
            using (Timeline.ScopeEvent("TargetMakefile.IsValidForSourceFiles()"))
            {
                // Get the list of excluded folder names for this platform
                ReadOnlyHashSet <string> ExcludedFolderNames = UEBuildPlatform.GetBuildPlatform(Platform).GetExcludedFolderNames();

                // Check if any source files have been added or removed
                foreach (KeyValuePair <DirectoryItem, FileItem[]> Pair in Makefile.DirectoryToSourceFiles)
                {
                    DirectoryItem InputDirectory = Pair.Key;
                    if (!InputDirectory.Exists || InputDirectory.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        FileItem[] SourceFiles = UEBuildModuleCPP.GetSourceFiles(InputDirectory);
                        if (SourceFiles.Length < Pair.Value.Length)
                        {
                            ReasonNotLoaded = "source file removed";
                            return(false);
                        }
                        else if (SourceFiles.Length > Pair.Value.Length)
                        {
                            ReasonNotLoaded = "source file added";
                            return(false);
                        }
                        else if (SourceFiles.Intersect(Pair.Value).Count() != SourceFiles.Length)
                        {
                            ReasonNotLoaded = "source file modified";
                            return(false);
                        }

                        foreach (DirectoryItem Directory in InputDirectory.EnumerateDirectories())
                        {
                            if (!Makefile.DirectoryToSourceFiles.ContainsKey(Directory) && ContainsSourceFiles(Directory, ExcludedFolderNames))
                            {
                                ReasonNotLoaded = "directory added";
                                return(false);
                            }
                        }
                    }
                }

                // Check if any external dependencies have changed. These comparisons are done against the makefile creation time.
                foreach (FileItem ExternalDependency in Makefile.ExternalDependencies)
                {
                    if (!ExternalDependency.Exists)
                    {
                        Log.TraceLog("{0} has been deleted since makefile was built.", ExternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} deleted", ExternalDependency.Location.GetFileName());
                        return(false);
                    }
                    if (ExternalDependency.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} has been modified since makefile was built.", ExternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} modified", ExternalDependency.Location.GetFileName());
                        return(false);
                    }
                }

                // Check if any internal dependencies has changed. These comparisons are done against the makefile modified time.
                foreach (FileItem InternalDependency in Makefile.InternalDependencies)
                {
                    if (!InternalDependency.Exists)
                    {
                        Log.TraceLog("{0} has been deleted since makefile was written.", InternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} deleted", InternalDependency.Location.GetFileName());
                        return(false);
                    }
                    if (InternalDependency.LastWriteTimeUtc > Makefile.ModifiedTimeUtc)
                    {
                        Log.TraceLog("{0} has been modified since makefile was written.", InternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} modified", InternalDependency.Location.GetFileName());
                        return(false);
                    }
                }

                // Check that no new plugins have been added
                foreach (FileReference PluginFile in Plugins.EnumeratePlugins(ProjectFile))
                {
                    FileItem PluginFileItem = FileItem.GetItemByFileReference(PluginFile);
                    if (!Makefile.PluginFiles.Contains(PluginFileItem))
                    {
                        Log.TraceLog("{0} has been added", PluginFile.GetFileName());
                        ReasonNotLoaded = string.Format("{0} has been added", PluginFile.GetFileName());
                        return(false);
                    }
                }

                // Load the metadata cache
                SourceFileMetadataCache MetadataCache = SourceFileMetadataCache.CreateHierarchy(ProjectFile);

                // Find the set of files that contain reflection markup
                ConcurrentBag <FileItem> NewFilesWithMarkupBag = new ConcurrentBag <FileItem>();
                using (ThreadPoolWorkQueue Queue = new ThreadPoolWorkQueue())
                {
                    foreach (DirectoryItem SourceDirectory in Makefile.SourceDirectories)
                    {
                        Queue.Enqueue(() => FindFilesWithMarkup(SourceDirectory, MetadataCache, ExcludedFolderNames, NewFilesWithMarkupBag, Queue));
                    }
                }

                // Check whether the list has changed
                List <FileItem> PrevFilesWithMarkup = Makefile.UObjectModuleHeaders.Where(x => !x.bUsePrecompiled).SelectMany(x => x.HeaderFiles).ToList();
                List <FileItem> NextFilesWithMarkup = NewFilesWithMarkupBag.ToList();
                if (NextFilesWithMarkup.Count != PrevFilesWithMarkup.Count || NextFilesWithMarkup.Intersect(PrevFilesWithMarkup).Count() != PrevFilesWithMarkup.Count)
                {
                    ReasonNotLoaded = "UHT files changed";
                    return(false);
                }

                // If adaptive unity build is enabled, do a check to see if there are any source files that became part of the
                // working set since the Makefile was created (or, source files were removed from the working set.)  If anything
                // changed, then we'll force a new Makefile to be created so that we have fresh unity build blobs.  We always
                // want to make sure that source files in the working set are excluded from those unity blobs (for fastest possible
                // iteration times.)

                // Check if any source files in the working set no longer belong in it
                foreach (FileItem SourceFile in Makefile.WorkingSet)
                {
                    if (!WorkingSet.Contains(SourceFile) && SourceFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} was part of source working set and now is not; invalidating makefile", SourceFile.AbsolutePath);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(false);
                    }
                }

                // Check if any source files that are eligible for being in the working set have been modified
                foreach (FileItem SourceFile in Makefile.CandidatesForWorkingSet)
                {
                    if (WorkingSet.Contains(SourceFile) && SourceFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} was part of source working set and now is not", SourceFile.AbsolutePath);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(false);
                    }
                }
            }

            ReasonNotLoaded = null;
            return(true);
        }
示例#24
0
        public override FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            List <FileItem> Outputs = new List <FileItem>();

            for (int ArchIndex = 0; ArchIndex < Arches.Length; ArchIndex++)
            {
                string Arch = Arches[ArchIndex];
                for (int GPUArchIndex = 0; GPUArchIndex < GPUArchitectures.Length; GPUArchIndex++)
                {
                    string GPUArchitecture = GPUArchitectures[GPUArchIndex];
                    int    OutputPathIndex = ArchIndex * GPUArchitectures.Length + GPUArchIndex;

                    // Android will have an array of outputs
                    if (LinkEnvironment.Config.OutputFilePaths.Count < OutputPathIndex ||
                        !Path.GetFileNameWithoutExtension(LinkEnvironment.Config.OutputFilePaths[OutputPathIndex]).EndsWith(Arch + GPUArchitecture))
                    {
                        throw new BuildException("The OutputFilePaths array didn't match the Arches array in AndroidToolChain.LinkAllFiles");
                    }

                    // Create an action that invokes the linker.
                    Action LinkAction = new Action(ActionType.Link);
                    LinkAction.WorkingDirectory = Path.GetFullPath(".");

                    if (LinkEnvironment.Config.bIsBuildingLibrary)
                    {
                        LinkAction.CommandPath = Arch == "-armv7" ? ArPathArm : ArPathx86;
                    }
                    else
                    {
                        LinkAction.CommandPath = ClangPath;
                    }

                    string LinkerPath = LinkAction.WorkingDirectory;

                    LinkAction.WorkingDirectory = LinkEnvironment.Config.IntermediateDirectory;

                    // Get link arguments.
                    LinkAction.CommandArguments = LinkEnvironment.Config.bIsBuildingLibrary ? GetArArguments(LinkEnvironment) : GetLinkArguments(LinkEnvironment, Arch);

                    // Add the output file as a production of the link action.
                    FileItem OutputFile;
                    OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePaths[OutputPathIndex]);
                    Outputs.Add(OutputFile);
                    LinkAction.ProducedItems.Add(OutputFile);
                    LinkAction.StatusDescription = string.Format("{0}", Path.GetFileName(OutputFile.AbsolutePath));

                    // LinkAction.bPrintDebugInfo = true;

                    // Add the output file to the command-line.
                    if (LinkEnvironment.Config.bIsBuildingLibrary)
                    {
                        LinkAction.CommandArguments += string.Format(" \"{0}\"", OutputFile.AbsolutePath);
                    }
                    else
                    {
                        LinkAction.CommandArguments += string.Format(" -o \"{0}\"", OutputFile.AbsolutePath);
                    }

                    // Add the input files to a response file, and pass the response file on the command-line.
                    List <string> InputFileNames = new List <string>();
                    foreach (FileItem InputFile in LinkEnvironment.InputFiles)
                    {
                        // make sure it's for current Arch
                        if (Path.GetFileNameWithoutExtension(InputFile.AbsolutePath).EndsWith(Arch + GPUArchitecture))
                        {
                            string AbsolutePath = InputFile.AbsolutePath.Replace("\\", "/");

                            AbsolutePath = AbsolutePath.Replace(LinkEnvironment.Config.IntermediateDirectory.Replace("\\", "/"), "");
                            AbsolutePath = AbsolutePath.TrimStart(new char[] { '/' });

                            InputFileNames.Add(string.Format("\"{0}\"", AbsolutePath));
                            LinkAction.PrerequisiteItems.Add(InputFile);
                        }
                    }

                    string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);
                    LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, InputFileNames));

                    // libs don't link in other libs
                    if (!LinkEnvironment.Config.bIsBuildingLibrary)
                    {
                        // Add the library paths to the argument list.
                        foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
                        {
                            // LinkerPaths could be relative or absolute
                            string AbsoluteLibraryPath = ActionThread.ExpandEnvironmentVariables(LibraryPath);
                            if (IsDirectoryForArch(AbsoluteLibraryPath, Arch))
                            {
                                // environment variables aren't expanded when using the $( style
                                if (Path.IsPathRooted(AbsoluteLibraryPath) == false)
                                {
                                    AbsoluteLibraryPath = Path.Combine(LinkerPath, AbsoluteLibraryPath);
                                }
                                LinkAction.CommandArguments += string.Format(" -L\"{0}\"", AbsoluteLibraryPath);
                            }
                        }

                        // add libraries in a library group
                        LinkAction.CommandArguments += string.Format(" -Wl,--start-group");
                        foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
                        {
                            if (!ShouldSkipLib(AdditionalLibrary, Arch, GPUArchitecture))
                            {
                                if (String.IsNullOrEmpty(Path.GetDirectoryName(AdditionalLibrary)))
                                {
                                    LinkAction.CommandArguments += string.Format(" \"-l{0}\"", AdditionalLibrary);
                                }
                                else
                                {
                                    // full pathed libs are compiled by us, so we depend on linking them
                                    LinkAction.CommandArguments += string.Format(" \"{0}\"", Path.GetFullPath(AdditionalLibrary));
                                    LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
                                }
                            }
                        }
                        LinkAction.CommandArguments += string.Format(" -Wl,--end-group");
                    }

                    // Add the additional arguments specified by the environment.
                    LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
                    LinkAction.CommandArguments  = LinkAction.CommandArguments.Replace("\\", "/");

                    // Only execute linking on the local PC.
                    LinkAction.bCanExecuteRemotely = false;
                }
            }

            return(Outputs.ToArray());
        }
示例#25
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            if (Arches.Length == 0)
            {
                throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build");
            }

            if (!bHasPrintedApiLevel)
            {
                Console.WriteLine("Compiling Native code with NDK API '{0}'", GetNdkApiLevel());
                bHasPrintedApiLevel = true;
            }

            string BaseArguments = "";

            if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create)
            {
                BaseArguments += " -Werror";
            }

            // Directly added NDK files for NDK extensions
            ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName);

            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                BaseArguments += string.Format(" -D \"{0}\"", Definition);
            }

            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);



            string BasePCHName  = "";
            var    PCHExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Android].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);

            if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
            {
                BasePCHName = RemoveArchName(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath).Replace(PCHExtension, "");
            }

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (string Arch in Arches)
            {
                foreach (string GPUArchitecture in GPUArchitectures)
                {
                    // which toolchain to use
                    string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments;

                    if (GPUArchitecture == "-gl4")
                    {
                        Arguments += " -DPLATFORM_ANDROIDGL4=1";
                    }
                    else if (GPUArchitecture == "-es31")
                    {
                        Arguments += " -DPLATFORM_ANDROIDES31=1";
                    }

                    // which PCH file to include
                    string PCHArguments = "";
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        // Add the precompiled header file's path to the include path so Clang can find it.
                        // This needs to be before the other include paths to ensure Clang uses it instead of the source header file.
                        PCHArguments += string.Format(" -include \"{0}\"", InlineArchName(BasePCHName, Arch, GPUArchitecture));
                    }

                    // Add include paths to the argument list (filtered by architecture)
                    foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
                    {
                        if (IsDirectoryForArch(IncludePath, Arch))
                        {
                            Arguments += string.Format(" -I\"{0}\"", IncludePath);
                        }
                    }
                    foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
                    {
                        if (IsDirectoryForArch(IncludePath, Arch))
                        {
                            Arguments += string.Format(" -I\"{0}\"", IncludePath);
                        }
                    }

                    foreach (FileItem SourceFile in SourceFiles)
                    {
                        Action CompileAction = new Action(ActionType.Compile);
                        string FileArguments = "";
                        bool   bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C";

                        // should we disable optimizations on this file?
                        // @todo android - We wouldn't need this if we could disable optimizations per function (via pragma)
                        bool bDisableOptimizations = false;                        // SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1;
                        if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
                        {
                            Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath);
                        }

                        bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug;

                        // Add C or C++ specific compiler arguments.
                        if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                        {
                            FileArguments += GetCompileArguments_PCH(bDisableOptimizations);
                        }
                        else if (bIsPlainCFile)
                        {
                            FileArguments += GetCompileArguments_C(bDisableOptimizations);
                        }
                        else
                        {
                            FileArguments += GetCompileArguments_CPP(bDisableOptimizations);

                            // only use PCH for .cpp files
                            FileArguments += PCHArguments;
                        }

                        // Add the C++ source file and its included files to the prerequisite item list.
                        AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);

                        if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                        {
                            // Add the precompiled header file to the produced item list.
                            FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                                Path.Combine(
                                    CompileEnvironment.Config.OutputDirectory,
                                    Path.GetFileName(InlineArchName(SourceFile.AbsolutePath, Arch, GPUArchitecture) + PCHExtension)
                                    )
                                );

                            CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
                            Result.PrecompiledHeaderFile = PrecompiledHeaderFile;

                            // Add the parameters needed to compile the precompiled header file to the command-line.
                            FileArguments += string.Format(" -o \"{0}\"", PrecompiledHeaderFile.AbsolutePath, false);
                        }
                        else
                        {
                            if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                            {
                                CompileAction.bIsUsingPCH = true;
                                FileItem ArchPrecompiledHeaderFile = FileItem.GetItemByPath(InlineArchName(BasePCHName, Arch, GPUArchitecture) + PCHExtension);
                                CompileAction.PrerequisiteItems.Add(ArchPrecompiledHeaderFile);
                            }

                            var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Android].GetBinaryExtension(UEBuildBinaryType.Object);

                            // Add the object file to the produced item list.
                            FileItem ObjectFile = FileItem.GetItemByPath(
                                InlineArchName(Path.Combine(
                                                   CompileEnvironment.Config.OutputDirectory,
                                                   Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension), Arch, GPUArchitecture
                                               )
                                );
                            CompileAction.ProducedItems.Add(ObjectFile);
                            Result.ObjectFiles.Add(ObjectFile);

                            FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false);
                        }

                        // Add the source file path to the command-line.
                        FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath);

                        // Build a full argument list
                        string AllArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                        AllArguments = ActionThread.ExpandEnvironmentVariables(AllArguments);
                        AllArguments = AllArguments.Replace("\\", "/");

                        // Create the response file
                        string ResponseFileName = CompileAction.ProducedItems[0].AbsolutePath + ".response";
                        string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List <string> {
                            AllArguments
                        }));

                        CompileAction.WorkingDirectory  = Path.GetFullPath(".");
                        CompileAction.CommandPath       = ClangPath;
                        CompileAction.CommandArguments  = ResponseArgument;
                        CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", ""));

                        CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler);

                        // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves
                        CompileAction.bShouldOutputStatusDescription = true;

                        // Don't farm out creation of pre-compiled headers as it is the critical path task.
                        CompileAction.bCanExecuteRemotely =
                            CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create ||
                            BuildConfiguration.bAllowRemotelyCompiledPCHs;
                    }
                }
            }

            return(Result);
        }
示例#26
0
		/**
		 * Returns the direct dependencies of the specified FileItem if it exists in the cache and if the
		 * file has a last write time before the creation time of the cache. 
		 * 
		 * The code also keeps track of whether dependencies have been successfully accessed for a given
		 * file.
		 * 
		 * @param	File				File to try to find dependencies in cache
		 * @param	Result	[out]		List of dependencies if successful, null otherwise
		 * @param	HasUObjects			True if the file was found to have UObject classes, otherwise false
		 */
		public bool GetCachedDirectDependencies(FileItem File, out List<DependencyInclude> Result, out bool HasUObjects)
		{
			Result = null;
			HasUObjects = false;

			// Check whether File is in cache.
			DependencyInfo? DependencyInfo = GetCachedDependencyInfo(File);
			if( DependencyInfo != null )
			{
				// Check if any of the resolved includes is missing
				foreach (var Include in DependencyInfo.Value.Includes)
				{
					if (!String.IsNullOrEmpty(Include.IncludeResolvedName))
					{
						bool bIncludeExists = false;
						string FileExistsKey = Include.IncludeResolvedName.ToLowerInvariant();
						if (FileExistsInfo.TryGetValue(FileExistsKey, out bIncludeExists) == false)
						{
							bIncludeExists = System.IO.File.Exists(Include.IncludeResolvedName);
							FileExistsInfo.Add(FileExistsKey, bIncludeExists);
						}
						if (!bIncludeExists)
						{
							// Remove entry from cache as it's stale, as well as the include which no longer exists
							RemoveFileFromCache(Include.IncludeResolvedName);
							RemoveFileFromCache(File.AbsolutePath);							
							return false;
						}
					}						
				}
				// Cached version is up to date, return it.
				Result = DependencyInfo.Value.Includes;
				HasUObjects = DependencyInfo.Value.HasUObjects;
				return true;
			}
			// Not in cache.
			else
			{
				return false;
			}
		}
示例#27
0
		/// <summary>
		/// Caches the fully resolved path of the include.
		/// TODO: This method should be more tightly coupled with the Resolve step itself so we don't have to reach into the cache externally
		/// using internal details like the list index.
		/// </summary>
		/// <param name="File">The file whose include is being resolved</param>
		/// <param name="DirectlyIncludedFileNameIndex">Index in the resolve list to quickly find the include in question in the existing cache.</param>
		/// <param name="DirectlyIncludedFileNameFullPath">Full path name of the resolve include.</param>
		public void CacheResolvedIncludeFullPath(FileItem File, int DirectlyIncludedFileNameIndex, string DirectlyIncludedFileNameFullPath)
		{
			if (BuildConfiguration.bUseIncludeDependencyResolveCache)
			{
				var Includes = DependencyMap[File.AbsolutePath.ToLowerInvariant()].Includes;
				var IncludeToResolve = Includes[DirectlyIncludedFileNameIndex];
				if (BuildConfiguration.bTestIncludeDependencyResolveCache)
				{
					// test whether there are resolve conflicts between modules with different include paths.
					if (IncludeToResolve.IncludeResolvedName != null && IncludeToResolve.IncludeResolvedName != DirectlyIncludedFileNameFullPath)
					{
						throw new BuildException("Found directly included file that resolved differently in different modules. File ({0}) had previously resolved to ({1}) and now resolves to ({2}).",
							File.AbsolutePath, IncludeToResolve.IncludeResolvedName, DirectlyIncludedFileNameFullPath);
					}
				}
				Includes[DirectlyIncludedFileNameIndex].IncludeResolvedName = DirectlyIncludedFileNameFullPath;
				if (!String.IsNullOrEmpty(DirectlyIncludedFileNameFullPath))
				{
					bIsDirty = true;
				}
			}
		}
示例#28
0
        /// <summary>
        /// Finds the header file that is referred to by a partial include filename.
        /// </summary>
        /// <param name="RelativeIncludePath">path relative to the project</param>
        /// <param name="bSkipExternalHeader">true to skip processing of headers in external path</param>
        /// <param name="SourceFilesDirectory">- The folder containing the source files we're generating a PCH for</param>
        public static FileItem FindIncludedFile(string RelativeIncludePath, bool bSkipExternalHeader, List <string> IncludePathsToSearch, Dictionary <string, FileItem> IncludeFileSearchDictionary)
        {
            FileItem Result = null;

            if (IncludePathsToSearch == null)
            {
                throw new BuildException("Was not expecting IncludePathsToSearch to be empty for file '{0}'!", RelativeIncludePath);
            }

            ++TotalFindIncludedFileCalls;

            // Only search for the include file if the result hasn't been cached.
            string InvariantPath = RelativeIncludePath.ToLowerInvariant();

            if (!IncludeFileSearchDictionary.TryGetValue(InvariantPath, out Result))
            {
                int SearchAttempts = 0;
                if (Path.IsPathRooted(RelativeIncludePath))
                {
                    FileReference Reference = new FileReference(RelativeIncludePath);
                    if (DirectoryLookupCache.FileExists(Reference))
                    {
                        Result = FileItem.GetItemByFileReference(Reference);
                    }
                    ++SearchAttempts;
                }
                else
                {
                    // Find the first include path that the included file exists in.
                    foreach (string IncludePath in IncludePathsToSearch)
                    {
                        ++SearchAttempts;
                        string RelativeFilePath = "";
                        try
                        {
                            RelativeFilePath = Path.Combine(IncludePath, RelativeIncludePath);
                        }
                        catch (ArgumentException Exception)
                        {
                            throw new BuildException(Exception, "Failed to combine null or invalid include paths.");
                        }
                        FileReference FullFilePath = null;
                        try
                        {
                            FullFilePath = new FileReference(RelativeFilePath);
                        }
                        catch (Exception)
                        {
                        }
                        if (FullFilePath != null && DirectoryLookupCache.FileExists(FullFilePath))
                        {
                            Result = FileItem.GetItemByFileReference(FullFilePath);
                            break;
                        }
                    }
                }

                IncludePathSearchAttempts += SearchAttempts;

                if (BuildConfiguration.bPrintPerformanceInfo)
                {
                    // More than two search attempts indicates:
                    //		- Include path was not relative to the directory that the including file was in
                    //		- Include path was not relative to the project's base
                    if (SearchAttempts > 2)
                    {
                        Trace.TraceInformation("   Cache miss: " + RelativeIncludePath + " found after " + SearchAttempts.ToString() + " attempts: " + (Result != null ? Result.AbsolutePath : "NOT FOUND!"));
                    }
                }

                // Cache the result of the include path search.
                IncludeFileSearchDictionary.Add(InvariantPath, Result);
            }

            // @todo ubtmake: The old UBT tried to skip 'external' (STABLE) headers here.  But it didn't work.  We might want to do this though!  Skip system headers and source/thirdparty headers!

            if (Result != null)
            {
                Log.TraceVerbose("Resolved included file \"{0}\" to: {1}", RelativeIncludePath, Result.AbsolutePath);
            }
            else
            {
                Log.TraceVerbose("Couldn't resolve included file \"{0}\"", RelativeIncludePath);
            }

            return(Result);
        }
		FileItem CopyBundleResource(UEBuildBundleResource Resource, FileItem Executable)
		{
			Action CopyAction = new Action(ActionType.CreateAppBundle);
			CopyAction.WorkingDirectory = Path.GetFullPath(".");
			CopyAction.CommandPath = "/bin/sh";
			CopyAction.CommandDescription = "";

			string BundlePath = Executable.AbsolutePath.Substring(0, Executable.AbsolutePath.IndexOf(".app") + 4);
			string SourcePath = Path.Combine(CopyAction.WorkingDirectory, Resource.ResourcePath);
			string TargetPath = Path.Combine(BundlePath, "Contents", Resource.BundleContentsSubdir, Path.GetFileName(Resource.ResourcePath));

			FileItem TargetItem;
			if(BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
			{
				TargetItem = FileItem.GetItemByPath(TargetPath);
			}
			else
			{
				TargetItem = FileItem.GetRemoteItemByPath(TargetPath, RemoteToolChainPlatform);
			}

			CopyAction.CommandArguments = string.Format("-c 'cp -f -R \"{0}\" \"{1}\"; touch -c \"{2}\"'", ConvertPath(SourcePath), Path.GetDirectoryName(TargetPath).Replace('\\', '/') + "/", TargetPath.Replace('\\', '/'));
			CopyAction.PrerequisiteItems.Add(Executable);
			CopyAction.ProducedItems.Add(TargetItem);
			CopyAction.bShouldOutputStatusDescription = Resource.bShouldLog;
			CopyAction.StatusDescription = string.Format("Copying {0} to app bundle", Path.GetFileName(Resource.ResourcePath));
			CopyAction.bCanExecuteRemotely = false;

			if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
			{
				CopyAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
			}

			if (Directory.Exists(Resource.ResourcePath))
			{
				foreach (string ResourceFile in Directory.GetFiles(Resource.ResourcePath, "*", SearchOption.AllDirectories))
				{
					QueueFileForBatchUpload(FileItem.GetItemByFullPath(Path.GetFullPath(ResourceFile)));
				}
			}
			else
			{
				QueueFileForBatchUpload(FileItem.GetItemByFullPath(SourcePath));
			}

			return TargetItem;
		}
示例#30
0
        public static List <FileItem> FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem SourceFile, UEBuildPlatform 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.Reference);
                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 <FileReference>();
                    foreach (var IncludedFile in Result)
                    {
                        Dependencies.Add(IncludedFile.Reference);
                    }
                    FileReference PCHName = SourceFile.PrecompiledHeaderIncludeFilename;
                    FlatCPPIncludeDependencyCache[Target].SetDependenciesForFile(SourceFile.Reference, PCHName, Dependencies);
                }
            }

            return(Result);
        }
示例#31
0
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            var EnvVars = VCEnvironment.SetEnvironment(LinkEnvironment.Config.Target.Platform);

            if (LinkEnvironment.Config.bIsBuildingDotNetAssembly)
            {
                return(FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath));
            }

            bool bIsBuildingLibrary = LinkEnvironment.Config.bIsBuildingLibrary || bBuildImportLibraryOnly;
            bool bIncludeDependentLibrariesInLibrary = bIsBuildingLibrary && LinkEnvironment.Config.bIncludeDependentLibrariesInLibrary;

            // Get link arguments.
            StringBuilder Arguments = new StringBuilder();

            if (bIsBuildingLibrary)
            {
                AppendLibArguments(LinkEnvironment, Arguments);
            }
            else
            {
                AppendLinkArguments(LinkEnvironment, Arguments);
            }



            // If we're only building an import library, add the '/DEF' option that tells the LIB utility
            // to simply create a .LIB file and .EXP file, and don't bother validating imports
            if (bBuildImportLibraryOnly)
            {
                Arguments.Append(" /DEF");

                // Ensure that the import library references the correct filename for the linked binary.
                Arguments.AppendFormat(" /NAME:\"{0}\"", Path.GetFileName(LinkEnvironment.Config.OutputFilePath));
            }


            // Add delay loaded DLLs.
            if (!bIsBuildingLibrary)
            {
                // Delay-load these DLLs.
                foreach (string DelayLoadDLL in LinkEnvironment.Config.DelayLoadDLLs)
                {
                    Arguments.AppendFormat(" /DELAYLOAD:\"{0}\"", DelayLoadDLL);
                }
            }

            // @todo UE4 DLL: Why do I need LIBPATHs to build only export libraries with /DEF? (tbbmalloc.lib)
            if (!LinkEnvironment.Config.bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary))
            {
                // Add the library paths to the argument list.
                foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
                {
                    Arguments.AppendFormat(" /LIBPATH:\"{0}\"", LibraryPath);
                }

                // Add the excluded default libraries to the argument list.
                foreach (string ExcludedLibrary in LinkEnvironment.Config.ExcludedLibraries)
                {
                    Arguments.AppendFormat(" /NODEFAULTLIB:\"{0}\"", ExcludedLibrary);
                }
            }

            // For targets that are cross-referenced, we don't want to write a LIB file during the link step as that
            // file will clobber the import library we went out of our way to generate during an earlier step.  This
            // file is not needed for our builds, but there is no way to prevent MSVC from generating it when
            // linking targets that have exports.  We don't want this to clobber our LIB file and invalidate the
            // existing timstamp, so instead we simply emit it with a different name
            string ImportLibraryFilePath = Path.Combine(LinkEnvironment.Config.IntermediateDirectory,
                                                        Path.GetFileNameWithoutExtension(LinkEnvironment.Config.OutputFilePath) + ".lib");

            if (LinkEnvironment.Config.bIsCrossReferenced && !bBuildImportLibraryOnly)
            {
                ImportLibraryFilePath += ".suppressed";
            }

            FileItem OutputFile;

            if (bBuildImportLibraryOnly)
            {
                OutputFile = FileItem.GetItemByPath(ImportLibraryFilePath);
            }
            else
            {
                OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath);
                OutputFile.bNeedsHotReloadNumbersDLLCleanUp = LinkEnvironment.Config.bIsBuildingDLL;
            }

            List <FileItem> ProducedItems = new List <FileItem>();

            ProducedItems.Add(OutputFile);

            List <FileItem> PrerequisiteItems = new List <FileItem>();

            // Add the input files to a response file, and pass the response file on the command-line.
            List <string> InputFileNames = new List <string>();

            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath));
                PrerequisiteItems.Add(InputFile);
            }

            if (!bBuildImportLibraryOnly)
            {
                // Add input libraries as prerequisites, too!
                foreach (FileItem InputLibrary in LinkEnvironment.InputLibraries)
                {
                    InputFileNames.Add(string.Format("\"{0}\"", InputLibrary.AbsolutePath));
                    PrerequisiteItems.Add(InputLibrary);
                }
            }

            if (!bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary))
            {
                foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
                {
                    InputFileNames.Add(string.Format("\"{0}\"", AdditionalLibrary));

                    // If the library file name has a relative path attached (rather than relying on additional
                    // lib directories), then we'll add it to our prerequisites list.  This will allow UBT to detect
                    // when the binary needs to be relinked because a dependent external library has changed.
                    //if( !String.IsNullOrEmpty( Path.GetDirectoryName( AdditionalLibrary ) ) )
                    {
                        PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
                    }
                }
            }

            // Create a response file for the linker
            string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);

            // Never create response files when we are only generating IntelliSense data
            if (!ProjectFileGenerator.bGenerateProjectFiles)
            {
                ResponseFile.Create(ResponseFileName, InputFileNames);
            }
            Arguments.AppendFormat(" @\"{0}\"", ResponseFileName);

            // Add the output file to the command-line.
            Arguments.AppendFormat(" /OUT:\"{0}\"", OutputFile.AbsolutePath);

            if (bBuildImportLibraryOnly || (LinkEnvironment.Config.bHasExports && !bIsBuildingLibrary))
            {
                // An export file is written to the output directory implicitly; add it to the produced items list.
                string   ExportFilePath = Path.ChangeExtension(ImportLibraryFilePath, ".exp");
                FileItem ExportFile     = FileItem.GetItemByPath(ExportFilePath);
                ProducedItems.Add(ExportFile);
            }

            if (!bIsBuildingLibrary)
            {
                // Xbox 360 LTCG does not seem to produce those.
                if (LinkEnvironment.Config.bHasExports &&
                    (LinkEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Shipping))
                {
                    // Write the import library to the output directory for nFringe support.
                    FileItem ImportLibraryFile = FileItem.GetItemByPath(ImportLibraryFilePath);
                    Arguments.AppendFormat(" /IMPLIB:\"{0}\"", ImportLibraryFilePath);
                    ProducedItems.Add(ImportLibraryFile);
                }

                if (LinkEnvironment.Config.bCreateDebugInfo)
                {
                    // Write the PDB file to the output directory.
                    string   PDBFilePath = Path.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".pdb");
                    FileItem PDBFile     = FileItem.GetItemByPath(PDBFilePath);
                    Arguments.AppendFormat(" /PDB:\"{0}\"", PDBFilePath);
                    ProducedItems.Add(PDBFile);

                    // Write the MAP file to the output directory.
#if false
                    if (true)
                    {
                        string   MAPFilePath = Path.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".map");
                        FileItem MAPFile     = FileItem.GetItemByPath(MAPFilePath);
                        LinkAction.CommandArguments += string.Format(" /MAP:\"{0}\"", MAPFilePath);
                        LinkAction.ProducedItems.Add(MAPFile);
                    }
#endif
                }

                // Add the additional arguments specified by the environment.
                Arguments.Append(LinkEnvironment.Config.AdditionalArguments);
            }

            // Create an action that invokes the linker.
            Action LinkAction = new Action(ActionType.Link);
            LinkAction.CommandDescription = "Link";
            LinkAction.WorkingDirectory   = Path.GetFullPath(".");
            LinkAction.CommandPath        = bIsBuildingLibrary ? EnvVars.LibraryLinkerPath : EnvVars.LinkerPath;
            LinkAction.CommandArguments   = Arguments.ToString();
            LinkAction.ProducedItems.AddRange(ProducedItems);
            LinkAction.PrerequisiteItems.AddRange(PrerequisiteItems);
            LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath);

            // Tell the action that we're building an import library here and it should conditionally be
            // ignored as a prerequisite for other actions
            LinkAction.bProducesImportLibrary = bBuildImportLibraryOnly || LinkEnvironment.Config.bIsBuildingDLL;

            // Only execute linking on the local PC.
            LinkAction.bCanExecuteRemotely = false;

            Log.TraceVerbose("     Linking: " + LinkAction.StatusDescription);
            Log.TraceVerbose("     Command: " + LinkAction.CommandArguments);

            return(OutputFile);
        }
示例#32
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ProjectFile"></param>
        /// <param name="Executable"></param>
        /// <param name="StageDirectory"></param>
        /// <param name="PlatformType"></param>
        public static void GenerateAssetCatalog(FileReference ProjectFile, string Executable, string StageDirectory, UnrealTargetPlatform PlatformType)
        {
            // Initialize the toolchain.
            IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(PlatformType)).ReadProjectSettings(null);
            IOSToolChain       ToolChain       = new IOSToolChain(ProjectFile, ProjectSettings);

            // Determine whether the user has modified icons that require a remote Mac to build.
            CppPlatform Platform         = PlatformType == UnrealTargetPlatform.IOS ? CppPlatform.IOS : CppPlatform.TVOS;
            bool        bUserImagesExist = false;

            ToolChain.GenerateAssetCatalog(Platform, ref bUserImagesExist);

            // Don't attempt to do anything remotely if the user is using the default UE4 images.
            if (!bUserImagesExist)
            {
                return;
            }

            // Also don't attempt to use a remote Mac if packaging for TVOS on PC.
            if (Platform == CppPlatform.TVOS && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                return;
            }

            // Save off the current bUseRPCUtil setting to restore at the end of this function.
            // At this time, iPhonePackager needs to be called with bUseRPCUtil == true.
            bool bSaveUseRPCUtil = RemoteToolChain.bUseRPCUtil;

            // Initialize the remote calling environment, taking into account the user's SSH setting.
            ToolChain.SetUpGlobalEnvironment(false);

            // Build the asset catalog ActionGraph.
            ActionGraph     ActionGraph = new ActionGraph();
            List <FileItem> OutputFiles = new List <FileItem>();

            ToolChain.CompileAssetCatalog(FileItem.GetItemByPath(Executable), Platform, ActionGraph, OutputFiles);

            ActionGraph.FinalizeActionGraph();

            // I'm not sure how to derive the UE4Game and Development arguments programmatically.
            string[] Arguments = new string[] { "UE4Game", (PlatformType == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "Development", "-UniqueBuildEnvironment" };

            // Perform all of the setup necessary to actually execute the ActionGraph instance.
            ReadOnlyBuildVersion Version        = new ReadOnlyBuildVersion(BuildVersion.ReadDefault());
            List <string[]>      TargetSettings = new List <string[]>();

            TargetSettings.Add(Arguments);
            var Targets = new List <UEBuildTarget>();
            Dictionary <UEBuildTarget, CPPHeaders> TargetToHeaders = new Dictionary <UEBuildTarget, CPPHeaders>();
            List <TargetDescriptor> TargetDescs = new List <TargetDescriptor>();

            foreach (string[] TargetSetting in TargetSettings)
            {
                TargetDescs.AddRange(TargetDescriptor.ParseCommandLine(TargetSetting, ref ProjectFile));
            }
            foreach (TargetDescriptor TargetDesc in TargetDescs)
            {
                UEBuildTarget Target = UEBuildTarget.CreateTarget(TargetDesc, Arguments, false, Version);
                if (Target == null)
                {
                    continue;
                }
                Targets.Add(Target);
                TargetToHeaders.Add(Target, null);
            }

            bool bIsRemoteCompile = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac;

            // Create the build configuration object, and read the settings
            BuildConfiguration BuildConfiguration = new BuildConfiguration();

            XmlConfig.ApplyTo(BuildConfiguration);
            CommandLine.ParseArguments(Arguments, BuildConfiguration);
            BuildConfiguration.bUseUBTMakefiles = false;

            Action[] PrerequisiteActions;
            {
                HashSet <Action> PrerequisiteActionsSet = new HashSet <Action>();
                foreach (FileItem OutputFile in OutputFiles)
                {
                    ActionGraph.GatherPrerequisiteActions(OutputFile, ref PrerequisiteActionsSet);
                }
                PrerequisiteActions = PrerequisiteActionsSet.ToArray();
            }

            // Copy any asset catalog files to the remote Mac, if necessary.
            foreach (UEBuildTarget Target in Targets)
            {
                UEBuildPlatform.GetBuildPlatform(Target.Platform).PreBuildSync();
            }

            // Begin execution of the ActionGraph.
            Dictionary <UEBuildTarget, List <FileItem> > TargetToOutdatedPrerequisitesMap;
            List <Action> ActionsToExecute = ActionGraph.GetActionsToExecute(BuildConfiguration, PrerequisiteActions, Targets, TargetToHeaders, true, true, out TargetToOutdatedPrerequisitesMap);
            string        ExecutorName     = "Unknown";
            bool          bSuccess         = ActionGraph.ExecuteActions(BuildConfiguration, ActionsToExecute, bIsRemoteCompile, out ExecutorName, "", EHotReload.Disabled);

            if (bSuccess)
            {
                if (bIsRemoteCompile)
                {
                    // Copy the remotely built AssetCatalog directory locally.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string   RemoteDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        FileItem LocalExecutable = ToolChain.RemoteToLocalFileItem(FileItem.GetItemByPath(Executable));
                        string   LocalDirectory  = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(LocalExecutable.AbsolutePath), "AssetCatalog");
                        LocalDirectory = StageDirectory;
                        RPCUtilHelper.CopyDirectory(RemoteDirectory, LocalDirectory, RPCUtilHelper.ECopyOptions.DoNotReplace);
                    }
                }
                else
                {
                    // Copy the built AssetCatalog directory to the StageDirectory.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string SourceDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        System.IO.DirectoryInfo SourceDirectoryInfo = new System.IO.DirectoryInfo(SourceDirectory);
                        if (!System.IO.Directory.Exists(StageDirectory))
                        {
                            System.IO.Directory.CreateDirectory(StageDirectory);
                        }
                        System.IO.FileInfo[] SourceFiles = SourceDirectoryInfo.GetFiles();
                        foreach (System.IO.FileInfo SourceFile in SourceFiles)
                        {
                            string DestinationPath = System.IO.Path.Combine(StageDirectory, SourceFile.Name);
                            SourceFile.CopyTo(DestinationPath, true);
                        }
                    }
                }
            }

            // Restore the former bUseRPCUtil setting.
            RemoteToolChain.bUseRPCUtil = bSaveUseRPCUtil;
        }
示例#33
0
        internal bool ExecuteActions(List <Action> InActions, Dictionary <Action, ActionThread> InActionThreadDictionary)
        {
            // Build the script file that will be executed by SN-DBS
            StreamWriter ScriptFile;
            string       ScriptFilename = Path.Combine(UnrealBuildTool.EngineDirectory.FullName, "Intermediate", "Build", "SNDBS.bat");

            FileStream ScriptFileStream = new FileStream(ScriptFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);

            ScriptFile           = new StreamWriter(ScriptFileStream);
            ScriptFile.AutoFlush = true;

            int           NumScriptedActions = 0;
            List <Action> LocalActions       = new List <Action>();
            ActionThread  DummyActionThread  = new ActionThread(null, 1, 1);
            bool          PrintDebugInfo     = false;

            foreach (Action Action in InActions)
            {
                ActionThread ActionProcess       = null;
                bool         bFoundActionProcess = InActionThreadDictionary.TryGetValue(Action, out ActionProcess);
                if (bFoundActionProcess == false)
                {
                    // Determine whether there are any prerequisites of the action that are outdated.
                    bool bHasOutdatedPrerequisites = false;
                    bool bHasFailedPrerequisites   = false;
                    foreach (Action PrerequisiteAction in Action.PrerequisiteActions)
                    {
                        if (InActions.Contains(PrerequisiteAction))
                        {
                            ActionThread PrerequisiteProcess       = null;
                            bool         bFoundPrerequisiteProcess = InActionThreadDictionary.TryGetValue(PrerequisiteAction, out PrerequisiteProcess);
                            if (bFoundPrerequisiteProcess == true)
                            {
                                if (PrerequisiteProcess == null)
                                {
                                    bHasFailedPrerequisites = true;
                                }
                                else if (PrerequisiteProcess.bComplete == false)
                                {
                                    bHasOutdatedPrerequisites = true;
                                }
                                else if (PrerequisiteProcess.ExitCode != 0)
                                {
                                    bHasFailedPrerequisites = true;
                                }
                            }
                            else
                            {
                                bHasOutdatedPrerequisites = true;
                            }
                        }
                    }

                    // If there are any failed prerequisites of this action, don't execute it.
                    if (bHasFailedPrerequisites)
                    {
                        // Add a null entry in the dictionary for this action.
                        InActionThreadDictionary.Add(Action, null);
                    }
                    // If there aren't any outdated prerequisites of this action, execute it.
                    else if (!bHasOutdatedPrerequisites)
                    {
                        if (Action.bCanExecuteRemotely == false || Action.bCanExecuteRemotelyWithSNDBS == false)
                        {
                            // Execute locally
                            LocalActions.Add(Action);
                        }
                        else
                        {
                            // Create a dummy force-included file which references PCH files, so that SN-DBS knows they are dependencies.
                            string AdditionalStubIncludes = "";
                            if (Action.CommandPath.GetFileName().Equals("cl.exe", StringComparison.OrdinalIgnoreCase))
                            {
                                string        ResponseFile    = Action.CommandArguments.Replace("\"", "").Replace("@", "").Trim();
                                StringBuilder WrapperContents = new StringBuilder();
                                using (StringWriter Writer = new StringWriter(WrapperContents))
                                {
                                    Writer.WriteLine("// PCH dependencies for {0}", ResponseFile);
                                    Writer.WriteLine("#if 0");
                                    foreach (FileItem Preqrequisite in Action.PrerequisiteItems)
                                    {
                                        if (Preqrequisite.AbsolutePath.EndsWith(".pch"))
                                        {
                                            Writer.WriteLine("#include \"{0}\"", Preqrequisite.AbsolutePath.Replace(".pch", ".obj"));
                                        }
                                    }
                                    Writer.WriteLine("#endif");
                                }

                                FileItem DummyResponseFileDependency = FileItem.CreateIntermediateTextFile(new FileReference(ResponseFile + ".dummy.h"), WrapperContents.ToString());
                                AdditionalStubIncludes = string.Format("/FI\"{0}\"", DummyResponseFileDependency);
                            }

                            // Add to script for execution by SN-DBS
                            string NewCommandArguments = "\"" + Action.CommandPath + "\"" + " " + AdditionalStubIncludes + " " + Action.CommandArguments;
                            ScriptFile.WriteLine(NewCommandArguments);
                            InActionThreadDictionary.Add(Action, DummyActionThread);
                            Action.StartTime = Action.EndTime = DateTimeOffset.Now;
                            Log.TraceInformation("[{0}/{1}] {2} {3}", JobNumber, InActions.Count, Action.CommandDescription, Action.StatusDescription);
                            JobNumber++;
                            NumScriptedActions++;
                            PrintDebugInfo |= Action.bPrintDebugInfo;

                            if (Action.DependencyListFile != null && File.Exists(Action.DependencyListFile.AbsolutePath))
                            {
                                Log.TraceVerbose("Deleting dependency list file {0}", Action.DependencyListFile.AbsolutePath);
                                File.Delete(Action.DependencyListFile.AbsolutePath);
                            }
                        }
                    }
                }
            }

            ScriptFile.Flush();
            ScriptFile.Close();
            ScriptFile.Dispose();
            ScriptFile = null;

            if (NumScriptedActions > 0)
            {
                // Create the process
                string             SCERoot                = Environment.GetEnvironmentVariable("SCE_ROOT_DIR");
                string             SNDBSExecutable        = Path.Combine(SCERoot, "Common/SN-DBS/bin/dbsbuild.exe");
                DirectoryReference TemplatesDir           = DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Programs", "UnrealBuildTool", "SndbsTemplates");
                string             IncludeRewriteRulesArg = String.Format("--include-rewrite-rules \"{0}\"", IncludeRewriteRulesFile.FullName);
                string             VerbosityLevel         = PrintDebugInfo ? "-v" : "-q";
                ProcessStartInfo   PSI = new ProcessStartInfo(SNDBSExecutable, String.Format("{0} -p UE4 -s \"{1}\" -templates \"{2}\" {3}", VerbosityLevel, FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "sndbs.bat").FullName, TemplatesDir.FullName, IncludeRewriteRulesArg));
                PSI.RedirectStandardOutput = true;
                PSI.RedirectStandardError  = true;
                PSI.UseShellExecute        = false;
                PSI.CreateNoWindow         = true;
                PSI.WorkingDirectory       = Path.GetFullPath(".");
                Process NewProcess = new Process();
                NewProcess.StartInfo           = PSI;
                NewProcess.OutputDataReceived += new DataReceivedEventHandler(ActionDebugOutput);
                NewProcess.ErrorDataReceived  += new DataReceivedEventHandler(ActionDebugOutput);
                DateTimeOffset StartTime = DateTimeOffset.Now;
                NewProcess.Start();
                NewProcess.BeginOutputReadLine();
                NewProcess.BeginErrorReadLine();

                NewProcess.WaitForExit();

                TimeSpan       Duration;
                DateTimeOffset EndTime = DateTimeOffset.Now;
                if (EndTime == DateTimeOffset.MinValue)
                {
                    Duration = DateTimeOffset.Now - StartTime;
                }
                else
                {
                    Duration = EndTime - StartTime;
                }

                DummyActionThread.bComplete = true;
                int ExitCode = NewProcess.ExitCode;
                if (ExitCode != 0)
                {
                    return(false);
                }
            }

            // Execute local tasks
            if (LocalActions.Count > 0)
            {
                return(ExecuteLocalActions(LocalActions, InActionThreadDictionary, InActions.Count));
            }

            return(true);
        }
示例#34
0
        private LinkEnvironment SetupBinaryLinkEnvironment(UEBuildTarget Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            LinkEnvironment         BinaryLinkEnvironment         = LinkEnvironment.DeepCopy();
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CompileEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            CompileEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            CPPEnvironment BinaryCompileEnvironment = CompileEnvironment.DeepCopy();

            // @Hack: This to prevent UHT from listing CoreUObject.generated.cpp as its dependency.
            // We flag the compile environment when we build UHT so that we don't need to check
            // this for each file when generating their dependencies.
            BinaryCompileEnvironment.bHackHeaderGenerator = (Target.GetAppName() == "UnrealHeaderTool");

            // @todo: This should be in some Windows code somewhere...
            // Set the original file name macro; used in PCLaunch.rc to set the binary metadata fields.
            string OriginalFilename = (Config.OriginalOutputFilePaths != null) ?
                                      Config.OriginalOutputFilePaths[0].GetFileName() :
                                      Config.OutputFilePaths[0].GetFileName();

            BinaryCompileEnvironment.Config.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"");

            foreach (UEBuildModule Module in Modules)
            {
                List <FileItem> LinkInputFiles;
                if (Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + Module.Name);
                    LinkInputFiles = Module.Compile(Target, ToolChain, BinaryCompileEnvironment, SharedPCHs, ActionGraph);

                    // NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input
                    // multiple times for a single binary.  We'll check for that here, and only add it once.  This avoids
                    // a linker warning about redundant .obj files.
                    foreach (FileItem LinkInputFile in LinkInputFiles)
                    {
                        if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile))
                        {
                            BinaryLinkEnvironment.InputFiles.Add(LinkInputFile);
                        }
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    // Allow the module to modify the link environment for the binary.
                    Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules);
                }
            }


            // Allow the binary dependencies to modify the link environment.
            foreach (UEBuildBinary BinaryDependency in BinaryDependencies)
            {
                BinaryDependency.SetupDependentLinkEnvironment(BinaryLinkEnvironment);
            }

            // Remove the default resource file on Windows (PCLaunch.rc) if the user has specified their own
            if (BinaryLinkEnvironment.InputFiles.Select(Item => Path.GetFileName(Item.AbsolutePath).ToLower()).Any(Name => Name.EndsWith(".res") && !Name.EndsWith(".inl.res") && Name != "pclaunch.rc.res"))
            {
                BinaryLinkEnvironment.InputFiles.RemoveAll(x => Path.GetFileName(x.AbsolutePath).ToLower() == "pclaunch.rc.res");
            }

            // Set the link output file.
            BinaryLinkEnvironment.Config.OutputFilePaths = Config.OutputFilePaths.ToList();

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.Config.bHasExports = Config.bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.Config.IntermediateDirectory = Config.IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.Config.OutputDirectory = Config.OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            BinaryLinkEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            BinaryLinkEnvironment.Config.ProjectFile = Target.ProjectFile;

            // Add the default resources for dlls
            if (Config.Type == UEBuildBinaryType.DynamicLinkLibrary)
            {
                // Check if there's already a custom resource file
                if (!BinaryLinkEnvironment.InputFiles.Any(x => x.Reference.HasExtension(".res")))
                {
                    if (UEBuildConfiguration.bFormalBuild)
                    {
                        // For formal builds, compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        CPPEnvironment BinaryResourceCompileEnvironment = BinaryCompileEnvironment.DeepCopy();
                        BinaryResourceCompileEnvironment.Config.OutputDirectory = DirectoryReference.Combine(BinaryResourceCompileEnvironment.Config.OutputDirectory, Modules.First().Name);
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(BinaryResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ActionGraph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                    else
                    {
                        // For non-formal builds, we just want to share the default resource file between modules
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                }

                // Add all the common resource files
                BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);
            }

            return(BinaryLinkEnvironment);
        }
示例#35
0
        private PrecompileHeaderEnvironment ApplySharedPCH(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment, CPPEnvironment ModuleCompileEnvironment, List<FileItem> CPPFiles, ref FileItem SharedPCHHeaderFile)
        {
            // Check to see if we have a PCH header already setup that we can use
            var SharedPCHHeaderFileCopy = SharedPCHHeaderFile;
            var SharedPCHEnvironment = GlobalCompileEnvironment.SharedPCHEnvironments.Find(Env => Env.PrecompiledHeaderIncludeFilename == SharedPCHHeaderFileCopy);
            if (SharedPCHEnvironment == null)
            {
                return null;
            }

            // Don't mix CLR modes
            if (SharedPCHEnvironment.CLRMode != ModuleCompileEnvironment.Config.CLRMode)
            {
                Log.TraceVerbose("Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because CLR modes don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName);
                SharedPCHHeaderFile = null;
                return null;
            }
            // Don't mix RTTI modes
            if (bUseRTTI)
            {
                Log.TraceVerbose("Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because RTTI modes don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName);
                SharedPCHHeaderFile = null;
                return null;
            }

            // Don't mix non-optimized code with optimized code (PCHs won't be compatible)
            var SharedPCHCodeOptimization = SharedPCHEnvironment.OptimizeCode;
            var ModuleCodeOptimization    = ModuleCompileEnvironment.Config.OptimizeCode;

            if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
            {
                if (SharedPCHCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds)
                {
                    SharedPCHCodeOptimization = ModuleRules.CodeOptimization.Always;
                }

                if (ModuleCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds)
                {
                    ModuleCodeOptimization = ModuleRules.CodeOptimization.Always;
                }
            }

            if (SharedPCHCodeOptimization != ModuleCodeOptimization)
            {
                Log.TraceVerbose("Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because optimization levels don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName);
                SharedPCHHeaderFile = null;
                return null;
            }

            return SharedPCHEnvironment;
        }
示例#36
0
 /// <summary>
 /// Constructs a fresh cache, storing the file name that it should be saved as later on
 /// </summary>
 /// <param name="Cache">File name for this cache, usually unique per context (e.g. target)</param>
 protected FlatCPPIncludeDependencyCache(FileItem Cache)
 {
     CacheFileItem = Cache;
     DependencyMap = new Dictionary <string, FlatCPPIncludeDependencyInfo>();
 }
示例#37
0
 /// <summary>
 /// Checks if the specified file is a C++ source file
 /// </summary>
 /// <param name="FileItem">The file to check</param>
 /// <returns>True if this is a C++ source file</returns>
 private static bool IsCPPFile( FileItem FileItem )
 {
     return IsCPPImplementationFile( FileItem ) || IsCPPIncludeFile( FileItem ) || IsCPPResourceFile( FileItem );
 }
示例#38
0
        private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, TargetMakefile Makefile)
        {
            LinkEnvironment         BinaryLinkEnvironment         = new LinkEnvironment(LinkEnvironment);
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CppCompileEnvironment BinaryCompileEnvironment = CreateBinaryCompileEnvironment(CompileEnvironment);

            if (BinaryCompileEnvironment.bUseSharedBuildEnvironment && Target.ProjectFile != null && IntermediateDirectory.IsUnderDirectory(Target.ProjectFile.Directory))
            {
                BinaryCompileEnvironment.bUseSharedBuildEnvironment = false;
            }

            foreach (UEBuildModule Module in Modules)
            {
                List <FileItem> LinkInputFiles;
                if (Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + Module.Name);
                    LinkInputFiles = Module.Compile(Target, ToolChain, BinaryCompileEnvironment, WorkingSet, Makefile);

                    // NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input
                    // multiple times for a single binary.  We'll check for that here, and only add it once.  This avoids
                    // a linker warning about redundant .obj files.
                    foreach (FileItem LinkInputFile in LinkInputFiles)
                    {
                        if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile))
                        {
                            BinaryLinkEnvironment.InputFiles.Add(LinkInputFile);
                        }
                    }

                    // Force a reference to initialize module for this binary
                    if (Module.Rules.bRequiresImplementModule.Value)
                    {
                        BinaryLinkEnvironment.IncludeFunctions.Add(String.Format("IMPLEMENT_MODULE_{0}", Module.Name));
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                // Allow the module to modify the link environment for the binary.
                Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules, ExeDir);
            }


            // Allow the binary dependencies to modify the link environment.
            foreach (UEBuildBinary BinaryDependency in BinaryDependencies)
            {
                BinaryDependency.SetupDependentLinkEnvironment(BinaryLinkEnvironment);
            }

            // Set the link output file.
            BinaryLinkEnvironment.OutputFilePaths = OutputFilePaths.ToList();

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.bHasExports = bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.IntermediateDirectory = IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.OutputDirectory = OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.bIsBuildingDLL     = IsBuildingDll(Type);
            BinaryLinkEnvironment.bIsBuildingLibrary = IsBuildingLibrary(Type);

            // If we don't have any resource file, use the default or compile a custom one for this module
            if (BinaryLinkEnvironment.Platform == UnrealTargetPlatform.Win32 || BinaryLinkEnvironment.Platform == UnrealTargetPlatform.Win64)
            {
                // Figure out if this binary has any custom resource files. Hacky check to ignore the resource file in the Launch module, since it contains dialogs that the engine needs and always needs to be included.
                FileItem[] CustomResourceFiles = BinaryLinkEnvironment.InputFiles.Where(x => x.Location.HasExtension(".res") && !x.Location.FullName.EndsWith("\\Launch\\PCLaunch.rc.res", StringComparison.OrdinalIgnoreCase)).ToArray();
                if (CustomResourceFiles.Length == 0)
                {
                    if (BinaryLinkEnvironment.DefaultResourceFiles.Count > 0)
                    {
                        // Use the default resource file if possible
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                    else
                    {
                        // Get the intermediate directory
                        DirectoryReference ResourceIntermediateDirectory = BinaryLinkEnvironment.IntermediateDirectory;

                        // Create a compile environment for resource files
                        CppCompileEnvironment ResourceCompileEnvironment = new CppCompileEnvironment(BinaryCompileEnvironment);

                        // @todo: This should be in some Windows code somewhere...
                        // Set the original file name macro; used in Default.rc2 to set the binary metadata fields.
                        ResourceCompileEnvironment.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OutputFilePaths[0].GetFileName() + "\"");

                        // Set the other version fields
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILT_FROM_CHANGELIST={0}", Target.Version.Changelist));
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILD_VERSION={0}", Target.BuildVersion));

                        // Otherwise compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "Windows", "Resources", "Default.rc2"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(ResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ResourceIntermediateDirectory, Makefile.Actions);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                }
            }

            // Add all the common resource files
            BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);

            return(BinaryLinkEnvironment);
        }
示例#39
0
 /// <summary>
 /// Checks if the specified file is a C++ source header file (e.g., .h or .inl)
 /// </summary>
 /// <param name="FileItem">The file to check</param>
 /// <returns>True if this is a C++ source file</returns>
 private static bool IsCPPIncludeFile( FileItem FileItem )
 {
     return( FileItem.AbsolutePath.EndsWith( ".h", StringComparison.InvariantCultureIgnoreCase ) ||
             FileItem.AbsolutePath.EndsWith( ".inl", StringComparison.InvariantCultureIgnoreCase ) );
 }
示例#40
0
        /**
         * Determines the full set of actions that must be built to produce an item.
         * @param OutputItem - The item to be built.
         * @param PrerequisiteActions - The actions that must be built and the root action are
         */
        public static void GatherPrerequisiteActions(
			FileItem OutputItem,
			ref HashSet<Action> PrerequisiteActions
			)
        {
            if (OutputItem != null && OutputItem.ProducingAction != null)
            {
                if (!PrerequisiteActions.Contains(OutputItem.ProducingAction))
                {
                    PrerequisiteActions.Add(OutputItem.ProducingAction);
                    foreach (FileItem PrerequisiteItem in OutputItem.ProducingAction.PrerequisiteItems)
                    {
                        GatherPrerequisiteActions(PrerequisiteItem, ref PrerequisiteActions);
                    }
                }
            }
        }
示例#41
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, UEBuildPlatform 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.
                List <DependencyInclude> DirectIncludes = GetDirectIncludeDependencies(Target, CPPFile, BuildPlatform, bOnlyCachedDependencies: bOnlyCachedDependencies);

                // 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.HasAttemptedResolve ||
                        // 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.Reference : null);
                    }
                    else
                    {
                        // we might have cached an attempt to resolve the file, but couldn't actually find the file (system headers, etc).
                        if (DirectInclude.IncludeResolvedNameIfSuccessful != null)
                        {
                            DirectlyIncludedFiles.Add(FileItem.GetItemByFileReference(DirectInclude.IncludeResolvedNameIfSuccessful));
                        }
                    }
                }
                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);
            }
        }
 /// <summary>
 /// Checks if the given file is part of the working set
 /// </summary>
 /// <param name="File">File to check</param>
 /// <returns>True if the file is part of the working set, false otherwise</returns>
 public bool Contains(FileItem File)
 {
     return(false);
 }
示例#43
0
 /// <summary>
 /// Checks if the specified file is a C++ source implementation file (e.g., .cpp)
 /// </summary>
 /// <param name="FileItem">The file to check</param>
 /// <returns>True if this is a C++ source file</returns>
 private static bool IsCPPImplementationFile( FileItem FileItem )
 {
     return( FileItem.AbsolutePath.EndsWith( ".cpp", StringComparison.InvariantCultureIgnoreCase ) ||
             FileItem.AbsolutePath.EndsWith( ".c", StringComparison.InvariantCultureIgnoreCase ) ||
             FileItem.AbsolutePath.EndsWith( ".mm", StringComparison.InvariantCultureIgnoreCase ) );
 }
示例#44
0
        /// <summary>
        /// Finds the names of files directly included by the given C++ file, and also whether the file contains any UObjects
        /// </summary>
        public static List <DependencyInclude> GetDirectIncludeDependencies(UEBuildTarget Target, FileItem CPPFile, UEBuildPlatform BuildPlatform, bool bOnlyCachedDependencies)
        {
            // Try to fulfill request from cache first.
            List <DependencyInclude> Info = IncludeDependencyCache[Target].GetCachedDependencyInfo(CPPFile);

            if (Info != null)
            {
                return(Info);
            }

            var Result = new List <DependencyInclude>();

            if (bOnlyCachedDependencies)
            {
                return(Result);
            }

            var TimerStartTime = DateTime.UtcNow;

            ++CPPEnvironment.TotalDirectIncludeCacheMisses;

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

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

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

            if (string.IsNullOrEmpty(FileContents))
            {
                return(Result);
            }

            // 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);
            }

            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;
                    }

                    Result.AddRange(CollectHeaders(Target.ProjectFile, CPPFile, FileToRead, FileContents, InstalledFolder, StartIndex, EndIndex));

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

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

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

            return(Result);
        }
示例#45
0
 /// <summary>
 /// Checks if the specified file is a C++ resource file (e.g., .rc)
 /// </summary>
 /// <param name="FileItem">The file to check</param>
 /// <returns>True if this is a C++ source file</returns>
 private static bool IsCPPResourceFile( FileItem FileItem )
 {
     return( FileItem.AbsolutePath.EndsWith( ".rc", StringComparison.InvariantCultureIgnoreCase ) );
 }
示例#46
0
        /// <summary>
        /// Collects all header files included in a CPPFile
        /// </summary>
        /// <param name="CPPFile"></param>
        /// <param name="FileToRead"></param>
        /// <param name="FileContents"></param>
        /// <param name="InstalledFolder"></param>
        /// <param name="StartIndex"></param>
        /// <param name="EndIndex"></param>
        private static List <DependencyInclude> CollectHeaders(FileReference ProjectFile, FileItem CPPFile, string FileToRead, string FileContents, string InstalledFolder, int StartIndex, int EndIndex)
        {
            var Result = new List <DependencyInclude>();

            Match             M        = CPPHeaderRegex.Match(FileContents, StartIndex, EndIndex - StartIndex);
            CaptureCollection Captures = M.Groups["HeaderFile"].Captures;

            Result.Capacity = Result.Count;
            foreach (Capture C in Captures)
            {
                string HeaderValue = C.Value;

                if (HeaderValue.IndexOfAny(Path.GetInvalidPathChars()) != -1)
                {
                    throw new BuildException("In {0}: An #include statement contains invalid characters.  You might be missing a double-quote character. (\"{1}\")", FileToRead, C.Value);
                }

                //@TODO: The intermediate exclusion is to work around autogenerated absolute paths in Module.SomeGame.cpp style files
                bool bCheckForBackwardSlashes = FileToRead.StartsWith(InstalledFolder) || ((ProjectFile != null) && new FileReference(FileToRead).IsUnderDirectory(ProjectFile.Directory));
                if (bCheckForBackwardSlashes && !FileToRead.Contains("Intermediate") && !FileToRead.Contains("ThirdParty") && HeaderValue.IndexOf('\\', 0) >= 0)
                {
                    throw new BuildException("In {0}: #include \"{1}\" contains backslashes ('\\'), please use forward slashes ('/') instead.", FileToRead, C.Value);
                }
                HeaderValue = Utils.CleanDirectorySeparators(HeaderValue);
                Result.Add(new DependencyInclude(HeaderValue));
            }

            // also look for #import in objective C files
            string Ext = Path.GetExtension(CPPFile.AbsolutePath).ToUpperInvariant();

            if (Ext == ".MM" || Ext == ".M")
            {
                M                = MMHeaderRegex.Match(FileContents, StartIndex, EndIndex - StartIndex);
                Captures         = M.Groups["HeaderFile"].Captures;
                Result.Capacity += Captures.Count;
                foreach (Capture C in Captures)
                {
                    Result.Add(new DependencyInclude(C.Value));
                }
            }

            return(Result);
        }
示例#47
0
		protected void AddPrerequisiteSourceFile(UEBuildTarget Target, UEBuildPlatform BuildPlatform, CPPEnvironment CompileEnvironment, FileItem SourceFile, List<FileItem> PrerequisiteItems)
		{
			PrerequisiteItems.Add(SourceFile);

			RemoteToolChain 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
				List<FileItem> 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);
						}
					}
				}
			}
		}
示例#48
0
        /// <summary>
        /// Given a set of C++ files, generates another set of C++ files that #include all the original
        /// files, the goal being to compile the same code in fewer translation units.
        /// The "unity" files are written to the CompileEnvironment's OutputDirectory.
        /// </summary>
        /// <param name="Target">The target we're building</param>
        /// <param name="CPPFiles">The C++ files to #include.</param>
        /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param>
        /// <param name="WorkingSet">Interface to query files which belong to the working set</param>
        /// <param name="BaseName">Base name to use for the Unity files</param>
        /// <returns>The "unity" C++ files.</returns>
        public static List <FileItem> GenerateUnityCPPs(
            ReadOnlyTargetRules Target,
            List <FileItem> CPPFiles,
            CppCompileEnvironment CompileEnvironment,
            ISourceFileWorkingSet WorkingSet,
            string BaseName
            )
        {
            List <FileItem> NewCPPFiles = new List <FileItem>();

            UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Platform);

            // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not.
            long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Info.Length);

            // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This
            // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X
            // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file.


            // When enabled, UnrealBuildTool will try to determine source files that you are actively iteratively changing, and break those files
            // out of their unity blobs so that you can compile them as individual translation units, much faster than recompiling the entire
            // unity blob each time.
            bool bUseAdaptiveUnityBuild = Target.bUseAdaptiveUnityBuild && !Target.bStressTestUnity;

            // Optimization only makes sense if PCH files are enabled.
            bool bForceIntoSingleUnityFile = Target.bStressTestUnity || (TotalBytesInCPPFiles < Target.NumIncludedBytesPerUnityCPP * 2 && Target.bUsePCHFiles);

            // Build the list of unity files.
            List <FileCollection> AllUnityFiles;
            {
                // Sort the incoming file paths alphabetically, so there will be consistency in unity blobs across multiple machines.
                // Note that we're relying on this not only sorting files within each directory, but also the directories
                // themselves, so the whole list of file paths is the same across computers.
                List <FileItem> SortedCPPFiles = CPPFiles.GetRange(0, CPPFiles.Count);
                {
                    // Case-insensitive file path compare, because you never know what is going on with local file systems
                    Comparison <FileItem> FileItemComparer = (FileA, FileB) => { return(FileA.AbsolutePath.ToLowerInvariant().CompareTo(FileB.AbsolutePath.ToLowerInvariant())); };
                    SortedCPPFiles.Sort(FileItemComparer);
                }


                // Figure out whether we REALLY want to use adaptive unity for this module.  If nearly every file in the module appears in the working
                // set, we'll just go ahead and let unity build do its thing.
                if (bUseAdaptiveUnityBuild)
                {
                    int CandidateWorkingSetSourceFileCount = 0;
                    int WorkingSetSourceFileCount          = 0;
                    foreach (FileItem CPPFile in SortedCPPFiles)
                    {
                        ++CandidateWorkingSetSourceFileCount;

                        // Don't include writable source files into unity blobs
                        if (WorkingSet.Contains(CPPFile.Reference))
                        {
                            ++WorkingSetSourceFileCount;

                            // Mark this file as part of the working set.  This will be saved into the UBT Makefile so that
                            // the assembler can automatically invalidate the Makefile when the working set changes (allowing this
                            // code to run again, to build up new unity blobs.)
                            SourceFileWorkingSet.Add(CPPFile);
                        }
                    }

                    if (WorkingSetSourceFileCount >= CandidateWorkingSetSourceFileCount)
                    {
                        // Every single file in the module appears in the working set, so don't bother using adaptive unity for this
                        // module.  Otherwise it would make full builds really slow.
                        bUseAdaptiveUnityBuild = false;
                    }
                }

                UnityFileBuilder CPPUnityFileBuilder          = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : Target.NumIncludedBytesPerUnityCPP);
                StringBuilder    AdaptiveUnityBuildInfoString = new StringBuilder();
                foreach (FileItem CPPFile in SortedCPPFiles)
                {
                    if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.IndexOf(".GeneratedWrapper.", StringComparison.InvariantCultureIgnoreCase) != -1)
                    {
                        NewCPPFiles.Add(CPPFile);
                    }

                    // When adaptive unity is enabled, go ahead and exclude any source files that we're actively working with
                    if (bUseAdaptiveUnityBuild && SourceFileWorkingSet.Contains(CPPFile))
                    {
                        // Just compile this file normally, not as part of the unity blob
                        NewCPPFiles.Add(CPPFile);

                        // Let the unity file builder know about the file, so that we can retain the existing size of the unity blobs.
                        // This won't actually make the source file part of the unity blob, but it will keep track of how big the
                        // file is so that other existing unity blobs from the same module won't be invalidated.  This prevents much
                        // longer compile times the first time you build after your working file set changes.
                        CPPUnityFileBuilder.AddVirtualFile(CPPFile);

                        string CPPFileName = Path.GetFileName(CPPFile.AbsolutePath);
                        if (AdaptiveUnityBuildInfoString.Length == 0)
                        {
                            AdaptiveUnityBuildInfoString.Append(String.Format("[Adaptive unity build] Excluded from {0} unity file: {1}", BaseName, CPPFileName));
                        }
                        else
                        {
                            AdaptiveUnityBuildInfoString.Append(", " + CPPFileName);
                        }
                    }

                    else
                    {
                        // If adaptive unity build is enabled for this module, add this source file to the set that will invalidate the makefile
                        if (bUseAdaptiveUnityBuild)
                        {
                            CandidateSourceFilesForWorkingSet.Add(CPPFile);
                        }

                        // Compile this file as part of the unity blob
                        CPPUnityFileBuilder.AddFile(CPPFile);

                        // Now that the CPPFile is part of this unity file, we will no longer need to treat it like a root level prerequisite for our
                        // dependency cache, as it is now an "indirect include" from the unity file.  We'll clear out the compile environment
                        // attached to this file.  This prevents us from having to cache all of the indirect includes from these files inside our
                        // dependency cache, which speeds up iterative builds a lot!
                        CPPFile.CachedIncludePaths = null;
                    }
                }

                if (AdaptiveUnityBuildInfoString.Length > 0)
                {
                    if (PrintedSettingsForTargets.Add(Target.Name))
                    {
                        if (Target.bAdaptiveUnityDisablesPCH)
                        {
                            Log.TraceInformation("[Adaptive unity build] Disabling PCH for excluded files. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to change this behavior.");
                        }
                        if (Target.bAdaptiveUnityDisablesOptimizations)
                        {
                            Log.TraceInformation("[Adaptive unity build] Disabling optimizations for excluded files. Set bAdaptiveUnityDisablesOptimizations to false in BuildConfiguration.xml to change this behavior.");
                        }
                    }
                    Log.TraceInformation(AdaptiveUnityBuildInfoString.ToString());
                }

                AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles();
            }

            // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding
            // actions to compile them.
            int CurrentUnityFileCount = 0;

            foreach (FileCollection UnityFile in AllUnityFiles)
            {
                ++CurrentUnityFileCount;

                StringWriter OutputUnityCPPWriter = new StringWriter();

                OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files.");

                // Add source files to the unity file
                foreach (FileItem CPPFile in UnityFile.Files)
                {
                    string IncludePath;
                    if (BuildPlatform.UseAbsolutePathsInUnityFiles())
                    {
                        IncludePath = CPPFile.AbsolutePath;
                    }
                    else
                    {
                        // @todo: MakeRelativeTo does not work with code projects on a different drive than the engine. reverting to old version until we can come
                        // up with a better solution
                        IncludePath = RemoteExports.ConvertPath(CPPFile.AbsolutePath).Replace('\\', '/');
                    }
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", IncludePath);
                }

                // Determine unity file path name
                string UnityCPPFileName;
                if (AllUnityFiles.Count > 1)
                {
                    UnityCPPFileName = string.Format("{0}{1}.{2}_of_{3}.cpp", ModulePrefix, BaseName, CurrentUnityFileCount, AllUnityFiles.Count);
                }
                else
                {
                    UnityCPPFileName = string.Format("{0}{1}.cpp", ModulePrefix, BaseName);
                }
                FileReference UnityCPPFilePath = FileReference.Combine(CompileEnvironment.OutputDirectory, UnityCPPFileName);

                // Write the unity file to the intermediate folder.
                FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString());

                UnityCPPFile.RelativeCost = UnityFile.TotalLength;
                NewCPPFiles.Add(UnityCPPFile);

                // Cache information about the unity .cpp dependencies
                // @todo ubtmake urgent: Fails when building remotely for Mac because unity .cpp has an include for a PCH on the REMOTE machine
                UEBuildModuleCPP.CachePCHUsageForModuleSourceFile(CompileEnvironment, UnityCPPFile);
            }

            return(NewCPPFiles);
        }
示例#49
0
		public virtual ICollection<FileItem> PostBuild(FileItem Executable, LinkEnvironment ExecutableLinkEnvironment)
		{
			return new List<FileItem>();
		}
示例#50
0
        /**
         * Builds and runs the header tool and touches the header directories.
         * Performs any early outs if headers need no changes, given the UObject modules, tool path, game name, and configuration
         */
        public static bool ExecuteHeaderToolIfNecessary(UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List <UHTModuleInfo> UObjectModules, string ModuleInfoFileName, ref ECompilationResult UHTResult)
        {
            using (ProgressWriter Progress = new ProgressWriter("Generating code...", false))
            {
                // We never want to try to execute the header tool when we're already trying to build it!
                var bIsBuildingUHT = Target.GetTargetName().Equals("UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase);

                var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform);
                var CppPlatform   = BuildPlatform.GetCPPTargetPlatform(Target.Platform);
                var ToolChain     = UEToolChain.GetPlatformToolChain(CppPlatform);
                var RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath);


                // ensure the headers are up to date
                bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || AreGeneratedCodeFilesOutOfDate(UObjectModules));
                if (bUHTNeedsToRun || UnrealBuildTool.IsGatheringBuild)
                {
                    // Since code files are definitely out of date, we'll now finish computing information about the UObject modules for UHT.  We
                    // want to save this work until we know that UHT actually needs to be run to speed up best-case iteration times.
                    if (UnrealBuildTool.IsGatheringBuild)                               // In assembler-only mode, PCH info is loaded from our UBTMakefile!
                    {
                        foreach (var UHTModuleInfo in UObjectModules)
                        {
                            // Only cache the PCH name if we don't already have one.  When running in 'gather only' mode, this will have already been cached
                            if (string.IsNullOrEmpty(UHTModuleInfo.PCH))
                            {
                                UHTModuleInfo.PCH = "";

                                // We need to figure out which PCH header this module is including, so that UHT can inject an include statement for it into any .cpp files it is synthesizing
                                var DependencyModuleCPP      = (UEBuildModuleCPP)Target.GetModuleByName(UHTModuleInfo.ModuleName);
                                var ModuleCompileEnvironment = DependencyModuleCPP.CreateModuleCompileEnvironment(GlobalCompileEnvironment);
                                DependencyModuleCPP.CachePCHUsageForModuleSourceFiles(ModuleCompileEnvironment);
                                if (DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile != null)
                                {
                                    UHTModuleInfo.PCH = DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath;
                                }
                            }
                        }
                    }
                }

                // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run!  Can't we use the existing copy?  (see below use of Manifest)
                UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules);

                if (!bIsBuildingUHT && bUHTNeedsToRun)
                {
                    // Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem or hot-reloading
                    if (UnrealBuildTool.RunningRocket() == false &&
                        UEBuildConfiguration.bDoNotBuildUHT == false &&
                        UEBuildConfiguration.bHotReloadFromIDE == false &&
                        !(!UnrealBuildTool.IsGatheringBuild && UnrealBuildTool.IsAssemblingBuild))                              // If running in "assembler only" mode, we assume UHT is already up to date for much faster iteration!
                    {
                        // If it is out of date or not there it will be built.
                        // If it is there and up to date, it will add 0.8 seconds to the build time.
                        Log.TraceInformation("Building UnrealHeaderTool...");

                        var UBTArguments = new StringBuilder();

                        UBTArguments.Append("UnrealHeaderTool");

                        // Which desktop platform do we need to compile UHT for?
                        UBTArguments.Append(" " + BuildHostPlatform.Current.Platform.ToString());
                        // NOTE: We force Development configuration for UHT so that it runs quickly, even when compiling debug
                        UBTArguments.Append(" " + UnrealTargetConfiguration.Development.ToString());

                        // NOTE: We disable mutex when launching UBT from within UBT to compile UHT
                        UBTArguments.Append(" -NoMutex");

                        if (UnrealBuildTool.CommandLineContains("-noxge"))
                        {
                            UBTArguments.Append(" -noxge");
                        }

                        if (RunExternalExecutable(UnrealBuildTool.GetUBTPath(), UBTArguments.ToString()) != 0)
                        {
                            return(false);
                        }
                    }

                    Progress.Write(1, 3);

                    var ActualTargetName = String.IsNullOrEmpty(Target.GetTargetName()) ? "UE4" : Target.GetTargetName();
                    Log.TraceInformation("Parsing headers for {0}", ActualTargetName);

                    string HeaderToolPath = GetHeaderToolPath();
                    if (!File.Exists(HeaderToolPath))
                    {
                        throw new BuildException("Unable to generate headers because UnrealHeaderTool binary was not found ({0}).", Path.GetFullPath(HeaderToolPath));
                    }

                    // Disable extensions when serializing to remove the $type fields
                    Directory.CreateDirectory(Path.GetDirectoryName(ModuleInfoFileName));
                    System.IO.File.WriteAllText(ModuleInfoFileName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters {
                        UseExtensions = false
                    }));

                    string CmdLine = (UnrealBuildTool.HasUProjectFile()) ? "\"" + UnrealBuildTool.GetUProjectFile() + "\"" : Target.GetTargetName();
                    CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\"";
                    if (UnrealBuildTool.RunningRocket())
                    {
                        CmdLine += " -rocket -installed";
                    }

                    if (UEBuildConfiguration.bFailIfGeneratedCodeChanges)
                    {
                        CmdLine += " -FailIfGeneratedCodeChanges";
                    }

                    Stopwatch s = new Stopwatch();
                    s.Start();
                    UHTResult = (ECompilationResult)RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine);
                    s.Stop();

                    if (UHTResult != ECompilationResult.Succeeded)
                    {
                        Log.TraceInformation("Error: Failed to generate code for {0} - error code: {2} ({1})", ActualTargetName, (int)UHTResult, UHTResult.ToString());
                        return(false);
                    }

                    Log.TraceInformation("Reflection code generated for {0}", ActualTargetName);
                    if (BuildConfiguration.bPrintPerformanceInfo)
                    {
                        Log.TraceInformation("UnrealHeaderTool took {1}", ActualTargetName, (double)s.ElapsedMilliseconds / 1000.0);
                    }

                    // Now that UHT has successfully finished generating code, we need to update all cached FileItems in case their last write time has changed.
                    // Otherwise UBT might not detect changes UHT made.
                    DateTime StartTime = DateTime.UtcNow;
                    FileItem.ResetInfos();
                    double ResetDuration = (DateTime.UtcNow - StartTime).TotalSeconds;
                    Log.TraceVerbose("FileItem.ResetInfos() duration: {0}s", ResetDuration);
                }
                else
                {
                    Log.TraceVerbose("Generated code is up to date.");
                }

                Progress.Write(2, 3);

                // There will never be generated code if we're building UHT, so this should never be called.
                if (!bIsBuildingUHT)
                {
                    // Allow generated code to be sync'd to remote machines if needed. This needs to be done even if UHT did not run because
                    // generated headers include other generated headers using absolute paths which in case of building remotely are already
                    // the remote machine absolute paths. Because of that parsing headers will not result in finding all includes properly.
                    // @todo ubtmake: Need to figure out what this does in the assembler case, and whether we need to run it
                    ToolChain.PostCodeGeneration(Manifest);
                }

                // touch the directories
                UpdateDirectoryTimestamps(UObjectModules);

                Progress.Write(3, 3);
            }
            return(true);
        }
示例#51
0
		/// <summary>
		/// Gets information about this file from our dependency cache.  Only returns information if the file has already been 
		/// cached, and the file has not been changed since the last time we updated our cache
		/// </summary>
		/// <param name="File">The file to check</param>
		/// <returns>Information about this dependency, or null if we have nothing cached</returns>
		DependencyInfo? GetCachedDependencyInfo( FileItem File )
		{
			// Check whether File is in cache.
			DependencyInfo DependencyInfo;
			if (DependencyMap.TryGetValue(File.AbsolutePath.ToLowerInvariant(), out DependencyInfo))
			{
				// File is in cache, now check whether last write time is prior to cache creation time.
				if (File.LastWriteTime < CacheCreateDate)
				{
					return DependencyInfo;					
				}
				else
				{
					// Remove entry from cache as it's stale.
					RemoveFileFromCache(File.AbsolutePath);
					return null;
				}
			}

			return null;
		}
 /// <summary>
 /// Get the name of the response file for the current linker environment and output file
 /// </summary>
 /// <param name="LinkEnvironment"></param>
 /// <param name="OutputFile"></param>
 /// <returns></returns>
 public static FileReference GetResponseFileName(LinkEnvironment LinkEnvironment, FileItem OutputFile)
 {
     // Construct a relative path for the intermediate response file
     return(FileReference.Combine(LinkEnvironment.IntermediateDirectory, OutputFile.Reference.GetFileName() + ".response"));
 }
示例#53
0
		/**
		 * Update cache with dependencies for the passed in file.
		 * 
		 * @param	File			File to update dependencies for
		 * @param	Dependencies	List of dependencies to cache for passed in file
		 * @param	HasUObjects		True if this file was found to contain UObject classes or types
		 */
		public void SetDependencyInfo(FileItem File, List<DependencyInclude> DirectDependencies, bool HasUObjects)
		{
			DependencyMap[File.AbsolutePath.ToLowerInvariant()] = new DependencyInfo() { Includes = DirectDependencies, HasUObjects = HasUObjects };
			bIsDirty = true;
		}
 public virtual ICollection <FileItem> PostBuild(FileItem Executable, LinkEnvironment ExecutableLinkEnvironment, ActionGraph ActionGraph)
 {
     return(new List <FileItem>());
 }
		FileItem FixDylibDependencies(LinkEnvironment LinkEnvironment, FileItem Executable)
		{
			Action LinkAction = new Action(ActionType.Link);
			LinkAction.WorkingDirectory = Path.GetFullPath(".");
			LinkAction.CommandPath = "/bin/sh";
			LinkAction.CommandDescription = "";

			// Call the FixDylibDependencies.sh script which will link the dylibs and the main executable, this time proper ones, as it's called
			// once all are already created, so the cross dependency problem no longer prevents linking.
			// The script is deleted after it's executed so it's empty when we start appending link commands for the next executable.
			FileItem FixDylibDepsScript = FileItem.GetItemByFullPath(Path.Combine(LinkEnvironment.Config.LocalShadowDirectory, "FixDylibDependencies.sh"));
			FileItem RemoteFixDylibDepsScript = LocalToRemoteFileItem(FixDylibDepsScript, true);

			LinkAction.CommandArguments = "-c 'chmod +x \"" + RemoteFixDylibDepsScript.AbsolutePath + "\"; \"" + RemoteFixDylibDepsScript.AbsolutePath + "\"; if [[ $? -ne 0 ]]; then exit 1; fi; ";

			if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
			{
				LinkAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
			}

			// Make sure this action is executed after all the dylibs and the main executable are created

			foreach (FileItem Dependency in BundleDependencies)
			{
				LinkAction.PrerequisiteItems.Add(Dependency);
			}

			BundleDependencies.Clear();

			LinkAction.StatusDescription = string.Format("Fixing dylib dependencies for {0}", Path.GetFileName(Executable.AbsolutePath));
			LinkAction.bCanExecuteRemotely = false;

			FileItem OutputFile = FileItem.GetItemByPath(Path.Combine(LinkEnvironment.Config.LocalShadowDirectory, Path.GetFileNameWithoutExtension(Executable.AbsolutePath) + ".link"));
			FileItem RemoteOutputFile = LocalToRemoteFileItem(OutputFile, false);

			LinkAction.CommandArguments += "echo \"Dummy\" >> \"" + RemoteOutputFile.AbsolutePath + "\"";
			LinkAction.CommandArguments += "'";

			LinkAction.ProducedItems.Add(RemoteOutputFile);

			return RemoteOutputFile;
		}
        protected virtual void AddPrerequisiteSourceFile(CppCompileEnvironment CompileEnvironment, FileItem SourceFile, List <FileItem> PrerequisiteItems)
        {
            PrerequisiteItems.Add(SourceFile);

            if (!CompileEnvironment.Headers.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
                List <FileItem> IncludedFileList = CompileEnvironment.Headers.FindAndCacheAllIncludedFiles(SourceFile, CompileEnvironment.IncludePaths, bOnlyCachedDependencies: false);
                if (IncludedFileList != null)
                {
                    foreach (FileItem IncludedFile in IncludedFileList)
                    {
                        PrerequisiteItems.Add(IncludedFile);
                    }
                }
            }
        }
		/**
		 * Creates app bundle for a given executable
		 *
		 * @param Executable FileItem describing the executable to generate app bundle for
		 */
		FileItem FinalizeAppBundle(LinkEnvironment LinkEnvironment, FileItem Executable, FileItem FixDylibOutputFile)
		{
			// Make a file item for the source and destination files
			string FullDestPath = Executable.AbsolutePath.Substring(0, Executable.AbsolutePath.IndexOf(".app") + 4);
			FileItem DestFile = FileItem.GetItemByPath(FullDestPath);
			FileItem RemoteDestFile = LocalToRemoteFileItem(DestFile, false);

			// Make the compile action
			Action FinalizeAppBundleAction = new Action(ActionType.CreateAppBundle);
			FinalizeAppBundleAction.WorkingDirectory = Path.GetFullPath(".");
			FinalizeAppBundleAction.CommandPath = "/bin/sh";
			FinalizeAppBundleAction.CommandDescription = "";

			// make path to the script
			FileItem BundleScript = FileItem.GetItemByFullPath(Path.Combine(LinkEnvironment.Config.IntermediateDirectory, "FinalizeAppBundle.sh"));
			FileItem RemoteBundleScript = LocalToRemoteFileItem(BundleScript, true);

			if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
			{
				FinalizeAppBundleAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
			}

			FinalizeAppBundleAction.CommandArguments = "\"" + RemoteBundleScript.AbsolutePath + "\"";
			FinalizeAppBundleAction.PrerequisiteItems.Add(FixDylibOutputFile);
			FinalizeAppBundleAction.ProducedItems.Add(RemoteDestFile);
			FinalizeAppBundleAction.StatusDescription = string.Format("Finalizing app bundle: {0}.app", Path.GetFileName(Executable.AbsolutePath));
			FinalizeAppBundleAction.bCanExecuteRemotely = false;

			return RemoteDestFile;
		}
示例#58
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            var EnvVars = VCEnvironment.SetEnvironment(CompileEnvironment.Config.Target.Platform);

            StringBuilder Arguments = new StringBuilder();

            AppendCLArguments_Global(CompileEnvironment, EnvVars, Arguments);

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
            {
                string IncludePathRelative = Utils.CleanDirectorySeparators(Utils.MakePathRelativeTo(IncludePath, Path.Combine(ProjectFileGenerator.RootRelativePath, "Engine/Source")), '/');
                Arguments.AppendFormat(" /I \"{0}\"", IncludePathRelative);
            }
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
            {
                string IncludePathRelative = Utils.CleanDirectorySeparators(Utils.MakePathRelativeTo(IncludePath, Path.Combine(ProjectFileGenerator.RootRelativePath, "Engine/Source")), '/');
                Arguments.AppendFormat(" /I \"{0}\"", IncludePathRelative);
            }


            if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled)
            {
                // Add .NET framework assembly paths.  This is needed so that C++/CLI projects
                // can reference assemblies with #using, without having to hard code a path in the
                // .cpp file to the assembly's location.
                foreach (string AssemblyPath in CompileEnvironment.Config.SystemDotNetAssemblyPaths)
                {
                    Arguments.AppendFormat(" /AI \"{0}\"", AssemblyPath);
                }

                // Add explicit .NET framework assembly references
                foreach (string AssemblyName in CompileEnvironment.Config.FrameworkAssemblyDependencies)
                {
                    Arguments.AppendFormat(" /FU \"{0}\"", AssemblyName);
                }

                // Add private assembly references
                foreach (PrivateAssemblyInfo CurAssemblyInfo in CompileEnvironment.PrivateAssemblyDependencies)
                {
                    Arguments.AppendFormat(" /FU \"{0}\"", CurAssemblyInfo.FileItem.AbsolutePath);
                }
            }


            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                // Escape all quotation marks so that they get properly passed with the command line.
                var DefinitionArgument = Definition.Contains("\"") ? Definition.Replace("\"", "\\\"") : Definition;
                Arguments.AppendFormat(" /D\"{0}\"", DefinitionArgument);
            }

            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                CompileAction.CommandDescription = "Compile";

                StringBuilder FileArguments = new StringBuilder();
                bool          bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C";

                // Add the C++ source file and its included files to the prerequisite item list.
                AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);

                // If this is a CLR file then make sure our dependent assemblies are added as prerequisites
                if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled)
                {
                    foreach (PrivateAssemblyInfo CurPrivateAssemblyDependency in CompileEnvironment.PrivateAssemblyDependencies)
                    {
                        CompileAction.PrerequisiteItems.Add(CurPrivateAssemblyDependency.FileItem);
                    }
                }

                bool bEmitsObjectFile = true;
                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    // Generate a CPP File that just includes the precompiled header.
                    string   PCHCPPFilename = "PCH." + ModuleName + "." + Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename) + ".cpp";
                    string   PCHCPPPath     = Path.Combine(CompileEnvironment.Config.OutputDirectory, PCHCPPFilename);
                    FileItem PCHCPPFile     = FileItem.CreateIntermediateTextFile(
                        PCHCPPPath,
                        string.Format("#include \"{0}\"\r\n", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename)
                        );

                    // Make sure the original source directory the PCH header file existed in is added as an include
                    // path -- it might be a private PCH header and we need to make sure that its found!
                    string OriginalPCHHeaderDirectory = Path.GetDirectoryName(SourceFile.AbsolutePath);
                    FileArguments.AppendFormat(" /I \"{0}\"", OriginalPCHHeaderDirectory);

                    var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.UWP].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
                    // Add the precompiled header file to the produced items list.
                    FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + PrecompiledFileExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
                    Result.PrecompiledHeaderFile = PrecompiledHeaderFile;

                    // Add the parameters needed to compile the precompiled header file to the command-line.
                    FileArguments.AppendFormat(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                    FileArguments.AppendFormat(" /Fp\"{0}\"", PrecompiledHeaderFile.AbsolutePath);

                    // If we're creating a PCH that will be used to compile source files for a library, we need
                    // the compiled modules to retain a reference to PCH's module, so that debugging information
                    // will be included in the library.  This is also required to avoid linker warning "LNK4206"
                    // when linking an application that uses this library.
                    if (CompileEnvironment.Config.bIsBuildingLibrary)
                    {
                        // NOTE: The symbol name we use here is arbitrary, and all that matters is that it is
                        // unique per PCH module used in our library
                        string FakeUniquePCHSymbolName = Path.GetFileNameWithoutExtension(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                        FileArguments.AppendFormat(" /Yl{0}", FakeUniquePCHSymbolName);
                    }

                    FileArguments.AppendFormat(" \"{0}\"", PCHCPPFile.AbsolutePath);

                    CompileAction.StatusDescription = PCHCPPFilename;
                }
                else
                {
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        CompileAction.bIsUsingPCH = true;
                        CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile);

                        FileArguments.AppendFormat(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                        FileArguments.AppendFormat(" /Fp\"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath);

                        // Is it unsafe to always force inclusion?  Clang is doing it, and .generated.cpp files
                        // won't work otherwise, because they're not located in the context of the module,
                        // so they can't access the module's PCH without an absolute path.
                        //if( CompileEnvironment.Config.bForceIncludePrecompiledHeader )
                        {
                            // Force include the precompiled header file.  This is needed because we may have selected a
                            // precompiled header that is different than the first direct include in the C++ source file, but
                            // we still need to make sure that our precompiled header is the first thing included!
                            FileArguments.AppendFormat(" /FI\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                        }
                    }

                    // Add the source file path to the command-line.
                    FileArguments.AppendFormat(" \"{0}\"", SourceFile.AbsolutePath);

                    CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath);
                }

                if (bEmitsObjectFile)
                {
                    var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.UWP].GetBinaryExtension(UEBuildBinaryType.Object);
                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(ObjectFile);
                    Result.ObjectFiles.Add(ObjectFile);
                    FileArguments.AppendFormat(" /Fo\"{0}\"", ObjectFile.AbsolutePath);
                }

                // Create PDB files if we were configured to do that.
                //
                // Also, when debug info is off and XGE is enabled, force PDBs, otherwise it will try to share
                // a PDB file, which causes PCH creation to be serial rather than parallel (when debug info is disabled)
                //		--> See https://udn.epicgames.com/lists/showpost.php?id=50619&list=unprog3
                if (BuildConfiguration.bUsePDBFiles ||
                    (BuildConfiguration.bAllowXGE && !CompileEnvironment.Config.bCreateDebugInfo))
                {
                    string PDBFileName;
                    bool   bActionProducesPDB = false;

                    // All files using the same PCH are required to share the same PDB that was used when compiling the PCH
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        PDBFileName = "PCH." + ModuleName + "." + Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                    }
                    // Files creating a PCH use a PDB per file.
                    else if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                    {
                        PDBFileName        = "PCH." + ModuleName + "." + Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                        bActionProducesPDB = true;
                    }
                    // Ungrouped C++ files use a PDB per file.
                    else if (!bIsPlainCFile)
                    {
                        PDBFileName        = Path.GetFileName(SourceFile.AbsolutePath);
                        bActionProducesPDB = true;
                    }
                    // Group all plain C files that doesn't use PCH into the same PDB
                    else
                    {
                        PDBFileName = "MiscPlainC";
                    }

                    // Specify the PDB file that the compiler should write to.
                    FileItem PDBFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            PDBFileName + ".pdb"
                            )
                        );
                    FileArguments.AppendFormat(" /Fd\"{0}\"", PDBFile.AbsolutePath);

                    // Only use the PDB as an output file if we want PDBs and this particular action is
                    // the one that produces the PDB (as opposed to no debug info, where the above code
                    // is needed, but not the output PDB, or when multiple files share a single PDB, so
                    // only the action that generates it should count it as output directly)
                    if (BuildConfiguration.bUsePDBFiles && bActionProducesPDB)
                    {
                        CompileAction.ProducedItems.Add(PDBFile);
                        Result.DebugDataFiles.Add(PDBFile);
                    }
                }

                // Add C or C++ specific compiler arguments.
                if (bIsPlainCFile)
                {
                    AppendCLArguments_C(FileArguments);
                }
                else
                {
                    AppendCLArguments_CPP(CompileEnvironment, FileArguments);
                }

                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                CompileAction.CommandPath      = EnvVars.CompilerPath;
                CompileAction.CommandArguments = Arguments.ToString() + FileArguments.ToString() + CompileEnvironment.Config.AdditionalArguments;

                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    Log.TraceVerbose("Creating PCH: " + CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                    Log.TraceVerbose("     Command: " + CompileAction.CommandArguments);
                }
                else
                {
                    Log.TraceVerbose("   Compiling: " + CompileAction.StatusDescription);
                    Log.TraceVerbose("     Command: " + CompileAction.CommandArguments);
                }

                // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves
                CompileAction.bShouldOutputStatusDescription = false;

                // Don't farm out creation of precompiled headers as it is the critical path task.
                CompileAction.bCanExecuteRemotely =
                    CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create ||
                    BuildConfiguration.bAllowRemotelyCompiledPCHs
                ;

                // @todo: XGE has problems remote compiling C++/CLI files that use .NET Framework 4.0
                if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled)
                {
                    CompileAction.bCanExecuteRemotely = false;
                }
            }
            return(Result);
        }
		public override ICollection<FileItem> PostBuild(FileItem Executable, LinkEnvironment BinaryLinkEnvironment)
		{
			var OutputFiles = base.PostBuild(Executable, BinaryLinkEnvironment);

			if (BinaryLinkEnvironment.Config.bIsBuildingLibrary)
			{
				return OutputFiles;
			}

			foreach (UEBuildBundleResource Resource in BinaryLinkEnvironment.Config.AdditionalBundleResources)
			{
				OutputFiles.Add(CopyBundleResource(Resource, Executable));
			}

			// If building for Mac on a Mac, use actions to finalize the builds (otherwise, we use Deploy)
			if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
			{
				return OutputFiles;
			}

			if (BinaryLinkEnvironment.Config.bIsBuildingDLL || BinaryLinkEnvironment.Config.bIsBuildingLibrary)
			{
				return OutputFiles;
			}

			FileItem FixDylibOutputFile = FixDylibDependencies(BinaryLinkEnvironment, Executable);
			OutputFiles.Add(FixDylibOutputFile);
			if (!BinaryLinkEnvironment.Config.bIsBuildingConsoleApplication)
			{
				OutputFiles.Add(FinalizeAppBundle(BinaryLinkEnvironment, Executable, FixDylibOutputFile));
			}

			return OutputFiles;
		}
示例#60
0
        public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List <FileItem> RCFiles)
        {
            var EnvVars = VCEnvironment.SetEnvironment(Environment.Config.Target.Platform);

            CPPOutput Result = new CPPOutput();

            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(Environment.Config.Target.Platform);

            foreach (FileItem RCFile in RCFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                CompileAction.CommandDescription = "Resource";
                CompileAction.WorkingDirectory   = Path.GetFullPath(".");
                CompileAction.CommandPath        = EnvVars.ResourceCompilerPath;
                CompileAction.StatusDescription  = Path.GetFileName(RCFile.AbsolutePath);

                // Suppress header spew
                CompileAction.CommandArguments += " /nologo";

                // If we're compiling for 64-bit Windows, also add the _WIN64 definition to the resource
                // compiler so that we can switch on that in the .rc file using #ifdef.
                CompileAction.CommandArguments += " /D_WIN64";

                // Language
                CompileAction.CommandArguments += " /l 0x409";

                // Include paths.
                foreach (string IncludePath in Environment.Config.CPPIncludeInfo.IncludePaths)
                {
                    CompileAction.CommandArguments += string.Format(" /i \"{0}\"", IncludePath);
                }

                // System include paths.
                foreach (var SystemIncludePath in Environment.Config.CPPIncludeInfo.SystemIncludePaths)
                {
                    CompileAction.CommandArguments += string.Format(" /i \"{0}\"", SystemIncludePath);
                }

                // Preprocessor definitions.
                foreach (string Definition in Environment.Config.Definitions)
                {
                    CompileAction.CommandArguments += string.Format(" /d \"{0}\"", Definition);
                }

                // Add the RES file to the produced item list.
                FileItem CompiledResourceFile = FileItem.GetItemByPath(
                    Path.Combine(
                        Environment.Config.OutputDirectory,
                        Path.GetFileName(RCFile.AbsolutePath) + ".res"
                        )
                    );
                CompileAction.ProducedItems.Add(CompiledResourceFile);
                CompileAction.CommandArguments += string.Format(" /fo \"{0}\"", CompiledResourceFile.AbsolutePath);
                Result.ObjectFiles.Add(CompiledResourceFile);

                // Add the RC file as a prerequisite of the action.
                CompileAction.CommandArguments += string.Format(" \"{0}\"", RCFile.AbsolutePath);

                // Add the C++ source file and its included files to the prerequisite item list.
                AddPrerequisiteSourceFile(Target, BuildPlatform, Environment, RCFile, CompileAction.PrerequisiteItems);
            }

            return(Result);
        }