private static ExecutionResult RunFBuild(BuildStep step, string bffString) { ExecutionResult result; try { var watch = Stopwatch.StartNew(); Log.TraceInformation(step == BuildStep.CompileObjects ? "Building Objects" : "Linking Objects"); var distScriptFilename = Path.Combine(BuildConfiguration.BaseIntermediatePath, "fbuild.bff"); var distScriptFileStream = new FileStream(distScriptFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read); var scriptFile = new StreamWriter(distScriptFileStream) { AutoFlush = true }; scriptFile.WriteLine(ActionThread.ExpandEnvironmentVariables(bffString)); scriptFile.Flush(); scriptFile.Close(); scriptFile.Dispose(); scriptFile = null; result = DispatchFBuild(); watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Log.TraceInformation((step == BuildStep.CompileObjects ? "Object Compilation" : "Object Linking") + " Finished. Execution Time: " + elapsedMs); } catch (Exception) { result = ExecutionResult.TasksFailed; } return(result); }
static string GetFullIncludePath(string IncludePath) { return(Path.GetFullPath(ActionThread.ExpandEnvironmentVariables(IncludePath))); }
internal bool ExecuteActions(List <Action> InActions, Dictionary <Action, ActionThread> InActionThreadDictionary) { // Build the script file that will be executed by SN-DBS StreamWriter ScriptFile; string ScriptFilename = Path.Combine(UnrealBuildTool.EngineDirectory.FullName, "Intermediate", "Build", "SNDBS.bat"); FileStream ScriptFileStream = new FileStream(ScriptFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read); ScriptFile = new StreamWriter(ScriptFileStream); ScriptFile.AutoFlush = true; int NumScriptedActions = 0; List <Action> LocalActions = new List <Action>(); ActionThread DummyActionThread = new ActionThread(null, 1, 1); foreach (Action Action in InActions) { ActionThread ActionProcess = null; bool bFoundActionProcess = InActionThreadDictionary.TryGetValue(Action, out ActionProcess); if (bFoundActionProcess == false) { // Determine whether there are any prerequisites of the action that are outdated. bool bHasOutdatedPrerequisites = false; bool bHasFailedPrerequisites = false; foreach (FileItem PrerequisiteItem in Action.PrerequisiteItems) { if (PrerequisiteItem.ProducingAction != null && InActions.Contains(PrerequisiteItem.ProducingAction)) { ActionThread PrerequisiteProcess = null; bool bFoundPrerequisiteProcess = InActionThreadDictionary.TryGetValue(PrerequisiteItem.ProducingAction, out PrerequisiteProcess); if (bFoundPrerequisiteProcess == true) { if (PrerequisiteProcess == null) { bHasFailedPrerequisites = true; } else if (PrerequisiteProcess.bComplete == false) { bHasOutdatedPrerequisites = true; } else if (PrerequisiteProcess.ExitCode != 0) { bHasFailedPrerequisites = true; } } else { bHasOutdatedPrerequisites = true; } } } // If there are any failed prerequisites of this action, don't execute it. if (bHasFailedPrerequisites) { // Add a null entry in the dictionary for this action. InActionThreadDictionary.Add(Action, null); } // If there aren't any outdated prerequisites of this action, execute it. else if (!bHasOutdatedPrerequisites) { if (Action.bCanExecuteRemotely == false || Action.bCanExecuteRemotelyWithSNDBS == false) { // Execute locally LocalActions.Add(Action); } else { // Add to script for execution by SN-DBS string NewCommandArguments = "\"" + Action.CommandPath + "\"" + " " + Action.CommandArguments; ScriptFile.WriteLine(ActionThread.ExpandEnvironmentVariables(NewCommandArguments)); InActionThreadDictionary.Add(Action, DummyActionThread); Action.StartTime = Action.EndTime = DateTimeOffset.Now; Log.TraceInformation("[{0}/{1}] {2} {3}", JobNumber, InActions.Count, Action.CommandDescription, Action.StatusDescription); JobNumber++; NumScriptedActions++; } } } } ScriptFile.Flush(); ScriptFile.Close(); ScriptFile.Dispose(); ScriptFile = null; if (NumScriptedActions > 0) { // Create the process string SCERoot = Environment.GetEnvironmentVariable("SCE_ROOT_DIR"); string SNDBSExecutable = Path.Combine(SCERoot, "Common/SN-DBS/bin/dbsbuild.exe"); ProcessStartInfo PSI = new ProcessStartInfo(SNDBSExecutable, String.Format("-q -p UE4 -s \"{0}\"", FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "sndbs.bat").FullName)); PSI.RedirectStandardOutput = true; PSI.RedirectStandardError = true; PSI.UseShellExecute = false; PSI.CreateNoWindow = true; PSI.WorkingDirectory = Path.GetFullPath(".");; Process NewProcess = new Process(); NewProcess.StartInfo = PSI; NewProcess.OutputDataReceived += new DataReceivedEventHandler(ActionDebugOutput); NewProcess.ErrorDataReceived += new DataReceivedEventHandler(ActionDebugOutput); DateTimeOffset StartTime = DateTimeOffset.Now; NewProcess.Start(); NewProcess.BeginOutputReadLine(); NewProcess.BeginErrorReadLine(); NewProcess.WaitForExit(); TimeSpan Duration; DateTimeOffset EndTime = DateTimeOffset.Now; if (EndTime == DateTimeOffset.MinValue) { Duration = DateTimeOffset.Now - StartTime; } else { Duration = EndTime - StartTime; } DummyActionThread.bComplete = true; int ExitCode = NewProcess.ExitCode; if (ExitCode != 0) { return(false); } } // Execute local tasks if (LocalActions.Count > 0) { return(ExecuteLocalActions(LocalActions, InActionThreadDictionary, InActions.Count)); } return(true); }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName) { if (Arches.Count == 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); // Deal with dynamic modules removed by architecture GenerateEmptyLinkFunctionsForRemovedModules(SourceFiles, ModuleName, CompileEnvironment.Config.OutputDirectory); // 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); var NDKRoot = Environment.GetEnvironmentVariable("NDKROOT").Replace("\\", "/"); string BasePCHName = ""; var PCHExtension = UEBuildPlatform.GetBuildPlatform(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) { if (ShouldSkipModule(ModuleName, Arch)) { continue; } foreach (string GPUArchitecture in GPUArchitectures) { // which toolchain to use string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments; switch (Arch) { case "-armv7": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break; case "-arm64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_ARM64=1"; break; case "-x86": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_X86=1"; break; case "-x64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_X64=1"; break; default: Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break; } if (GPUArchitecture == "-esdeferred") { Arguments += " -DPLATFORM_ANDROIDESDEFERRED=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"; bool bDisableShadowWarning = false; // 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); // remove shadow variable warnings for NDK files if (SourceFile.AbsolutePath.Replace("\\", "/").StartsWith(NDKRoot)) { bDisableShadowWarning = true; } } 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.GetItemByFileReference( FileReference.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.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.Object); // Add the object file to the produced item list. FileItem ObjectFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, InlineArchName(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("\\", "/"); // Remove shadow warning for this file if requested if (bDisableShadowWarning) { int WarningIndex = AllArguments.IndexOf(" -Wshadow"); if (WarningIndex > 0) { AllArguments = AllArguments.Remove(WarningIndex, 9); } } // Create the response file FileReference ResponseFileName = CompileAction.ProducedItems[0].Reference + "_" + AllArguments.GetHashCode().ToString("X") + ".response"; string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List<string> { AllArguments }).FullName); CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; CompileAction.CommandPath = ClangPath; CompileAction.CommandArguments = ResponseArgument; CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", "")); // 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>(); var NDKRoot = Environment.GetEnvironmentVariable("NDKROOT").Replace("\\", "/"); int NDKApiLevelInt = GetNdkApiLevelInt(); string OptionalLinkArguments; for (int ArchIndex = 0; ArchIndex < Arches.Count; ArchIndex++) { string Arch = Arches[ArchIndex]; // 32-bit ABI may need fixup for removed bsd_signal in NDK11 for android-21+ OptionalLinkArguments = ""; if (NDKApiLevelInt >= 21) { // this file was added in NDK11 so use existence to detect (RELEASE.TXT no longer present) if (File.Exists(Path.Combine(NDKRoot, "source.properties"))) { switch (Arch) { case "-armv7": OptionalLinkArguments = string.Format(" \"{0}\"", Path.Combine(UnrealBuildTool.EngineDirectory.FullName, "Build/Android/Prebuilt/bsdsignal/lib/armeabi-v7a/libbsdsignal.a")); break; case "-x86": OptionalLinkArguments = string.Format(" \"{0}\"", Path.Combine(UnrealBuildTool.EngineDirectory.FullName, "Build/Android/Prebuilt/bsdsignal/lib/x86/libbsdsignal.a")); break; } } } for (int GPUArchIndex = 0; GPUArchIndex < GPUArchitectures.Count; GPUArchIndex++) { string GPUArchitecture = GPUArchitectures[GPUArchIndex]; int OutputPathIndex = ArchIndex * GPUArchitectures.Count + GPUArchIndex; // Android will have an array of outputs if (LinkEnvironment.Config.OutputFilePaths.Count < OutputPathIndex || !LinkEnvironment.Config.OutputFilePaths[OutputPathIndex].GetFileNameWithoutExtension().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 = UnrealBuildTool.EngineSourceDirectory.FullName; if (LinkEnvironment.Config.bIsBuildingLibrary) { switch (Arch) { case "-armv7": LinkAction.CommandPath = ArPathArm; break; case "-arm64": LinkAction.CommandPath = ArPathArm64; break; case "-x86": LinkAction.CommandPath = ArPathx86; ; break; case "-x64": LinkAction.CommandPath = ArPathx64; ; break; default: LinkAction.CommandPath = ArPathArm; ; break; } } else { LinkAction.CommandPath = ClangPath; } string LinkerPath = LinkAction.WorkingDirectory; LinkAction.WorkingDirectory = LinkEnvironment.Config.IntermediateDirectory.FullName; // 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.GetItemByFileReference(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.FullName.Replace("\\", "/"), ""); AbsolutePath = AbsolutePath.TrimStart(new char[] { '/' }); InputFileNames.Add(string.Format("\"{0}\"", AbsolutePath)); LinkAction.PrerequisiteItems.Add(InputFile); } } FileReference 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 += OptionalLinkArguments; 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[] 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 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 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); } // 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); }