Ejemplo n.º 1
0
 public virtual CPPOutput CompileRCFiles(STBuildTarget Target, CPPEnvironment Environment, List<FileItem> RCFiles)
 {
     CPPOutput Result = new CPPOutput();
     return Result;
 }
Ejemplo n.º 2
0
        public override CPPOutput CompileRCFiles(STBuildTarget Target, CPPEnvironment Environment, List<FileItem> RCFiles)
        {
            var EnvVars = VCEnvironment.SetEnvironment(Environment.Config.Target.Platform);

            CPPOutput Result = new CPPOutput();

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

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

                // Resource tool can run remotely if possible
                CompileAction.bCanExecuteRemotely = true;

                if (WindowsPlatform.bCompileWithClang)
                {
                    CompileAction.OutputEventHandler = new DataReceivedEventHandler(ClangCompilerOutputFormatter);
                }

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

                // If we're compiling for 64-bit Windows, also add the _WIN64 definition to the resource
                // compiler so that we can switch on that in the .rc file using #ifdef.
                if (Environment.Config.Target.Platform == CPPTargetPlatform.Win64)
                {
                    CompileAction.CommandArguments += " /D _WIN64";
                }

                // When targeting Windows XP with Visual Studio 2012+, we need to tell the compiler to use the older Windows SDK that works
                // with Windows XP (http://blogs.msdn.com/b/vcblog/archive/2012/10/08/10357555.aspx)
                if (WindowsPlatform.IsWindowsXPSupported())
                {
                    CompileAction.CommandArguments += " /D_USING_V110_SDK71_";
                }

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

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

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

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

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

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

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

            return Result;
        }
