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) { if (LinkEnvironment.Config.Target.Architecture == "-win32") { 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 = Path.GetFullPath("."); 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.GetItemByPath(LinkEnvironment.Config.OutputFilePath); LinkAction.ProducedItems.Add(OutputFile); ReponseLines.Add(string.Format(" -o \"{0}\"", OutputFile.AbsolutePath)); FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath.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); string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile); LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, ReponseLines)); LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler); 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); }
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}\"", Path.GetFullPath(AdditionalLibrary)); LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary)); } } } LinkAction.CommandArguments += string.Format(" -Wl,--end-group"); } // Add the additional arguments specified by the environment. LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments; LinkAction.CommandArguments = LinkAction.CommandArguments.Replace("\\", "/"); // Only execute linking on the local PC. LinkAction.bCanExecuteRemotely = false; } } return(Outputs.ToArray()); }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName) { if (Arches.Length == 0) { throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build"); } if (!bHasPrintedApiLevel) { Console.WriteLine("Compiling Native code with NDK API '{0}'", GetNdkApiLevel()); bHasPrintedApiLevel = true; } string BaseArguments = ""; if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create) { BaseArguments += " -Werror"; } // Directly added NDK files for NDK extensions ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName); // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { BaseArguments += string.Format(" -D \"{0}\"", Definition); } var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); string BasePCHName = ""; var PCHExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Android].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { BasePCHName = RemoveArchName(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath).Replace(PCHExtension, ""); } // Create a compile action for each source file. CPPOutput Result = new CPPOutput(); foreach (string Arch in Arches) { foreach (string GPUArchitecture in GPUArchitectures) { // which toolchain to use string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments; if (GPUArchitecture == "-gl4") { Arguments += " -DPLATFORM_ANDROIDGL4=1"; } else if (GPUArchitecture == "-es31") { Arguments += " -DPLATFORM_ANDROIDES31=1"; } // which PCH file to include string PCHArguments = ""; if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { // Add the precompiled header file's path to the include path so Clang can find it. // This needs to be before the other include paths to ensure Clang uses it instead of the source header file. PCHArguments += string.Format(" -include \"{0}\"", InlineArchName(BasePCHName, Arch, GPUArchitecture)); } // Add include paths to the argument list (filtered by architecture) foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths) { if (IsDirectoryForArch(IncludePath, Arch)) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } } foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths) { if (IsDirectoryForArch(IncludePath, Arch)) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } } foreach (FileItem SourceFile in SourceFiles) { Action CompileAction = new Action(ActionType.Compile); string FileArguments = ""; bool bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C"; // should we disable optimizations on this file? // @todo android - We wouldn't need this if we could disable optimizations per function (via pragma) bool bDisableOptimizations = false; // SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1; if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath); } bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug; // Add C or C++ specific compiler arguments. if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { FileArguments += GetCompileArguments_PCH(bDisableOptimizations); } else if (bIsPlainCFile) { FileArguments += GetCompileArguments_C(bDisableOptimizations); } else { FileArguments += GetCompileArguments_CPP(bDisableOptimizations); // only use PCH for .cpp files FileArguments += PCHArguments; } // Add the C++ source file and its included files to the prerequisite item list. AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { // Add the precompiled header file to the produced item list. FileItem PrecompiledHeaderFile = FileItem.GetItemByPath( Path.Combine( CompileEnvironment.Config.OutputDirectory, Path.GetFileName(InlineArchName(SourceFile.AbsolutePath, Arch, GPUArchitecture) + PCHExtension) ) ); CompileAction.ProducedItems.Add(PrecompiledHeaderFile); Result.PrecompiledHeaderFile = PrecompiledHeaderFile; // Add the parameters needed to compile the precompiled header file to the command-line. FileArguments += string.Format(" -o \"{0}\"", PrecompiledHeaderFile.AbsolutePath, false); } else { if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { CompileAction.bIsUsingPCH = true; FileItem ArchPrecompiledHeaderFile = FileItem.GetItemByPath(InlineArchName(BasePCHName, Arch, GPUArchitecture) + PCHExtension); CompileAction.PrerequisiteItems.Add(ArchPrecompiledHeaderFile); } var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Android].GetBinaryExtension(UEBuildBinaryType.Object); // Add the object file to the produced item list. FileItem ObjectFile = FileItem.GetItemByPath( InlineArchName(Path.Combine( CompileEnvironment.Config.OutputDirectory, Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension), Arch, GPUArchitecture ) ); CompileAction.ProducedItems.Add(ObjectFile); Result.ObjectFiles.Add(ObjectFile); FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false); } // Add the source file path to the command-line. FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath); // Build a full argument list string AllArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments; AllArguments = ActionThread.ExpandEnvironmentVariables(AllArguments); AllArguments = AllArguments.Replace("\\", "/"); // Create the response file string ResponseFileName = CompileAction.ProducedItems[0].AbsolutePath + ".response"; string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List <string> { AllArguments })); CompileAction.WorkingDirectory = Path.GetFullPath("."); CompileAction.CommandPath = ClangPath; CompileAction.CommandArguments = ResponseArgument; CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", "")); CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler); // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves CompileAction.bShouldOutputStatusDescription = true; // Don't farm out creation of pre-compiled headers as it is the critical path task. CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create || BuildConfiguration.bAllowRemotelyCompiledPCHs; } } } return(Result); }
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); 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); }