Пример #1
0
        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);
        }
Пример #2
0
 static string GetFullIncludePath(string IncludePath)
 {
     return(Path.GetFullPath(ActionThread.ExpandEnvironmentVariables(IncludePath)));
 }
Пример #3
0
        internal bool ExecuteActions(List <Action> InActions, Dictionary <Action, ActionThread> InActionThreadDictionary)
        {
            // Build the script file that will be executed by SN-DBS
            StreamWriter ScriptFile;
            string       ScriptFilename = Path.Combine(UnrealBuildTool.EngineDirectory.FullName, "Intermediate", "Build", "SNDBS.bat");

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

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

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

            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();
		}
Пример #6
0
        public override FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            List <FileItem> Outputs = new List <FileItem>();

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

                    // Android will have an array of outputs
                    if (LinkEnvironment.Config.OutputFilePaths.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());
        }
Пример #7
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            if (Arches.Length == 0)
            {
                throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build");
            }

            if (!bHasPrintedApiLevel)
            {
                Console.WriteLine("Compiling 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);
        }