Ejemplo n.º 3
0
        public override CPPOutput CompileCPPFiles(STBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
        {
            var EnvVars = VCEnvironment.SetEnvironment(CompileEnvironment.Config.Target.Platform);

            StringBuilder Arguments = new StringBuilder();
            AppendCLArguments_Global(CompileEnvironment, EnvVars, Arguments);

            // Add include paths to the argument list.
            if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
            {
                foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
                {
                    Arguments.AppendFormat(" /I \"{0}\"", IncludePath);
                }
            }
            else
            {
                foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
                {
                    Arguments.AppendFormat(" /I \"{0}\"", System.IO.Path.GetFullPath(IncludePath));
                }
            }
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
            {
                if (WindowsPlatform.bCompileWithClang)
                {
                    // @todo Clang: Clang uses a special command-line syntax for system headers.  This is used for two reasons.  The first is that Clang will automatically
                    // suppress compiler warnings in headers found in these directories, such as the DirectX SDK headers.  The other reason this is important is in the case
                    // where there the same header include path is passed as both a regular include path and a system include path (extracted from INCLUDE environment).  In
                    // this case Clang will ignore any earlier occurrence of the include path, preventing a system header include path from overriding a different system
                    // include path set later on by a module.  NOTE: When passing "-Xclang", these options will always appear at the end of the command-line string, meaning
                    // they will be forced to appear *after* all environment-variable-extracted includes.  This is technically okay though.
                    Arguments.AppendFormat(" -Xclang -internal-isystem -Xclang \"{0}\"", IncludePath);
                }
                else
                {
                    Arguments.AppendFormat(" /I \"{0}\"", IncludePath);
                }
            }

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

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

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

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

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

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();
            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                CompileAction.CommandDescription = "Compile";

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

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

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

                if (WindowsPlatform.bCompileWithClang)
                {
                    CompileAction.OutputEventHandler = new DataReceivedEventHandler(ClangCompilerOutputFormatter);
                }

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

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

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

                    // @todo clang: Ideally clang-cl would support the regular MSVC arguments for PCH files, and we wouldn't need to do this manually
                    if (WindowsPlatform.bCompileWithClang)
                    {
                        // Tell Clang to generate a PCH header
                        FileArguments.Append(" -Xclang -x -Xclang c++-header");	// @todo clang: Doesn't work due to Clang-cl overriding us at the end of the command-line (see -### option output)
                        FileArguments.AppendFormat(" /Fo\"{0}\"", PrecompiledHeaderFile.AbsolutePath);

                        // Clang PCH generation doesn't create an .obj file to link in, unlike MSVC
                        bEmitsObjectFile = false;
                    }
                    else
                    {
                        // Add the parameters needed to compile the precompiled header file to the command-line.
                        FileArguments.AppendFormat(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                        FileArguments.AppendFormat(" /Fp\"{0}\"", PrecompiledHeaderFile.AbsolutePath);

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

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

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

                        if (WindowsPlatform.bCompileWithClang)
                        {
                            // NOTE: With Clang, PCH headers are ALWAYS forcibly included!
                            // NOTE: This needs to be before the other include paths to ensure Clang uses it instead of the source header file.
                            FileArguments.AppendFormat(" /FI\"{0}\"", Path.ChangeExtension(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath, null));
                        }
                        else
                        {
                            FileArguments.AppendFormat(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                            FileArguments.AppendFormat(" /Fp\"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath);

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

                    // UnrealCodeAnalyzer requires compiled file name to be first argument.
                    if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                    {
                        // Add the source file path to the command-line.
                        FileArguments.AppendFormat(" \"{0}\"", SourceFile.AbsolutePath);
                    }

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

                if (bEmitsObjectFile)
                {
                    var ObjectFileExtension = STBuildPlatform.BuildPlatformDictionary[STTargetPlatform.Win64].GetBinaryExtension(STBuildBinaryType.Object);
                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(ObjectFile);
                    Result.ObjectFiles.Add(ObjectFile);
                    // UnrealCodeAnalyzer requires specific position of output file.
                    if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                    {
                        FileArguments.AppendFormat(" /Fo\"{0}\"", ObjectFile.AbsolutePath);
                    }
                }

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

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

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

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

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

                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                if (BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    CompileAction.CommandPath = System.IO.Path.Combine(CompileAction.WorkingDirectory, @"..", @"Binaries", @"Win32", @"UnrealCodeAnalyzer.exe");
                }
                else
                {
                    CompileAction.CommandPath = EnvVars.CompilerPath;
                }

                if (!WindowsPlatform.bCompileWithClang || !BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    CompileAction.bIsVCCompiler = true;
                }

                string UnrealCodeAnalyzerArguments = "";
                if (BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    var ObjectFileExtension = @".includes";
                    FileItem ObjectFile = FileItem.GetItemByPath(Path.Combine(CompileEnvironment.Config.OutputDirectory, Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension));
                    var ClangPath = System.IO.Path.Combine(CompileAction.WorkingDirectory, @"ThirdParty", @"llvm", @"3.5.0", @"bin", @"vs2013", @"x86", @"release", @"clang++.exe");
                    UnrealCodeAnalyzerArguments = @"-CreateIncludeFiles " + SourceFile.AbsolutePath + @" -OutputFile=""" + ObjectFile.AbsolutePath + @""" -- " + ClangPath + @" --driver-mode=cl ";
                }

                CompileAction.CommandArguments = UnrealCodeAnalyzerArguments + Arguments.ToString() + FileArguments.ToString() + CompileEnvironment.Config.AdditionalArguments;

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

                if (WindowsPlatform.bCompileWithClang || BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    // Clang doesn't print the file names by default, so we'll do it ourselves
                    CompileAction.bShouldOutputStatusDescription = true;
                }
                else
                {
                    // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves
                    CompileAction.bShouldOutputStatusDescription = false;
                }

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

                // @todo: XGE has problems remote compiling C++/CLI files that use .NET Framework 4.0
                if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled)
                {
                    CompileAction.bCanExecuteRemotely = false;
                }
            }
            return Result;
        }
Ejemplo n.º 4
0
        public override CPPOutput CompileCPPFiles(STBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
        {
            string Arguments = GetCompileArguments_Global(CompileEnvironment);
            string PCHArguments = "";

            if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
            {
                // Add the precompiled header file's path to the include path so GCC can find it.
                // This needs to be before the other include paths to ensure GCC uses it instead of the source header file.
                var PrecompiledFileExtension = STBuildPlatform.BuildPlatformDictionary[STTargetPlatform.IOS].GetBinaryExtension(STBuildBinaryType.PrecompiledHeader);
                PCHArguments += string.Format(" -include \"{0}\"", ConvertPath(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(PrecompiledFileExtension, "")));
            }

            // Add include paths to the argument list.
            HashSet<string> AllIncludes = new HashSet<string>(CompileEnvironment.Config.CPPIncludeInfo.IncludePaths);
            AllIncludes.UnionWith(CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths);
            foreach (string IncludePath in AllIncludes)
            {
                Arguments += string.Format(" -I\"{0}\"", ConvertPath(Path.GetFullPath(IncludePath)));

                if (BuildHostPlatform.Current.Platform != STTargetPlatform.Mac)
                {
                    // sync any third party headers we may need
                    if (IncludePath.Contains("ThirdParty"))
                    {
                        string[] FileList = Directory.GetFiles(IncludePath, "*.h", SearchOption.AllDirectories);
                        foreach (string File in FileList)
                        {
                            FileItem ExternalDependency = FileItem.GetItemByPath(File);
                            LocalToRemoteFileItem(ExternalDependency, true);
                        }

                        FileList = Directory.GetFiles(IncludePath, "*.cpp", SearchOption.AllDirectories);
                        foreach (string File in FileList)
                        {
                            FileItem ExternalDependency = FileItem.GetItemByPath(File);
                            LocalToRemoteFileItem(ExternalDependency, true);
                        }
                    }
                }
            }

            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                Arguments += string.Format(" -D\"{0}\"", Definition);
            }

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

            CPPOutput Result = new CPPOutput();
            // Create a compile action for each source file.
            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                string FileArguments = "";
                string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant();

                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    // Compile the file as a C++ PCH.
                    FileArguments += GetCompileArguments_PCH();
                }
                else if (Extension == ".C")
                {
                    // Compile the file as C code.
                    FileArguments += GetCompileArguments_C();
                }
                else if (Extension == ".CC")
                {
                    // Compile the file as C++ code.
                    FileArguments += GetCompileArguments_CPP();
                }
                else if (Extension == ".MM")
                {
                    // Compile the file as Objective-C++ code.
                    FileArguments += GetCompileArguments_MM();
                }
                else if (Extension == ".M")
                {
                    // Compile the file as Objective-C++ code.
                    FileArguments += GetCompileArguments_M();
                }
                else
                {
                    // Compile the file as C++ code.
                    FileArguments += GetCompileArguments_CPP();

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

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

                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    var PrecompiledFileExtension = STBuildPlatform.BuildPlatformDictionary[STTargetPlatform.IOS].GetBinaryExtension(STBuildBinaryType.PrecompiledHeader);
                    // Add the precompiled header file to the produced item list.
                    FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                        Path.GetFileName(SourceFile.AbsolutePath) + PrecompiledFileExtension
                            )
                        );

                    FileItem RemotePrecompiledHeaderFile = LocalToRemoteFileItem(PrecompiledHeaderFile, false);
                    CompileAction.ProducedItems.Add(RemotePrecompiledHeaderFile);
                    Result.PrecompiledHeaderFile = RemotePrecompiledHeaderFile;

                    // Add the parameters needed to compile the precompiled header file to the command-line.
                    FileArguments += string.Format(" -o \"{0}\"", RemotePrecompiledHeaderFile.AbsolutePath, false);
                }
                else
                {
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        CompileAction.bIsUsingPCH = true;
                        CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile);
                    }
                    var ObjectFileExtension = STBuildPlatform.BuildPlatformDictionary[STTargetPlatform.IOS].GetBinaryExtension(STBuildBinaryType.Object);
                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                            )
                        );

                    FileItem RemoteObjectFile = LocalToRemoteFileItem(ObjectFile, false);
                    CompileAction.ProducedItems.Add(RemoteObjectFile);
                    Result.ObjectFiles.Add(RemoteObjectFile);
                    FileArguments += string.Format(" -o \"{0}\"", RemoteObjectFile.AbsolutePath, false);
                }

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

                string CompilerPath = XcodeDeveloperDir + "Toolchains/XcodeDefault.xctoolchain/usr/bin/" + IOSCompiler;
                if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != STTargetPlatform.Mac)
                {
                    CompileAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
                }

                // RPC utility parameters are in terms of the Mac side
                CompileAction.WorkingDirectory = GetMacDevSrcRoot();
                CompileAction.CommandPath = CompilerPath;
                CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath));
                CompileAction.bIsGCCCompiler = true;
                // We're already distributing the command by execution on Mac.
                CompileAction.bCanExecuteRemotely = false;
                CompileAction.bShouldOutputStatusDescription = true;
                CompileAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);
            }
            return Result;
        }