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 if (!UnrealBuildTool.RunningRocket()) { 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); }
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.Length < 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}\"", 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()); }
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly) { if (LinkEnvironment.Config.bIsBuildingDotNetAssembly) { return(FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePath)); } bool bIsBuildingLibrary = LinkEnvironment.Config.bIsBuildingLibrary || bBuildImportLibraryOnly; bool bIncludeDependentLibrariesInLibrary = bIsBuildingLibrary && LinkEnvironment.Config.bIncludeDependentLibrariesInLibrary; // Create an action that invokes the linker. Action LinkAction = new Action(ActionType.Link); LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; LinkAction.CommandPath = GetVCToolPath( LinkEnvironment.Config.Target.Platform, LinkEnvironment.Config.Target.Configuration, bIsBuildingLibrary ? "lib" : "link"); // Get link arguments. LinkAction.CommandArguments = bIsBuildingLibrary ? GetLibArguments(LinkEnvironment) : GetLinkArguments(LinkEnvironment); // 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; // 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) { LinkAction.CommandArguments += " /DEF"; // Ensure that the import library references the correct filename for the linked binary. LinkAction.CommandArguments += string.Format(" /NAME:\"{0}\"", LinkEnvironment.Config.OutputFilePath.GetFileName()); } if (!LinkEnvironment.Config.bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary)) { // Add the library paths to the argument list. foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths) { LinkAction.CommandArguments += string.Format(" /LIBPATH:\"{0}\"", LibraryPath); } // Add the excluded default libraries to the argument list. foreach (string ExcludedLibrary in LinkEnvironment.Config.ExcludedLibraries) { LinkAction.CommandArguments += string.Format(" /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 FileReference ImportLibraryFilePath = FileReference.Combine(LinkEnvironment.Config.IntermediateDirectory, LinkEnvironment.Config.OutputFilePath.GetFileNameWithoutExtension() + ".lib"); if (LinkEnvironment.Config.bIsCrossReferenced && !bBuildImportLibraryOnly) { ImportLibraryFilePath += ".suppressed"; } FileItem OutputFile; if (bBuildImportLibraryOnly) { OutputFile = FileItem.GetItemByFileReference(ImportLibraryFilePath); } else { OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePath); OutputFile.bNeedsHotReloadNumbersDLLCleanUp = LinkEnvironment.Config.bIsBuildingDLL; } LinkAction.ProducedItems.Add(OutputFile); LinkAction.StatusDescription = Path.GetFileName(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) { InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath)); LinkAction.PrerequisiteItems.Add(InputFile); } if (!bBuildImportLibraryOnly) { // Add input libraries as prerequisites, too! foreach (FileItem InputLibrary in LinkEnvironment.InputLibraries) { InputFileNames.Add(string.Format("\"{0}\"", InputLibrary.AbsolutePath)); LinkAction.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 ) ) ) { LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary)); } } } // Create a response file for the linker FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile); // Never create response files when we are only generating IntelliSense data if (!ProjectFileGenerator.bGenerateProjectFiles) { ResponseFile.Create(ResponseFileName, InputFileNames); } LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFileName); // Add the output file to the command-line. LinkAction.CommandArguments += string.Format(" /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. FileReference ExportFilePath = ImportLibraryFilePath.ChangeExtension(".exp"); FileItem ExportFile = FileItem.GetItemByFileReference(ExportFilePath); LinkAction.ProducedItems.Add(ExportFile); } if (!bIsBuildingLibrary) { // There is anything to export if (LinkEnvironment.Config.bHasExports // Shipping monolithic builds don't need exports && (!((LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) && (LinkEnvironment.bShouldCompileMonolithic != false)))) { // Write the import library to the output directory for nFringe support. FileItem ImportLibraryFile = FileItem.GetItemByFileReference(ImportLibraryFilePath); LinkAction.CommandArguments += string.Format(" /IMPLIB:\"{0}\"", ImportLibraryFilePath); LinkAction.ProducedItems.Add(ImportLibraryFile); } if (LinkEnvironment.Config.bCreateDebugInfo) { // Write the PDB file to the output directory. { FileReference PDBFilePath = FileReference.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".pdb"); FileItem PDBFile = FileItem.GetItemByFileReference(PDBFilePath); LinkAction.CommandArguments += string.Format(" /PDB:\"{0}\"", PDBFilePath); LinkAction.ProducedItems.Add(PDBFile); } // Write the MAP file to the output directory. #if false if (true) { FileReference MAPFilePath = FileReference.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".map"); FileItem MAPFile = FileItem.GetItemByFileReference(MAPFilePath); LinkAction.CommandArguments += string.Format(" /MAP:\"{0}\"", MAPFilePath); LinkAction.ProducedItems.Add(MAPFile); } #endif } // Add the additional arguments specified by the environment. LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments; } Log.TraceVerbose(" Linking: " + LinkAction.StatusDescription); Log.TraceVerbose(" Command: " + LinkAction.CommandArguments); // Only execute linking on the local PC. LinkAction.bCanExecuteRemotely = false; return(OutputFile); }
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph) { FileItem OutputFile; // Make the final javascript file Action LinkAction = ActionGraph.Add(ActionType.Link); LinkAction.CommandDescription = "Link"; // LinkAction.bPrintDebugInfo = true; // ResponseFile lines. List <string> ReponseLines = new List <string>(); LinkAction.bCanExecuteRemotely = false; LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; LinkAction.CommandPath = HTML5SDKInfo.Python(); LinkAction.CommandArguments = HTML5SDKInfo.EmscriptenCompiler(); // bool bIsBuildingLibrary = LinkEnvironment.bIsBuildingLibrary || bBuildImportLibraryOnly; // ReponseLines.Add( // bIsBuildingLibrary ? // GetLibArguments(LinkEnvironment) : // GetLinkArguments(LinkEnvironment) // ); ReponseLines.Add(GetLinkArguments(LinkEnvironment)); // Add the input files to a response file, and pass the response file on the command-line. foreach (FileItem InputFile in LinkEnvironment.InputFiles) { //System.Console.WriteLine("File {0} ", InputFile.AbsolutePath); ReponseLines.Add(string.Format(" \"{0}\"", InputFile.AbsolutePath)); LinkAction.PrerequisiteItems.Add(InputFile); } if (!LinkEnvironment.bIsBuildingLibrary) { // Make sure ThirdParty libs are at the end. List <string> ThirdParty = (from Lib in LinkEnvironment.AdditionalLibraries where Lib.Contains("ThirdParty") select Lib).ToList(); LinkEnvironment.AdditionalLibraries.RemoveAll(Element => Element.Contains("ThirdParty")); LinkEnvironment.AdditionalLibraries.AddRange(ThirdParty); foreach (string InputFile in LinkEnvironment.AdditionalLibraries) { FileItem Item = FileItem.GetItemByPath(InputFile); if (Item.AbsolutePath.Contains(".lib")) { continue; } if (Item.ToString().EndsWith(".js")) { ReponseLines.Add(string.Format(" --js-library \"{0}\"", Item.AbsolutePath)); } // WARNING: With --pre-js and --post-js, the order in which these directives are passed to // the compiler is very critical, because that dictates the order in which they are appended. // // Set environment variable [ EMCC_DEBUG=1 ] to see the linker order used in packaging. // See GetSharedArguments_Global() above to set this environment variable else if (Item.ToString().EndsWith(".jspre")) { ReponseLines.Add(string.Format(" --pre-js \"{0}\"", Item.AbsolutePath)); } else if (Item.ToString().EndsWith(".jspost")) { ReponseLines.Add(string.Format(" --post-js \"{0}\"", Item.AbsolutePath)); } else { ReponseLines.Add(string.Format(" \"{0}\"", Item.AbsolutePath)); } LinkAction.PrerequisiteItems.Add(Item); } } // make the file we will create OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.OutputFilePath); LinkAction.ProducedItems.Add(OutputFile); ReponseLines.Add(string.Format(" -o \"{0}\"", OutputFile.AbsolutePath)); FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.OutputFilePath.FullName.Replace(".js", ".bc").Replace(".html", ".bc")); LinkAction.ProducedItems.Add(OutputBC); ReponseLines.Add(string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath)); LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath); FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile); LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, ReponseLines)); LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler); return(OutputFile); }
/// <summary> /// Reads dependencies from the given file. /// </summary> /// <param name="InputFile">The file to read from</param> /// <returns>List of included dependencies</returns> static List <FileItem> ReadDependenciesFile(FileReference InputFile) { if (InputFile.HasExtension(".txt")) { string[] Lines = FileReference.ReadAllLines(InputFile); HashSet <FileItem> DependencyItems = new HashSet <FileItem>(); foreach (string Line in Lines) { if (Line.Length > 0) { // Ignore *.tlh and *.tli files generated by the compiler from COM DLLs if (!Line.EndsWith(".tlh", StringComparison.OrdinalIgnoreCase) && !Line.EndsWith(".tli", StringComparison.OrdinalIgnoreCase)) { DependencyItems.Add(FileItem.GetItemByPath(Line)); } } } return(DependencyItems.ToList()); } else if (InputFile.HasExtension(".d")) { string Text = FileReference.ReadAllText(InputFile); List <string> Tokens = new List <string>(); StringBuilder Token = new StringBuilder(); for (int Idx = 0; TryReadMakefileToken(Text, ref Idx, Token);) { Tokens.Add(Token.ToString()); } int TokenIdx = 0; while (TokenIdx < Tokens.Count && Tokens[TokenIdx] == "\n") { TokenIdx++; } if (TokenIdx + 1 >= Tokens.Count || Tokens[TokenIdx + 1] != ":") { throw new BuildException("Unable to parse dependency file"); } TokenIdx += 2; List <FileItem> NewDependencyFiles = new List <FileItem>(); for (; TokenIdx < Tokens.Count && Tokens[TokenIdx] != "\n"; TokenIdx++) { NewDependencyFiles.Add(FileItem.GetItemByPath(Tokens[TokenIdx])); } while (TokenIdx < Tokens.Count && Tokens[TokenIdx] == "\n") { TokenIdx++; } if (TokenIdx != Tokens.Count) { throw new BuildException("Unable to parse dependency file"); } return(NewDependencyFiles); } else { throw new BuildException("Unknown dependency list file type: {0}", InputFile); } }
/// <summary> /// Checks to see if the assembly needs compilation /// </summary> /// <param name="SourceFiles">Set of source files</param> /// <param name="AssemblyManifestFilePath">File containing information about this assembly, like which source files it was built with and engine version</param> /// <param name="OutputAssemblyPath">Output path for the assembly</param> /// <returns>True if the assembly needs to be built</returns> private static bool RequiresCompilation(HashSet <FileReference> SourceFiles, FileReference AssemblyManifestFilePath, FileReference OutputAssemblyPath) { // HACK: We cannot do this without breaking marketplace plugins. Need to distribute separate rules assemblies for those. // // Do not compile the file if it's installed // if (UnrealBuildTool.IsFileInstalled(OutputAssemblyPath)) // { // Log.TraceLog("Skipping {0}: File is installed", OutputAssemblyPath); // return false; // } // Check to see if we already have a compiled assembly file on disk FileItem OutputAssemblyInfo = FileItem.GetItemByFileReference(OutputAssemblyPath); if (!OutputAssemblyInfo.Exists) { Log.TraceLog("Compiling {0}: Assembly does not exist", OutputAssemblyPath); return(true); } // Check the time stamp of the UnrealBuildTool.exe file. If Unreal Build Tool was compiled more // recently than the dynamically-compiled assembly, then we'll always recompile it. This is // because Unreal Build Tool's code may have changed in such a way that invalidate these // previously-compiled assembly files. FileItem ExecutableItem = FileItem.GetItemByFileReference(UnrealBuildTool.GetUBTPath()); if (ExecutableItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc) { Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, ExecutableItem.Name); return(true); } // Make sure we have a manifest of source files used to compile the output assembly. If it doesn't exist // for some reason (not an expected case) then we'll need to recompile. FileItem AssemblySourceListFile = FileItem.GetItemByFileReference(AssemblyManifestFilePath); if (!AssemblySourceListFile.Exists) { Log.TraceLog("Compiling {0}: Missing source file list ({1})", OutputAssemblyPath, AssemblyManifestFilePath); return(true); } JsonObject Manifest = JsonObject.Read(AssemblyManifestFilePath); // check if the engine version is different string EngineVersionManifest = Manifest.GetStringField("EngineVersion"); string EngineVersionCurrent = FormatVersionNumber(ReadOnlyBuildVersion.Current); if (EngineVersionManifest != EngineVersionCurrent) { Log.TraceLog("Compiling {0}: Engine Version changed from {1} to {2}", OutputAssemblyPath, EngineVersionManifest, EngineVersionCurrent); return(true); } // Make sure the source files we're compiling are the same as the source files that were compiled // for the assembly that we want to load HashSet <FileItem> CurrentSourceFileItems = new HashSet <FileItem>(); foreach (string Line in Manifest.GetStringArrayField("SourceFiles")) { CurrentSourceFileItems.Add(FileItem.GetItemByPath(Line)); } // Get the new source files HashSet <FileItem> SourceFileItems = new HashSet <FileItem>(); foreach (FileReference SourceFile in SourceFiles) { SourceFileItems.Add(FileItem.GetItemByFileReference(SourceFile)); } // Check if there are any differences between the sets foreach (FileItem CurrentSourceFileItem in CurrentSourceFileItems) { if (!SourceFileItems.Contains(CurrentSourceFileItem)) { Log.TraceLog("Compiling {0}: Removed source file ({1})", OutputAssemblyPath, CurrentSourceFileItem); return(true); } } foreach (FileItem SourceFileItem in SourceFileItems) { if (!CurrentSourceFileItems.Contains(SourceFileItem)) { Log.TraceLog("Compiling {0}: Added source file ({1})", OutputAssemblyPath, SourceFileItem); return(true); } } // Check if any of the timestamps are newer foreach (FileItem SourceFileItem in SourceFileItems) { if (SourceFileItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc) { Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, SourceFileItem); return(true); } } return(false); }
/// <summary> /// Patch the action graph for hot reloading, mapping files according to the given dictionary. /// </summary> public static void PatchActionGraph(IEnumerable <Action> Actions, Dictionary <FileReference, FileReference> OriginalFileToHotReloadFile) { // Gather all of the response files for link actions. We're going to need to patch 'em up after we figure out new // names for all of the output files and import libraries List <string> ResponseFilePaths = new List <string>(); // Same as Response files but for all of the link.sh files for link actions. // Only used on BuildHostPlatform Linux List <string> LinkScriptFilePaths = new List <string>(); // Keep a map of the original file names and their new file names, so we can fix up response files after Dictionary <string, string> OriginalFileNameAndNewFileNameList_NoExtensions = new Dictionary <string, string>(); // Finally, we'll keep track of any file items that we had to create counterparts for change file names, so we can fix those up too Dictionary <FileItem, FileItem> AffectedOriginalFileItemAndNewFileItemMap = new Dictionary <FileItem, FileItem>(); foreach (Action Action in Actions.Where((Action) => Action.ActionType == ActionType.Link)) { // Assume that the first produced item (with no extension) is our output file name FileReference HotReloadFile; if (!OriginalFileToHotReloadFile.TryGetValue(Action.ProducedItems[0].Location, out HotReloadFile)) { continue; } string OriginalFileNameWithoutExtension = Utils.GetFilenameWithoutAnyExtensions(Action.ProducedItems[0].AbsolutePath); string NewFileNameWithoutExtension = Utils.GetFilenameWithoutAnyExtensions(HotReloadFile.FullName); // Find the response file in the command line. We'll need to make a copy of it with our new file name. string ResponseFileExtension = ".response"; int ResponseExtensionIndex = Action.CommandArguments.IndexOf(ResponseFileExtension, StringComparison.InvariantCultureIgnoreCase); if (ResponseExtensionIndex != -1) { int ResponseFilePathIndex = Action.CommandArguments.LastIndexOf("@\"", ResponseExtensionIndex); if (ResponseFilePathIndex == -1) { throw new BuildException("Couldn't find response file path in action's command arguments when hot reloading"); } string OriginalResponseFilePathWithoutExtension = Action.CommandArguments.Substring(ResponseFilePathIndex + 2, (ResponseExtensionIndex - ResponseFilePathIndex) - 2); string OriginalResponseFilePath = OriginalResponseFilePathWithoutExtension + ResponseFileExtension; string NewResponseFilePath = ReplaceBaseFileName(OriginalResponseFilePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); // Copy the old response file to the new path if (String.Compare(OriginalResponseFilePath, NewResponseFilePath, StringComparison.OrdinalIgnoreCase) != 0) { File.Copy(OriginalResponseFilePath, NewResponseFilePath, overwrite: true); } // Keep track of the new response file name. We'll have to do some edits afterwards. ResponseFilePaths.Add(NewResponseFilePath); } // Find the *.link.sh file in the command line. We'll need to make a copy of it with our new file name. // Only currently used on Linux if (UEBuildPlatform.IsPlatformInGroup(BuildHostPlatform.Current.Platform, UnrealPlatformGroup.Unix)) { string LinkScriptFileExtension = ".link.sh"; int LinkScriptExtensionIndex = Action.CommandArguments.IndexOf(LinkScriptFileExtension, StringComparison.InvariantCultureIgnoreCase); if (LinkScriptExtensionIndex != -1) { // We expect the script invocation to be quoted int LinkScriptFilePathIndex = Action.CommandArguments.LastIndexOf("\"", LinkScriptExtensionIndex); if (LinkScriptFilePathIndex == -1) { throw new BuildException("Couldn't find link script file path in action's command arguments when hot reloading. Is the path quoted?"); } string OriginalLinkScriptFilePathWithoutExtension = Action.CommandArguments.Substring(LinkScriptFilePathIndex + 1, (LinkScriptExtensionIndex - LinkScriptFilePathIndex) - 1); string OriginalLinkScriptFilePath = OriginalLinkScriptFilePathWithoutExtension + LinkScriptFileExtension; string NewLinkScriptFilePath = ReplaceBaseFileName(OriginalLinkScriptFilePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); // Copy the old response file to the new path File.Copy(OriginalLinkScriptFilePath, NewLinkScriptFilePath, overwrite: true); // Keep track of the new response file name. We'll have to do some edits afterwards. LinkScriptFilePaths.Add(NewLinkScriptFilePath); } // Update this action's list of prerequisite items too for (int ItemIndex = 0; ItemIndex < Action.PrerequisiteItems.Count; ++ItemIndex) { FileItem OriginalPrerequisiteItem = Action.PrerequisiteItems[ItemIndex]; string NewPrerequisiteItemFilePath = ReplaceBaseFileName(OriginalPrerequisiteItem.AbsolutePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); if (OriginalPrerequisiteItem.AbsolutePath != NewPrerequisiteItemFilePath) { // OK, the prerequisite item's file name changed so we'll update it to point to our new file FileItem NewPrerequisiteItem = FileItem.GetItemByPath(NewPrerequisiteItemFilePath); Action.PrerequisiteItems[ItemIndex] = NewPrerequisiteItem; // Keep track of it so we can fix up dependencies in a second pass afterwards AffectedOriginalFileItemAndNewFileItemMap.Add(OriginalPrerequisiteItem, NewPrerequisiteItem); ResponseExtensionIndex = OriginalPrerequisiteItem.AbsolutePath.IndexOf(ResponseFileExtension, StringComparison.InvariantCultureIgnoreCase); if (ResponseExtensionIndex != -1) { string OriginalResponseFilePathWithoutExtension = OriginalPrerequisiteItem.AbsolutePath.Substring(0, ResponseExtensionIndex); string OriginalResponseFilePath = OriginalResponseFilePathWithoutExtension + ResponseFileExtension; string NewResponseFilePath = ReplaceBaseFileName(OriginalResponseFilePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); // Copy the old response file to the new path File.Copy(OriginalResponseFilePath, NewResponseFilePath, overwrite: true); // Keep track of the new response file name. We'll have to do some edits afterwards. ResponseFilePaths.Add(NewResponseFilePath); } } } } // Update this action's list of produced items too for (int ItemIndex = 0; ItemIndex < Action.ProducedItems.Count; ++ItemIndex) { FileItem OriginalProducedItem = Action.ProducedItems[ItemIndex]; string NewProducedItemFilePath = ReplaceBaseFileName(OriginalProducedItem.AbsolutePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); if (OriginalProducedItem.AbsolutePath != NewProducedItemFilePath) { // OK, the produced item's file name changed so we'll update it to point to our new file FileItem NewProducedItem = FileItem.GetItemByPath(NewProducedItemFilePath); Action.ProducedItems[ItemIndex] = NewProducedItem; // Keep track of it so we can fix up dependencies in a second pass afterwards AffectedOriginalFileItemAndNewFileItemMap.Add(OriginalProducedItem, NewProducedItem); } } // Fix up the list of items to delete too for (int Idx = 0; Idx < Action.DeleteItems.Count; Idx++) { FileItem NewItem; if (AffectedOriginalFileItemAndNewFileItemMap.TryGetValue(Action.DeleteItems[Idx], out NewItem)) { Action.DeleteItems[Idx] = NewItem; } } // The status description of the item has the file name, so we'll update it too Action.StatusDescription = ReplaceBaseFileName(Action.StatusDescription, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); // Keep track of the file names, so we can fix up response files afterwards. if (!OriginalFileNameAndNewFileNameList_NoExtensions.ContainsKey(OriginalFileNameWithoutExtension)) { OriginalFileNameAndNewFileNameList_NoExtensions[OriginalFileNameWithoutExtension] = NewFileNameWithoutExtension; } else if (OriginalFileNameAndNewFileNameList_NoExtensions[OriginalFileNameWithoutExtension] != NewFileNameWithoutExtension) { throw new BuildException("Unexpected conflict in renaming files; {0} maps to {1} and {2}", OriginalFileNameWithoutExtension, OriginalFileNameAndNewFileNameList_NoExtensions[OriginalFileNameWithoutExtension], NewFileNameWithoutExtension); } } // Do another pass and update any actions that depended on the original file names that we changed foreach (Action Action in Actions) { for (int ItemIndex = 0; ItemIndex < Action.PrerequisiteItems.Count; ++ItemIndex) { FileItem OriginalFileItem = Action.PrerequisiteItems[ItemIndex]; FileItem NewFileItem; if (AffectedOriginalFileItemAndNewFileItemMap.TryGetValue(OriginalFileItem, out NewFileItem)) { // OK, looks like we need to replace this file item because we've renamed the file Action.PrerequisiteItems[ItemIndex] = NewFileItem; } } } if (OriginalFileNameAndNewFileNameList_NoExtensions.Count > 0) { // Update all the paths in link actions foreach (Action Action in Actions.Where((Action) => Action.ActionType == ActionType.Link)) { foreach (KeyValuePair <string, string> FileNameTuple in OriginalFileNameAndNewFileNameList_NoExtensions) { string OriginalFileNameWithoutExtension = FileNameTuple.Key; string NewFileNameWithoutExtension = FileNameTuple.Value; Action.CommandArguments = ReplaceBaseFileName(Action.CommandArguments, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); } } foreach (string ResponseFilePath in ResponseFilePaths) { // Load the file up string FileContents = Utils.ReadAllText(ResponseFilePath); // Replace all of the old file names with new ones foreach (KeyValuePair <string, string> FileNameTuple in OriginalFileNameAndNewFileNameList_NoExtensions) { string OriginalFileNameWithoutExtension = FileNameTuple.Key; string NewFileNameWithoutExtension = FileNameTuple.Value; FileContents = ReplaceBaseFileName(FileContents, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); } // Overwrite the original file File.WriteAllText(ResponseFilePath, FileContents, new System.Text.UTF8Encoding(false)); } if (UEBuildPlatform.IsPlatformInGroup(BuildHostPlatform.Current.Platform, UnrealPlatformGroup.Unix)) { foreach (string LinkScriptFilePath in LinkScriptFilePaths) { // Load the file up string FileContents = Utils.ReadAllText(LinkScriptFilePath); // Replace all of the old file names with new ones foreach (KeyValuePair <string, string> FileNameTuple in OriginalFileNameAndNewFileNameList_NoExtensions) { string OriginalFileNameWithoutExtension = FileNameTuple.Key; string NewFileNameWithoutExtension = FileNameTuple.Value; FileContents = ReplaceBaseFileName(FileContents, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension); } // Overwrite the original file File.WriteAllText(LinkScriptFilePath, FileContents, new System.Text.UTF8Encoding(false)); } } } // Update the action that writes out the module manifests foreach (Action Action in Actions) { if (Action.ActionType == ActionType.WriteMetadata) { string Arguments = Action.CommandArguments; // Find the argument for the metadata file const string InputArgument = "-Input="; int InputIdx = Arguments.IndexOf(InputArgument); if (InputIdx == -1) { throw new Exception("Missing -Input= argument to WriteMetadata command when patching action graph."); } int FileNameIdx = InputIdx + InputArgument.Length; if (Arguments[FileNameIdx] == '\"') { FileNameIdx++; } int FileNameEndIdx = FileNameIdx; while (FileNameEndIdx < Arguments.Length && (Arguments[FileNameEndIdx] != ' ' || Arguments[FileNameIdx - 1] == '\"') && Arguments[FileNameEndIdx] != '\"') { FileNameEndIdx++; } // Read the metadata file FileReference TargetInfoFile = new FileReference(Arguments.Substring(FileNameIdx, FileNameEndIdx - FileNameIdx)); if (!FileReference.Exists(TargetInfoFile)) { throw new Exception(String.Format("Unable to find metadata file to patch action graph ({0})", TargetInfoFile)); } // Update the module names WriteMetadataTargetInfo TargetInfo = BinaryFormatterUtils.Load <WriteMetadataTargetInfo>(TargetInfoFile); foreach (KeyValuePair <FileReference, ModuleManifest> FileNameToVersionManifest in TargetInfo.FileToManifest) { KeyValuePair <string, string>[] ManifestEntries = FileNameToVersionManifest.Value.ModuleNameToFileName.ToArray(); foreach (KeyValuePair <string, string> Manifest in ManifestEntries) { FileReference OriginalFile = FileReference.Combine(FileNameToVersionManifest.Key.Directory, Manifest.Value); FileReference HotReloadFile; if (OriginalFileToHotReloadFile.TryGetValue(OriginalFile, out HotReloadFile)) { FileNameToVersionManifest.Value.ModuleNameToFileName[Manifest.Key] = HotReloadFile.GetFileName(); } } } // Write the hot-reload metadata file and update the argument list FileReference HotReloadTargetInfoFile = FileReference.Combine(TargetInfoFile.Directory, "Metadata-HotReload.dat"); BinaryFormatterUtils.SaveIfDifferent(HotReloadTargetInfoFile, TargetInfo); Action.PrerequisiteItems.RemoveAll(x => x.Location == TargetInfoFile); Action.PrerequisiteItems.Add(FileItem.GetItemByFileReference(HotReloadTargetInfoFile)); Action.CommandArguments = Arguments.Substring(0, FileNameIdx) + HotReloadTargetInfoFile + Arguments.Substring(FileNameEndIdx); } } }
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly) { Debug.Assert(!bBuildImportLibraryOnly); List <string> RPaths = new List <string>(); if (LinkEnvironment.Config.bIsBuildingLibrary || bBuildImportLibraryOnly) { return(CreateArchiveAndIndex(LinkEnvironment)); } // Create an action that invokes the linker. Action LinkAction = new Action(ActionType.Link); LinkAction.WorkingDirectory = Path.GetFullPath("."); if (String.IsNullOrEmpty(ClangPath)) { LinkAction.CommandPath = GCCPath; } else { LinkAction.CommandPath = ClangPath; } // Get link arguments. LinkAction.CommandArguments = GetLinkArguments(LinkEnvironment); // 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 = LinkEnvironment.Config.bIsBuildingDLL; // Add the output file as a production of the link action. FileItem OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath); LinkAction.ProducedItems.Add(OutputFile); LinkAction.CommandDescription = "Link"; LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath); // Add the output file to the command-line. 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) { InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath.Replace("\\", "/"))); LinkAction.PrerequisiteItems.Add(InputFile); } string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile); LinkAction.CommandArguments += string.Format(" -Wl,@\"{0}\"", ResponseFile.Create(ResponseFileName, InputFileNames)); if (LinkEnvironment.Config.bIsBuildingDLL) { LinkAction.CommandArguments += string.Format(" -Wl,-soname={0}", OutputFile); } // Start with the configured LibraryPaths and also add paths to any libraries that // we depend on (libraries that we've build ourselves). List <string> AllLibraryPaths = LinkEnvironment.Config.LibraryPaths; foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries) { string PathToLib = Path.GetDirectoryName(AdditionalLibrary); if (!String.IsNullOrEmpty(PathToLib)) { // make path absolute, because FixDependencies script may be executed in a different directory string AbsolutePathToLib = Path.GetFullPath(PathToLib); if (!AllLibraryPaths.Contains(AbsolutePathToLib)) { AllLibraryPaths.Add(AbsolutePathToLib); } } if ((AdditionalLibrary.Contains("Plugins") || AdditionalLibrary.Contains("Binaries/ThirdParty") || AdditionalLibrary.Contains("Binaries\\ThirdParty")) && Path.GetDirectoryName(AdditionalLibrary) != Path.GetDirectoryName(OutputFile.AbsolutePath)) { string RelativePath = Utils.MakePathRelativeTo(Path.GetDirectoryName(AdditionalLibrary), Path.GetDirectoryName(OutputFile.AbsolutePath)); if (!RPaths.Contains(RelativePath)) { RPaths.Add(RelativePath); LinkAction.CommandArguments += string.Format(" -Wl,-rpath=\"${{ORIGIN}}/{0}\"", RelativePath); } } } LinkAction.CommandArguments += string.Format(" -Wl,-rpath-link=\"{0}\"", Path.GetDirectoryName(OutputFile.AbsolutePath)); // Add the library paths to the argument list. foreach (string LibraryPath in AllLibraryPaths) { // use absolute paths because of FixDependencies script again LinkAction.CommandArguments += string.Format(" -L\"{0}\"", Path.GetFullPath(LibraryPath)); } // add libraries in a library group LinkAction.CommandArguments += string.Format(" -Wl,--start-group"); List <string> EngineAndGameLibraries = new List <string>(); foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries) { if (String.IsNullOrEmpty(Path.GetDirectoryName(AdditionalLibrary))) { // library was passed just like "jemalloc", turn it into -ljemalloc LinkAction.CommandArguments += string.Format(" -l{0}", AdditionalLibrary); } else if (Path.GetExtension(AdditionalLibrary) == ".a") { // static library passed in, pass it along but make path absolute, because FixDependencies script may be executed in a different directory string AbsoluteAdditionalLibrary = Path.GetFullPath(AdditionalLibrary); if (AbsoluteAdditionalLibrary.Contains(" ")) { AbsoluteAdditionalLibrary = string.Format("\"{0}\"", AbsoluteAdditionalLibrary); } LinkAction.CommandArguments += (" " + AbsoluteAdditionalLibrary); LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary)); } else { // Skip over full-pathed library dependencies when building DLLs to avoid circular // dependencies. FileItem LibraryDependency = FileItem.GetItemByPath(AdditionalLibrary); var LibName = Path.GetFileNameWithoutExtension(AdditionalLibrary); if (LibName.StartsWith("lib")) { // Remove lib prefix LibName = LibName.Remove(0, 3); } string LibLinkFlag = string.Format(" -l{0}", LibName); if (LinkEnvironment.Config.bIsBuildingDLL && LinkEnvironment.Config.bIsCrossReferenced) { // We are building a cross referenced DLL so we can't actually include // dependencies at this point. Instead we add it to the list of // libraries to be used in the FixDependencies step. EngineAndGameLibraries.Add(LibLinkFlag); if (!LinkAction.CommandArguments.Contains("--allow-shlib-undefined")) { LinkAction.CommandArguments += string.Format(" -Wl,--allow-shlib-undefined"); } } else { LinkAction.PrerequisiteItems.Add(LibraryDependency); LinkAction.CommandArguments += LibLinkFlag; } } } LinkAction.CommandArguments += " -lrt"; // needed for clock_gettime() LinkAction.CommandArguments += " -lm"; // math 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("\\\\", "/"); LinkAction.CommandArguments = LinkAction.CommandArguments.Replace("\\", "/"); // prepare a linker script string LinkerScriptPath = Path.Combine(LinkEnvironment.Config.LocalShadowDirectory, "remove-sym.ldscript"); if (!Directory.Exists(LinkEnvironment.Config.LocalShadowDirectory)) { Directory.CreateDirectory(LinkEnvironment.Config.LocalShadowDirectory); } if (File.Exists(LinkerScriptPath)) { File.Delete(LinkerScriptPath); } using (StreamWriter Writer = File.CreateText(LinkerScriptPath)) { Writer.WriteLine("UE4 {"); Writer.WriteLine(" global: *;"); Writer.WriteLine(" local: _Znwm;"); Writer.WriteLine(" _Znam;"); Writer.WriteLine(" _ZdaPv;"); Writer.WriteLine(" _ZdlPv;"); Writer.WriteLine("};"); }; LinkAction.CommandArguments += string.Format(" -Wl,--version-script=\"{0}\"", LinkerScriptPath); // Only execute linking on the local PC. LinkAction.bCanExecuteRemotely = false; // Prepare a script that will run later, once all shared libraries and the executable // are created. This script will be called by action created in FixDependencies() if (LinkEnvironment.Config.bIsCrossReferenced && LinkEnvironment.Config.bIsBuildingDLL) { bool bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32; string ScriptName = bUseCmdExe ? "FixDependencies.bat" : "FixDependencies.sh"; string FixDepsScriptPath = Path.Combine(LinkEnvironment.Config.LocalShadowDirectory, ScriptName); if (!bHasWipedFixDepsScript) { bHasWipedFixDepsScript = true; Log.TraceVerbose("Creating script: {0}", FixDepsScriptPath); StreamWriter Writer = File.CreateText(FixDepsScriptPath); if (bUseCmdExe) { Writer.Write("@echo off\n"); Writer.Write("rem Automatically generated by UnrealBuildTool\n"); Writer.Write("rem *DO NOT EDIT*\n\n"); } else { Writer.Write("#!/bin/sh\n"); Writer.Write("# Automatically generated by UnrealBuildTool\n"); Writer.Write("# *DO NOT EDIT*\n\n"); Writer.Write("set -o errexit\n"); } Writer.Close(); } StreamWriter FixDepsScript = File.AppendText(FixDepsScriptPath); string EngineAndGameLibrariesString = ""; foreach (string Library in EngineAndGameLibraries) { EngineAndGameLibrariesString += Library; } FixDepsScript.Write(string.Format("echo Fixing {0}\n", Path.GetFileName(OutputFile.AbsolutePath))); if (!bUseCmdExe) { FixDepsScript.Write(string.Format("TIMESTAMP=`stat --format %y \"{0}\"`\n", OutputFile.AbsolutePath)); } string FixDepsLine = LinkAction.CommandPath + " " + LinkAction.CommandArguments; string Replace = "-Wl,--allow-shlib-undefined"; FixDepsLine = FixDepsLine.Replace(Replace, EngineAndGameLibrariesString); string OutputFileForwardSlashes = OutputFile.AbsolutePath.Replace("\\", "/"); FixDepsLine = FixDepsLine.Replace(OutputFileForwardSlashes, OutputFileForwardSlashes + ".fixed"); FixDepsLine = FixDepsLine.Replace("$", "\\$"); FixDepsScript.Write(FixDepsLine + "\n"); if (bUseCmdExe) { FixDepsScript.Write(string.Format("move /Y \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath)); } else { FixDepsScript.Write(string.Format("mv \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath)); FixDepsScript.Write(string.Format("touch -d \"$TIMESTAMP\" \"{0}\"\n\n", OutputFile.AbsolutePath)); } FixDepsScript.Close(); } //LinkAction.CommandArguments += " -v"; return(OutputFile); }
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); }
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly) { if (LinkEnvironment.Config.Target.Architecture == "-win32") // simulator { return(base.LinkFiles(LinkEnvironment, bBuildImportLibraryOnly)); } FileItem OutputFile; // Make the final javascript file Action LinkAction = new Action(ActionType.Link); // ResponseFile lines. List <string> ReponseLines = new List <string>(); LinkAction.bCanExecuteRemotely = false; LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; LinkAction.CommandPath = HTML5SDKInfo.Python(); LinkAction.CommandArguments = HTML5SDKInfo.EmscriptenCompiler(); ReponseLines.Add(GetLinkArguments(LinkEnvironment)); // Add the input files to a response file, and pass the response file on the command-line. foreach (FileItem InputFile in LinkEnvironment.InputFiles) { //System.Console.WriteLine("File {0} ", InputFile.AbsolutePath); ReponseLines.Add(string.Format(" \"{0}\"", InputFile.AbsolutePath)); LinkAction.PrerequisiteItems.Add(InputFile); } if (!LinkEnvironment.Config.bIsBuildingLibrary) { // Make sure ThirdParty libs are at the end. List <string> ThirdParty = (from Lib in LinkEnvironment.Config.AdditionalLibraries where Lib.Contains("ThirdParty") select Lib).ToList(); LinkEnvironment.Config.AdditionalLibraries.RemoveAll(Element => Element.Contains("ThirdParty")); LinkEnvironment.Config.AdditionalLibraries.AddRange(ThirdParty); foreach (string InputFile in LinkEnvironment.Config.AdditionalLibraries) { FileItem Item = FileItem.GetItemByPath(InputFile); if (Item.AbsolutePath.Contains(".lib")) { continue; } if (Item != null) { if (Item.ToString().Contains(".js")) { ReponseLines.Add(string.Format(" --js-library \"{0}\"", Item.AbsolutePath)); } else { ReponseLines.Add(string.Format(" \"{0}\"", Item.AbsolutePath)); } LinkAction.PrerequisiteItems.Add(Item); } } } // make the file we will create OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePath); LinkAction.ProducedItems.Add(OutputFile); ReponseLines.Add(string.Format(" -o \"{0}\"", OutputFile.AbsolutePath)); FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath.FullName.Replace(".js", ".bc").Replace(".html", ".bc")); LinkAction.ProducedItems.Add(OutputBC); ReponseLines.Add(" --emit-symbol-map " + string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath)); LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath); FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile); LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, ReponseLines)); LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler); return(OutputFile); }
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); }
/// <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; }
/// <summary> /// Writes an action to a json file /// </summary> /// <param name="Object">The object to parse</param> public static Action ImportJson(JsonObject Object) { Action Action = new Action(Object.GetEnumField <ActionType>("Type")); string WorkingDirectory; if (Object.TryGetStringField("WorkingDirectory", out WorkingDirectory)) { Action.WorkingDirectory = new DirectoryReference(WorkingDirectory); } string CommandPath; if (Object.TryGetStringField("CommandPath", out CommandPath)) { Action.CommandPath = new FileReference(CommandPath); } string CommandArguments; if (Object.TryGetStringField("CommandArguments", out CommandArguments)) { Action.CommandArguments = CommandArguments; } string CommandDescription; if (Object.TryGetStringField("CommandDescription", out CommandDescription)) { Action.CommandDescription = CommandDescription; } string StatusDescription; if (Object.TryGetStringField("StatusDescription", out StatusDescription)) { Action.StatusDescription = StatusDescription; } bool bPrintDebugInfo; if (Object.TryGetBoolField("bPrintDebugInfo", out bPrintDebugInfo)) { Action.bPrintDebugInfo = bPrintDebugInfo; } bool bCanExecuteRemotely; if (Object.TryGetBoolField("bCanExecuteRemotely", out bCanExecuteRemotely)) { Action.bCanExecuteRemotely = bCanExecuteRemotely; } bool bCanExecuteRemotelyWithSNDBS; if (Object.TryGetBoolField("bCanExecuteRemotelyWithSNDBS", out bCanExecuteRemotelyWithSNDBS)) { Action.bCanExecuteRemotelyWithSNDBS = bCanExecuteRemotelyWithSNDBS; } bool bIsGCCCompiler; if (Object.TryGetBoolField("bIsGCCCompiler", out bIsGCCCompiler)) { Action.bIsGCCCompiler = bIsGCCCompiler; } bool bShouldOutputStatusDescription; if (Object.TryGetBoolField("bShouldOutputStatusDescription", out bShouldOutputStatusDescription)) { Action.bShouldOutputStatusDescription = bShouldOutputStatusDescription; } bool bProducesImportLibrary; if (Object.TryGetBoolField("bProducesImportLibrary", out bProducesImportLibrary)) { Action.bProducesImportLibrary = bProducesImportLibrary; } string[] PrerequisiteItems; if (Object.TryGetStringArrayField("PrerequisiteItems", out PrerequisiteItems)) { Action.PrerequisiteItems.AddRange(PrerequisiteItems.Select(x => FileItem.GetItemByPath(x))); } string[] ProducedItems; if (Object.TryGetStringArrayField("ProducedItems", out ProducedItems)) { Action.ProducedItems.AddRange(ProducedItems.Select(x => FileItem.GetItemByPath(x))); } string[] DeleteItems; if (Object.TryGetStringArrayField("DeleteItems", out DeleteItems)) { Action.DeleteItems.AddRange(DeleteItems.Select(x => FileItem.GetItemByPath(x))); } string DependencyListFile; if (Object.TryGetStringField("DependencyListFile", out DependencyListFile)) { Action.DependencyListFile = FileItem.GetItemByPath(DependencyListFile); } return(Action); }
/// <summary> /// Checks to see if the assembly needs compilation /// </summary> /// <param name="SourceFiles">Set of source files</param> /// <param name="AssemblySourceListFilePath">File to use to cache source file names</param> /// <param name="OutputAssemblyPath">Output path for the assembly</param> /// <returns>True if the assembly needs to be built</returns> private static bool RequiresCompilation(HashSet <FileReference> SourceFiles, FileReference AssemblySourceListFilePath, FileReference OutputAssemblyPath) { // Check to see if we already have a compiled assembly file on disk FileItem OutputAssemblyInfo = FileItem.GetItemByFileReference(OutputAssemblyPath); if (!OutputAssemblyInfo.Exists) { Log.TraceLog("Compiling {0}: Assembly does not exist", OutputAssemblyPath); return(true); } // Check the time stamp of the UnrealBuildTool.exe file. If Unreal Build Tool was compiled more // recently than the dynamically-compiled assembly, then we'll always recompile it. This is // because Unreal Build Tool's code may have changed in such a way that invalidate these // previously-compiled assembly files. FileItem ExecutableItem = FileItem.GetItemByFileReference(UnrealBuildTool.GetUBTPath()); if (ExecutableItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc) { Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, ExecutableItem.Name); return(true); } // Make sure we have a manifest of source files used to compile the output assembly. If it doesn't exist // for some reason (not an expected case) then we'll need to recompile. FileItem AssemblySourceListFile = FileItem.GetItemByFileReference(AssemblySourceListFilePath); if (!AssemblySourceListFile.Exists) { Log.TraceLog("Compiling {0}: Missing source file list ({1})", OutputAssemblyPath, AssemblySourceListFilePath); return(true); } // Make sure the source files we're compiling are the same as the source files that were compiled // for the assembly that we want to load HashSet <FileItem> CurrentSourceFileItems = new HashSet <FileItem>(); foreach (string Line in FileReference.ReadAllLines(AssemblySourceListFile.Location)) { CurrentSourceFileItems.Add(FileItem.GetItemByPath(Line)); } // Get the new source files HashSet <FileItem> SourceFileItems = new HashSet <FileItem>(); foreach (FileReference SourceFile in SourceFiles) { SourceFileItems.Add(FileItem.GetItemByFileReference(SourceFile)); } // Check if there are any differences between the sets foreach (FileItem CurrentSourceFileItem in CurrentSourceFileItems) { if (!SourceFileItems.Contains(CurrentSourceFileItem)) { Log.TraceLog("Compiling {0}: Removed source file ({1})", OutputAssemblyPath, AssemblySourceListFilePath); return(true); } } foreach (FileItem SourceFileItem in SourceFileItems) { if (!CurrentSourceFileItems.Contains(SourceFileItem)) { Log.TraceLog("Compiling {0}: Added source file ({1})", OutputAssemblyPath, AssemblySourceListFilePath); return(true); } } // Check if any of the timestamps are newer foreach (FileItem SourceFileItem in SourceFileItems) { if (SourceFileItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc) { Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, SourceFileItem); return(true); } } return(false); }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName) { if (CompileEnvironment.Config.Target.Architecture == "-win32") { return(base.CompileCPPFiles(Target, CompileEnvironment, SourceFiles, ModuleName)); } string Arguments = GetCLArguments_Global(CompileEnvironment); CPPOutput Result = new CPPOutput(); // Add include paths to the argument list. foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { Arguments += string.Format(" -D{0}", Definition); } var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); foreach (FileItem SourceFile in SourceFiles) { Action CompileAction = new Action(ActionType.Compile); 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); // Add the source file path to the command-line. string FileArguments = string.Format(" \"{0}\"", SourceFile.AbsolutePath); var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.HTML5].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); FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath); // Add C or C++ specific compiler arguments. if (bIsPlainCFile) { FileArguments += GetCLArguments_C(CompileEnvironment.Config.Target.Architecture); } else { FileArguments += GetCLArguments_CPP(CompileEnvironment); } CompileAction.WorkingDirectory = Path.GetFullPath("."); CompileAction.CommandPath = PythonPath; CompileAction.CommandArguments = EMCCPath + " " + Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments; System.Console.WriteLine(CompileAction.CommandArguments); CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath); CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler); // Don't farm out creation of precomputed headers as it is the critical path task. CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create; // this is the final output of the compile step (a .abc file) Result.ObjectFiles.Add(ObjectFile); // 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 precompiled headers as it is the critical path task. CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create || BuildConfiguration.bAllowRemotelyCompiledPCHs; } return(Result); }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName) { string Arguments = GetCLArguments_Global(CompileEnvironment); string PCHArguments = ""; if (CompileEnvironment.Config.bIsBuildingDLL) { Arguments += " -fPIC"; } 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. var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Linux].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader); PCHArguments += string.Format(" -include \"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(PrecompiledFileExtension, "")); } // Add include paths to the argument list. foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { Arguments += string.Format(" -D \"{0}\"", Definition); } 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); string FileArguments = ""; string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant(); // Add C or C++ specific compiler arguments. if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { FileArguments += GetCompileArguments_PCH(); } else if (Extension == ".C") { // Compile the file as C code. FileArguments += GetCompileArguments_C(); } else if (Extension == ".CC") { // Compile the file as C++ code. FileArguments += GetCompileArguments_CPP(); } else if (Extension == ".MM") { // Compile the file as Objective-C++ code. FileArguments += GetCompileArguments_MM(); } else if (Extension == ".M") { // Compile the file as Objective-C code. FileArguments += GetCompileArguments_M(); } else { FileArguments += GetCompileArguments_CPP(); // 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) { var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Linux].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader); // Add the precompiled header file to the produced item 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 += string.Format(" -o \"{0}\"", PrecompiledHeaderFile.AbsolutePath, false); } else { if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { CompileAction.bIsUsingPCH = true; CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile); } var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Linux].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 += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false); } // Add the source file path to the command-line. FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath); CompileAction.WorkingDirectory = Path.GetFullPath("."); if (!UsingClang()) { CompileAction.CommandPath = GCCPath; } else { CompileAction.CommandPath = ClangPath; } CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments; CompileAction.CommandDescription = "Compile"; CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath); CompileAction.bIsGCCCompiler = 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; CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler); } return(Result); }
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly) { if (LinkEnvironment.Config.Target.Architecture == "-win32") { return(base.LinkFiles(LinkEnvironment, bBuildImportLibraryOnly)); } FileItem OutputFile; // Make the final javascript file Action LinkAction = new Action(ActionType.Link); LinkAction.bCanExecuteRemotely = false; LinkAction.WorkingDirectory = Path.GetFullPath("."); LinkAction.CommandPath = PythonPath; LinkAction.CommandArguments = EMCCPath; LinkAction.CommandArguments += GetLinkArguments(LinkEnvironment); // Add the input files to a response file, and pass the response file on the command-line. foreach (FileItem InputFile in LinkEnvironment.InputFiles) { System.Console.WriteLine("File {0} ", InputFile.AbsolutePath); LinkAction.CommandArguments += string.Format(" \"{0}\"", InputFile.AbsolutePath); LinkAction.PrerequisiteItems.Add(InputFile); } foreach (string InputFile in LinkEnvironment.Config.AdditionalLibraries) { FileItem Item = FileItem.GetItemByPath(InputFile); if (Item.AbsolutePath.Contains(".lib")) { continue; } if (Item != null) { if (Item.ToString().Contains(".js")) { LinkAction.CommandArguments += string.Format(" --js-library \"{0}\"", Item.AbsolutePath); } else { LinkAction.CommandArguments += string.Format(" \"{0}\"", Item.AbsolutePath); } LinkAction.PrerequisiteItems.Add(Item); } } // make the file we will create OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath); LinkAction.ProducedItems.Add(OutputFile); LinkAction.CommandArguments += string.Format(" -o \"{0}\"", OutputFile.AbsolutePath); FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath.Replace(".js", ".bc").Replace(".html", ".bc")); LinkAction.ProducedItems.Add(OutputBC); LinkAction.CommandArguments += string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath); LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath); LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler); return(OutputFile); }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName) { string Arguments = GetCLArguments_Global(CompileEnvironment); // Add include paths to the argument list. foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths) { Arguments += string.Format(" /I \"{0}\"", IncludePath); } foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths) { Arguments += string.Format(" /I \"{0}\"", IncludePath); } if ((CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled) || (WinRTPlatform.ShouldCompileWinRT() == true)) { // 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 += string.Format(" /AI \"{0}\"", AssemblyPath); } // Add explicit .NET framework assembly references foreach (string AssemblyName in CompileEnvironment.Config.FrameworkAssemblyDependencies) { Arguments += string.Format(" /FU \"{0}\"", AssemblyName); } // Add private assembly references foreach (PrivateAssemblyInfo CurAssemblyInfo in CompileEnvironment.PrivateAssemblyDependencies) { Arguments += string.Format(" /FU \"{0}\"", CurAssemblyInfo.FileItem.AbsolutePath); } } else { foreach (string AssemblyPath in CompileEnvironment.Config.SystemDotNetAssemblyPaths) { Arguments += string.Format(" /AI \"{0}\"", AssemblyPath); } // Add explicit .NET framework assembly references foreach (string AssemblyName in CompileEnvironment.Config.FrameworkAssemblyDependencies) { Arguments += string.Format(" /FU \"{0}\"", AssemblyName); } } // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { Arguments += string.Format(" /D \"{0}\"", Definition); } // Log.TraceInformation("Compile Arguments for {0}:", ModuleName); // Log.TraceInformation(Arguments); 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); string FileArguments = ""; 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); } } if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { // Generate a CPP File that just includes the precompiled header. string PCHCPPFilename = "PCH." + 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 += string.Format(" /I \"{0}\"", OriginalPCHHeaderDirectory); var PCHExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.WinRT].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) + 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(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename); FileArguments += string.Format(" /Fp\"{0}\"", PrecompiledHeaderFile.AbsolutePath); FileArguments += string.Format(" \"{0}\"", PCHCPPFile.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 += string.Format(" /Yl{0}", FakeUniquePCHSymbolName); } CompileAction.StatusDescription = PCHCPPFilename; } else { if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { CompileAction.bIsUsingPCH = true; CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile); FileArguments += string.Format(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode); FileArguments += string.Format(" /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 += string.Format(" /FI\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode); } } // Add the source file path to the command-line. FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath); CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath); } var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.WinRT].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 += string.Format(" /Fo\"{0}\"", ObjectFile.AbsolutePath); // create PDBs per-file when not using debug info, 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 (!CompileEnvironment.Config.bCreateDebugInfo || BuildConfiguration.bUsePDBFiles) { string PDBFileName; bool bActionProducesPDB = false; // All files using the same PCH are required to share a PDB. if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { PDBFileName = Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename); } // Files creating a PCH or ungrouped C++ files use a PDB per file. else if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create || !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 += string.Format(" /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) { FileArguments += GetCLArguments_C(); } else { FileArguments += GetCLArguments_CPP(CompileEnvironment); } CompileAction.WorkingDirectory = Path.GetFullPath("."); CompileAction.CommandPath = GetVCToolPath(CompileEnvironment.Config.Target.Platform, CompileEnvironment.Config.Target.Configuration, "cl"); CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments; CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath)); // Don't farm out creation of precomputed headers as it is the critical path task. CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create; // @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); }
/** Creates an action to archive all the .o files into single .a file */ public FileItem CreateArchiveAndIndex(LinkEnvironment LinkEnvironment) { // Create an archive action Action ArchiveAction = new Action(ActionType.Link); ArchiveAction.WorkingDirectory = Path.GetFullPath("."); bool bUsingSh = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win64 && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win32; if (bUsingSh) { ArchiveAction.CommandPath = "/bin/sh"; ArchiveAction.CommandArguments = "-c '"; } else { ArchiveAction.CommandPath = "cmd.exe"; ArchiveAction.CommandArguments = "/c \""; } // this will produce a final library ArchiveAction.bProducesImportLibrary = true; // Add the output file as a production of the link action. FileItem OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath); ArchiveAction.ProducedItems.Add(OutputFile); ArchiveAction.CommandDescription = "Archive"; ArchiveAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath); ArchiveAction.CommandArguments += string.Format("\"{0}\" {1} \"{2}\"", GetArPath(LinkEnvironment.Config.Target.Architecture), GetArchiveArguments(LinkEnvironment), 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) { string InputAbsolutePath = InputFile.AbsolutePath.Replace("\\", "/"); InputFileNames.Add(string.Format("\"{0}\"", InputAbsolutePath)); ArchiveAction.PrerequisiteItems.Add(InputFile); ArchiveAction.CommandArguments += string.Format(" \"{0}\"", InputAbsolutePath); } // add ranlib ArchiveAction.CommandArguments += string.Format(" && \"{0}\" \"{1}\"", GetRanlibPath(LinkEnvironment.Config.Target.Architecture), OutputFile.AbsolutePath); // Add the additional arguments specified by the environment. ArchiveAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments; ArchiveAction.CommandArguments.Replace("\\", "/"); if (bUsingSh) { ArchiveAction.CommandArguments += "'"; } else { ArchiveAction.CommandArguments += "\""; } // Only execute linking on the local PC. ArchiveAction.bCanExecuteRemotely = false; return(OutputFile); }