Exemplo n.º 1
0
        public override CPPOutput CompileCPPFiles(CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
        {
            if (CompileEnvironment.Config.TargetArchitecture == "-win32")
            {
                return base.CompileCPPFiles(CompileEnvironment, SourceFiles, ModuleName);
            }

            string Arguments = GetCLArguments_Global(CompileEnvironment);
            string BaseSDKPath = Environment.GetEnvironmentVariable("EMSCRIPTEN");

            CPPOutput Result = new CPPOutput();

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.IncludePaths)
            {
                Arguments += string.Format(" -I\"{0}\"", IncludePath);
            }
            foreach (string IncludePath in CompileEnvironment.Config.SystemIncludePaths)
            {
                Arguments += string.Format(" -I\"{0}\"", IncludePath);
            }

            if ( ModuleName == "Launch" )
                Arguments += string.Format(" -I\"{0}\"", BaseSDKPath + "/system/lib/libcxxabi/include" );

            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                Arguments += string.Format(" -D{0}", Definition);
            }

            // Create a compile action for each source file.
            if (ModuleName == "Launch")
                SourceFiles.Add(FileItem.GetItemByPath(BaseSDKPath + "/system/lib/libcxxabi/src/cxa_demangle.cpp"));

            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                bool bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C";

                // Add the C++ source file and its included files to the prerequisite item list.
                CompileAction.PrerequisiteItems.Add(SourceFile);
                foreach (FileItem IncludedFile in CompileEnvironment.GetIncludeDependencies(SourceFile))
                {
                    CompileAction.PrerequisiteItems.Add(IncludedFile);
                }

                // Add the source file path to the command-line.
                string bfastlinkstring = bEnableFastIteration ? "" : " -c ";
                string FileArguments = string.Format(bfastlinkstring + " \"{0}\"", SourceFile.AbsolutePath);

                // Add the object file to the produced item list.
                FileItem ObjectFile = FileItem.GetItemByPath(
                    Path.Combine(
                        CompileEnvironment.Config.OutputDirectory,
                        Path.GetFileName(SourceFile.AbsolutePath) + (bEnableFastIteration ? ".js" : ".o")
                        )
                    );
                CompileAction.ProducedItems.Add(ObjectFile);
                FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath);

                // Add C or C++ specific compiler arguments.
                if (bIsPlainCFile)
                {
                    FileArguments += GetCLArguments_C(CompileEnvironment.Config.TargetArchitecture);
                }
                else
                {
                    FileArguments += GetCLArguments_CPP(CompileEnvironment);
                }

                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                CompileAction.CommandPath = PythonPath;

                string fastlinkString = SourceFile.Info.FullName.Contains("Launch") ?  " -s MAIN_MODULE=1 " : "-s SIDE_MODULE=1";
                CompileAction.CommandArguments = EMCCPath + Arguments + (bEnableFastIteration ? fastlinkString : "" )+ FileArguments + CompileEnvironment.Config.AdditionalArguments;

                System.Console.WriteLine(CompileAction.CommandArguments);
                CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath);
                CompileAction.StatusDetailedDescription = SourceFile.Description;
                CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler);

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

                // this is the final output of the compile step (a .abc file)
                Result.ObjectFiles.Add(ObjectFile);

                // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves
                CompileAction.bShouldOutputStatusDescription = true;

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

            return Result;
        }
Exemplo n.º 2
0
        public override CPPOutput CompileCPPFiles(CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
        {
            string Arguments = GetCompileArguments_Global(CompileEnvironment);
            string PCHArguments = "";

            if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create)
            {
                Arguments += " -Werror";
            }

            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.
                PCHArguments += string.Format(" -include \"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(".gch", ""));
            }

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

                if (ExternalExecution.GetRuntimePlatform() != UnrealTargetPlatform.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);
            }

            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.
                CompileAction.PrerequisiteItems.Add(SourceFile);

                if (ExternalExecution.GetRuntimePlatform() != UnrealTargetPlatform.Mac)
                {
                    QueueFileForBatchUpload(SourceFile);
                }

                foreach (FileItem IncludedFile in CompileEnvironment.GetIncludeDependencies(SourceFile))
                {
                    if (ExternalExecution.GetRuntimePlatform() != UnrealTargetPlatform.Mac)
                    {
                        QueueFileForBatchUpload(IncludedFile);
                    }

                    CompileAction.PrerequisiteItems.Add(IncludedFile);
                }

                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(SourceFile.AbsolutePath) + ".gch"
                            )
                        );

                    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);
                    }

                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ".o"
                            )
                        );

                    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);

                if (ExternalExecution.GetRuntimePlatform() != UnrealTargetPlatform.Mac)
                {
                    CompileAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
                }

                CompileAction.WorkingDirectory = GetMacDevSrcRoot();
                CompileAction.CommandPath = "xcrun";
                CompileAction.CommandArguments = MacCompiler + Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath));
                CompileAction.StatusDetailedDescription = SourceFile.Description;
                CompileAction.bIsGCCCompiler = true;
                // We're already distributing the command by execution on Mac.
                CompileAction.bCanExecuteRemotely = false;
                CompileAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);
            }
            return Result;
        }
Exemplo n.º 3
0
        public override CPPOutput CompileCPPFiles(CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
        {
            string Arguments = GetCLArguments_Global(CompileEnvironment);

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.IncludePaths)
            {
                Arguments += string.Format(" /I \"{0}\"", IncludePath);
            }
            foreach (string IncludePath in CompileEnvironment.Config.SystemIncludePaths)
            {
                Arguments += string.Format(" /I \"{0}\"", IncludePath);
            }

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

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

                // Add private assembly references
                foreach (PrivateAssemblyInfo CurAssemblyInfo in CompileEnvironment.PrivateAssemblyDependencies)
                {
                    Arguments += string.Format(" /FU \"{0}\"", CurAssemblyInfo.FileItem.AbsolutePath);
                }
            }
            else
            {
                foreach (string AssemblyPath in CompileEnvironment.Config.SystemDotNetAssemblyPaths)
                {
                    Arguments += string.Format(" /AI \"{0}\"", AssemblyPath);
                }

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

            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                Arguments += string.Format(" /D \"{0}\"", Definition);
            }

            // Log.TraceInformation("Compile Arguments for {0}:", ModuleName);
            // Log.TraceInformation(Arguments);

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

                // Add the C++ source file and its included files to the prerequisite item list.
                CompileAction.PrerequisiteItems.Add(SourceFile);
                foreach (FileItem IncludedFile in CompileEnvironment.GetIncludeDependencies(SourceFile))
                {
                    CompileAction.PrerequisiteItems.Add(IncludedFile);
                }

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

                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    // Generate a CPP File that just includes the precompiled header.
                    string PCHCPPFilename = "PCH." + 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 += string.Format(" /I \"{0}\"", OriginalPCHHeaderDirectory);

                    // Add the precompiled header file to the produced items list.
                    FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ".pch"
                            )
                        );
                    CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
                    Result.PrecompiledHeaderFile = PrecompiledHeaderFile;

                    // Add the parameters needed to compile the precompiled header file to the command-line.
                    FileArguments += string.Format(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                    FileArguments += string.Format(" /Fp\"{0}\"", PrecompiledHeaderFile.AbsolutePath);
                    FileArguments += string.Format(" \"{0}\"", PCHCPPFile.AbsolutePath);

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

                        if (CompileEnvironment.Config.bForceIncludePrecompiledHeader)
                        {
                            // Force include the precompiled header file.  This is needed because we may have selected a
                            // precompiled header that is different than the first direct include in the C++ source file, but
                            // we still need to make sure that our precompiled header is the first thing included!
                            FileArguments += string.Format(" /FI\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                        }
                    }

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

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

                // Add the object file to the produced item list.
                FileItem ObjectFile = FileItem.GetItemByPath(
                    Path.Combine(
                        CompileEnvironment.Config.OutputDirectory,
                        Path.GetFileName(SourceFile.AbsolutePath) + ".obj"
                        )
                    );
                CompileAction.ProducedItems.Add(ObjectFile);
                Result.ObjectFiles.Add(ObjectFile);
                FileArguments += string.Format(" /Fo\"{0}\"", ObjectFile.AbsolutePath);

                // create PDBs per-file when not using debug info, otherwise it will try to share a PDB file, which causes
                // PCH creation to be serial rather than parallel (when debug info is disabled)
                // See https://udn.epicgames.com/lists/showpost.php?id=50619&list=unprog3
                if (!CompileEnvironment.Config.bCreateDebugInfo || BuildConfiguration.bUsePDBFiles)
                {
                    string PDBFileName;
                    bool bActionProducesPDB = false;

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

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

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

                // Add C or C++ specific compiler arguments.
                if (bIsPlainCFile)
                {
                    FileArguments += GetCLArguments_C();
                }
                else
                {
                    FileArguments += GetCLArguments_CPP(CompileEnvironment);
                }

                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                CompileAction.CommandPath = GetVCToolPath(CompileEnvironment.Config.TargetPlatform, CompileEnvironment.Config.TargetConfiguration, "cl");
                CompileAction.bIsVCCompiler = true;
                CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath));
                CompileAction.StatusDetailedDescription = SourceFile.Description;

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

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

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.IncludePaths)
            {
                Arguments += string.Format(" /I \"{0}\"", IncludePath);
            }
            foreach (string IncludePath in CompileEnvironment.Config.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 += string.Format(" -Xclang -internal-isystem -Xclang \"{0}\"", IncludePath);
                }
                else
                {
                    Arguments += string.Format(" /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 += string.Format(" /AI \"{0}\"", AssemblyPath);
                }

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

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

            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                Arguments += string.Format(" /D \"{0}\"", Definition);
            }

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

                // Add the C++ source file and its included files to the prerequisite item list.
                CompileAction.PrerequisiteItems.Add(SourceFile);
                var IncludeDependencies = CompileEnvironment.GetIncludeDependencies( SourceFile );
                foreach (FileItem IncludedFile in IncludeDependencies)
                {
                    CompileAction.PrerequisiteItems.Add(IncludedFile);
                }

                // 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 );
                    }
                }

                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 += string.Format(" /I \"{0}\"", OriginalPCHHeaderDirectory);

                    // Add the precompiled header file to the produced items list.
                    FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ".pch"
                            )
                        );
                    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 += " -Xclang -x -Xclang c++-header";	// @todo clang: Doesn't work do to Clang-cl overriding us at the end of the command-line (see -### option output)
                        FileArguments += string.Format(" /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 += string.Format(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                        FileArguments += string.Format(" /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 += string.Format(" /Yl{0}", FakeUniquePCHSymbolName);
                        }
                    }

                    FileArguments += string.Format(" \"{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 += string.Format(" /FI\"{0}\"", Path.ChangeExtension(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath, null));
                        }
                        else
                        {
                            FileArguments += string.Format(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                            FileArguments += string.Format(" /Fp\"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath);

                            if( CompileEnvironment.Config.bForceIncludePrecompiledHeader )
                            {
                                // Force include the precompiled header file.  This is needed because we may have selected a
                                // precompiled header that is different than the first direct include in the C++ source file, but
                                // we still need to make sure that our precompiled header is the first thing included!
                                FileArguments += string.Format( " /FI\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                            }
                        }
                    }

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

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

                if( bEmitsObjectFile )
                {
                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ".obj"
                            )
                        );
                    CompileAction.ProducedItems.Add(ObjectFile);
                    Result.ObjectFiles.Add(ObjectFile);
                    FileArguments += string.Format(" /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";
                    }

                    // @todo Clang: Clang doesn't emit PDB files even when debugging is enabled
                    if( !WindowsPlatform.bCompileWithClang )
                    {
                        // Specify the PDB file that the compiler should write to.
                        FileItem PDBFile = FileItem.GetItemByPath(
                                Path.Combine(
                                    CompileEnvironment.Config.OutputDirectory,
                                    PDBFileName + ".pdb"
                                    )
                                );
                        FileArguments += string.Format(" /Fd\"{0}\"", PDBFile.AbsolutePath);

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

                // Add C or C++ specific compiler arguments.
                if (bIsPlainCFile)
                {
                    FileArguments += GetCLArguments_C();
                }
                else
                {
                    FileArguments += GetCLArguments_CPP( CompileEnvironment );
                }

                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                CompileAction.CommandPath = GetVCToolPath(CompileEnvironment.Config.TargetPlatform, CompileEnvironment.Config.TargetConfiguration, "cl");

                if( !WindowsPlatform.bCompileWithClang )
                {
                    CompileAction.bIsVCCompiler = true;
                }
                CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.StatusDetailedDescription = SourceFile.Description;

                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 )
                {
                    // 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;
        }
Exemplo n.º 5
0
        public override CPPOutput CompileRCFiles(CPPEnvironment Environment, List<FileItem> RCFiles)
        {
            CPPOutput Result = new CPPOutput();

            foreach (FileItem RCFile in RCFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                CompileAction.CommandPath = GetVCToolPath(Environment.Config.TargetPlatform, Environment.Config.TargetConfiguration, "rc");
                CompileAction.StatusDescription = Path.GetFileName(RCFile.AbsolutePath);

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

                // If we're compiling for 64-bit Windows, also add the _WIN64 definition to the resource
                // compiler so that we can switch on that in the .rc file using #ifdef.
                if (Environment.Config.TargetPlatform == 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.SupportWindowsXP)
                {
                    if (WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2013)
                    {
                        CompileAction.CommandArguments += " /D_USING_V120_SDK71_";
                    }
                    else if (WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2012)
                    {
                        CompileAction.CommandArguments += " /D_USING_V110_SDK71_";
                    }
                }

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

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

                // System include paths.
                foreach( var SystemIncludePath in Environment.Config.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.PrerequisiteItems.Add(RCFile);
                CompileAction.CommandArguments += string.Format(" \"{0}\"", RCFile.AbsolutePath);

                // Add the files included by the RC file as prerequisites of the action.
                foreach (FileItem IncludedFile in Environment.GetIncludeDependencies(RCFile))
                {
                    CompileAction.PrerequisiteItems.Add(IncludedFile);
                }
            }

            return Result;
        }
Exemplo n.º 6
0
        // UEBuildModule interface.
        public override List<FileItem> Compile(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment, bool bCompileMonolithic)
        {
            UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.TargetPlatform);

            var LinkInputFiles = new List<FileItem>();
            if( ProjectFileGenerator.bGenerateProjectFiles && IntelliSenseGatherer == null)
            {
                // Nothing to do for IntelliSense, bail out early
                return LinkInputFiles;
            }

            if(RedistStaticLibraryPath != null && !bBuildingRedistStaticLibrary)
            {
                // The redist static library will be added in SetupPrivateLinkEnvironment
                return LinkInputFiles;
            }

            var ModuleCompileEnvironment = new CPPEnvironment(CompileEnvironment);

            // Override compile environment
            ModuleCompileEnvironment.Config.OptimizeCode = OptimizeCode;
            ModuleCompileEnvironment.Config.bUseRTTI = bUseRTTI;
            ModuleCompileEnvironment.Config.bFasterWithoutUnity = bFasterWithoutUnity;
            ModuleCompileEnvironment.Config.OptimizeCode                           = OptimizeCode;
            ModuleCompileEnvironment.Config.bUseRTTI                               = bUseRTTI;
            ModuleCompileEnvironment.Config.bFasterWithoutUnity                    = bFasterWithoutUnity;
            ModuleCompileEnvironment.Config.OptimizeCode = OptimizeCode;
            ModuleCompileEnvironment.Config.bUseRTTI = bUseRTTI;
            ModuleCompileEnvironment.Config.bEnableBufferSecurityChecks = bEnableBufferSecurityChecks;
            ModuleCompileEnvironment.Config.bFasterWithoutUnity = bFasterWithoutUnity;
            ModuleCompileEnvironment.Config.MinFilesUsingPrecompiledHeaderOverride = MinFilesUsingPrecompiledHeaderOverride;
            ModuleCompileEnvironment.Config.bEnableExceptions                      = bEnableExceptions;
            ModuleCompileEnvironment.Config.bEnableInlining                        = bEnableInlining;
            ModuleCompileEnvironment.Config.OutputDirectory                        = Path.Combine(Binary.Config.IntermediateDirectory, Name);

            // Switch the optimization flag if we're building a game module
            if(Target.Configuration == UnrealTargetConfiguration.DebugGame && Type == UEBuildModuleType.GameModule)
            {
                ModuleCompileEnvironment.Config.TargetConfiguration = CPPTargetConfiguration.Debug;
            }

            // Add the module's private definitions.
            ModuleCompileEnvironment.Config.Definitions.AddRange(Definitions);

            // Setup the compile environment for the module.
            SetupPrivateCompileEnvironment(
                ref ModuleCompileEnvironment.Config.IncludePaths,
                ref ModuleCompileEnvironment.Config.SystemIncludePaths,
                ref ModuleCompileEnvironment.Config.Definitions
                );

            if( IntelliSenseGatherer != null )
            {
                // Update project file's set of preprocessor definitions and include paths
                IntelliSenseGatherer.AddIntelliSensePreprocessorDefinitions( ModuleCompileEnvironment.Config.Definitions );
                IntelliSenseGatherer.AddInteliiSenseIncludePaths( ModuleCompileEnvironment.Config.SystemIncludePaths );
                IntelliSenseGatherer.AddInteliiSenseIncludePaths( ModuleCompileEnvironment.Config.IncludePaths );

                // Bail out.  We don't need to actually compile anything while generating project files.
                return LinkInputFiles;
            }

            // Gather a list of CPP files in the project.
            var CPPFiles = new List<FileItem>();
            var CFiles = new List<FileItem>();
            var CCFiles = new List<FileItem>();
            var MMFiles = new List<FileItem>();
            var RCFiles = new List<FileItem>();
            var MissingFiles = new List<FileItem>();
            foreach (var SourceFile in SourceFiles)
            {
                string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant();
                if (SourceFile.bExists)
                {
                    if (Extension == ".CPP")
                    {
                        CPPFiles.Add(SourceFile);
                    }
                    else if (Extension == ".C")
                    {
                        CFiles.Add(SourceFile);
                    }
                    else if (Extension == ".CC")
                    {
                        CCFiles.Add(SourceFile);
                    }
                    else if (Extension == ".MM" || Extension == ".M")
                    {
                        MMFiles.Add(SourceFile);
                    }
                    else if (Extension == ".RC")
                    {
                        RCFiles.Add(SourceFile);
                    }
                }
                else
                {
                    MissingFiles.Add(SourceFile);
                }
            }

            // For an executable or a static library do not use the default RC file -
            // If the executable wants it, it will be in their source list anyway.
            // The issue here is that when making a monolithic game, the processing
            // of the other game modules will stomp the game-specific rc file.
            if (Binary.Config.Type == UEBuildBinaryType.DynamicLinkLibrary)
            {
                // Add default PCLaunch.rc file if this module has no own resource file specified
                if (RCFiles.Count <= 0)
                {
                    string DefRC = Path.Combine(Directory.GetCurrentDirectory(), "Runtime/Launch/Resources/Windows/PCLaunch.rc");
                    FileItem Item = FileItem.GetItemByFullPath(DefRC);
                    RCFiles.Add(Item);
                }
            }

            // Throw an error if the module's source file list referenced any non-existent files.
            if (MissingFiles.Count > 0)
            {
                string FileList = "";
                foreach (var MissingFile in MissingFiles)
                {
                    FileList += "\n";
                    FileList += MissingFile.AbsolutePath;
                }
                throw new BuildException(
                    "UBT ERROR: Module \"{0}\" references non-existent files:{1} (perhaps a file was added to the project but not checked in)",
                    Name,
                    FileList
                    );
            }

            // Clear out any references to precompiled header usage for source files..
            foreach (var CPPFile in CPPFiles)
            {
                CPPFile.PCHHeaderNameInCode = null;
                CPPFile.PrecompiledHeaderIncludeFilename = null;
            }

            // Check to see if this is an Engine module (including program or plugin modules).  That is, the module is located under the "Engine" folder
            var IsGameModule = !Utils.IsFileUnderDirectory( this.ModuleDirectory, Path.Combine( ProjectFileGenerator.EngineRelativePath ) );

            // Should we force a precompiled header to be generated for this module?  Usually, we only bother with a
            // precompiled header if there are at least several source files in the module (after combining them for unity
            // builds.)  But for game modules, it can be convenient to always have a precompiled header to single-file
            // changes to code is really quick to compile.
            int MinFilesUsingPrecompiledHeader = BuildConfiguration.MinFilesUsingPrecompiledHeader;
            if( MinFilesUsingPrecompiledHeaderOverride != 0 )
            {
                MinFilesUsingPrecompiledHeader = MinFilesUsingPrecompiledHeaderOverride;
            }
            else if( IsGameModule && BuildConfiguration.bForcePrecompiledHeaderForGameModules )
            {
                // This is a game module with only a small number of source files, so go ahead and force a precompiled header
                // to be generated to make incremental changes to source files as fast as possible for small projects.
                MinFilesUsingPrecompiledHeader = 1;
            }

            // Should we use unity build mode for this module?
            bool bModuleUsesUnityBuild = BuildConfiguration.bUseUnityBuild;
            if( bFasterWithoutUnity )
            {
                bModuleUsesUnityBuild = false;
            }
            else if( !BuildConfiguration.bForceUnityBuild && IsGameModule && CPPFiles != null && CPPFiles.Count < BuildConfiguration.MinGameModuleSourceFilesForUnityBuild )
            {
                // Game modules with only a small number of source files are usually better off having faster iteration times
                // on single source file changes, so we forcibly disable unity build for those modules
                bModuleUsesUnityBuild = false;
            }

            // Precompiled header support.
            bool bWasModuleCodeCompiled = false;
            if (BuildPlatform.ShouldUsePCHFiles(CompileEnvironment.Config.TargetPlatform, CompileEnvironment.Config.TargetConfiguration))
            {
                var PCHTimerStart = DateTime.UtcNow;

                // The code below will figure out whether this module will either use a "unique PCH" (private PCH that will only be included by
                // this module's code files), or a "shared PCH" (potentially included by many code files in many modules.)  Only one or the other
                // will be used.
                FileItem UniquePCHHeaderFile = null;
                FileItem SharedPCHHeaderFile = null;

                // In the case of a shared PCH, we also need to keep track of which module that PCH's header file is a member of
                string SharedPCHModuleName = String.Empty;

                // The precompiled header environment for all source files in this module that use a precompiled header, if we even need one
                PrecompileHeaderEnvironment ModulePCHEnvironment = null;

                bool bDisableSharedPCHFiles = (Binary.Config.bCompileMonolithic && CompileEnvironment.Config.bIsBuildingLibrary);
                if( BuildConfiguration.bUseSharedPCHs && bDisableSharedPCHFiles )
                {
                    Log.TraceVerbose("Module '{0}' was not allowed to use SharedPCHs, because we're compiling to a library in monolithic mode", this.Name );
                }

                bool bUseSharedPCHFiles = BuildConfiguration.bUseSharedPCHs && (bDisableSharedPCHFiles == false);
                bool bIsASharedPCHModule = false;
                if (bUseSharedPCHFiles)
                {
                    foreach( var CurSharedPCHHeaderFile in GlobalCompileEnvironment.SharedPCHHeaderFiles )
                    {
                        if( this == CurSharedPCHHeaderFile.Module )
                        {
                            bIsASharedPCHModule = true;
                            break;
                        }
                    }
                }

                // Map from pch header string to the source files that use that PCH
                var UsageMapPCH = new Dictionary<string, List<FileItem>>( StringComparer.InvariantCultureIgnoreCase );

                // Determine what potential precompiled header is used by each source file.
                double SharedPCHTotalTime = 0.0;
                foreach( var CPPFile in CPPFiles )
                {
                    if (bUseSharedPCHFiles)
                    {
                        var SharedPCHStartTime = DateTime.UtcNow;

                        // When compiling in modular mode, we can't use a shared PCH file when compiling a module
                        // with exports, because the shared PCH can only have imports in it to work correctly.
                        // @todo SharedPCH: If we ever have SharedPCH headers that themselves belong to modules which never use DLL Exports, we can avoid
                        // generating TWO PCH files by checking for that here.  For now, we always assume that SharedPCH headers have exports when
                        // compiling in modular mode.
                        if( bAllowSharedPCH && ( !bIsASharedPCHModule || bCompileMonolithic ) )
                        {
                            // Figure out which shared PCH tier we're in
                            int LargestSharedPCHHeaderFileIndex = -1;
                            {
                                var AllIncludedFiles = ModuleCompileEnvironment.GetIncludeDependencies( CPPFile );
                                foreach( var IncludedFile in AllIncludedFiles )
                                {
                                    // These PCHs are ordered from least complex to most complex.  We'll start at the last one and search backwards.
                                    for( var SharedPCHHeaderFileIndex = GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1; SharedPCHHeaderFileIndex > LargestSharedPCHHeaderFileIndex; --SharedPCHHeaderFileIndex )
                                    {
                                        var CurSharedPCHHeaderFile = GlobalCompileEnvironment.SharedPCHHeaderFiles[ SharedPCHHeaderFileIndex ];
                                        if( IncludedFile == CurSharedPCHHeaderFile.PCHHeaderFile )
                                        {
                                            LargestSharedPCHHeaderFileIndex = SharedPCHHeaderFileIndex;
                                            break;
                                        }
                                    }

                                    if( LargestSharedPCHHeaderFileIndex == GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1)
                                    {
                                        // We've determined that the module is using our most complex PCH header, so we can early-out
                                        break;
                                    }
                                }
                            }

                            if( LargestSharedPCHHeaderFileIndex > -1 )
                            {
                                var LargestIncludedSharedPCHHeaderFile = GlobalCompileEnvironment.SharedPCHHeaderFiles[LargestSharedPCHHeaderFileIndex];
                                if( SharedPCHHeaderFile == null )
                                {
                                    SharedPCHModuleName = LargestIncludedSharedPCHHeaderFile.Module.Name;
                                    SharedPCHHeaderFile = LargestIncludedSharedPCHHeaderFile.PCHHeaderFile;
                                }
                                else
                                {
                                    if( SharedPCHHeaderFile != LargestIncludedSharedPCHHeaderFile.PCHHeaderFile )
                                    {
                                        // @todo UBT perf: It is fairly costly to perform this test, as we could easily early-out after we have SharedPCHHeaderFile and not bother testing the rest of the files in the module.  But this can be useful to find abusive modules that include a shared PCH header in the bowels of a non-PCH private source file.
                                        Console.WriteLine( "WARNING: File '{0}' doesn't use same 'shared' precompiled header as other files in this module: '{1}' vs '{2}'.  This can greatly impact compile times.  Make sure that your module's private PCH header includes the 'largest' shared PCH header that your module uses",
                                            CPPFile.AbsolutePath, SharedPCHHeaderFile, LargestIncludedSharedPCHHeaderFile.PCHHeaderFile );
                                    }
                                }
                            }
                            else
                            {
                                Log.TraceVerbose("File {0} doesn't use a SharedPCH!", CPPFile.AbsolutePath);
                            }

                            SharedPCHTotalTime += ( DateTime.UtcNow - SharedPCHStartTime ).TotalSeconds;
                        }
                        else
                        {
                            Log.TraceVerbose("File '{0}' cannot create or use SharedPCHs, because its module '{1}' needs its own private PCH", CPPFile.AbsolutePath, this.Name);
                        }
                    }

                    {
                        // Find headers used by the source file.
                        List<DependencyInclude> DirectIncludeFilenames = CPPEnvironment.GetDirectIncludeDependencies( CPPFile, ModuleCompileEnvironment.Config.TargetPlatform, ModuleCompileEnvironment.bHackHeaderGenerator );
                        if( BuildConfiguration.bPrintDebugInfo )
                        {
                            var IncludedFileNames = new StringBuilder();
                            foreach( var CurInclude in DirectIncludeFilenames )
                            {
                                if( IncludedFileNames.Length > 0 )
                                {
                                    IncludedFileNames.Append( ", " );
                                }
                                IncludedFileNames.Append( Path.GetFileName( CurInclude.IncludeName ) );
                            }

                            Log.TraceVerbose( "Found direct includes for {0}: {1}", Path.GetFileName( CPPFile.AbsolutePath ), IncludedFileNames );
                        }

                        if( DirectIncludeFilenames.Count > 0 )
                        {
                            // The pch header should always be the first include in the source file.
                            // NOTE: This is not an absolute path.  This is just the literal include string from the source file!
                            CPPFile.PCHHeaderNameInCode = DirectIncludeFilenames[ 0 ].IncludeName;

                            // Resolve the PCH header to an absolute path.
                            // Check NullOrEmpty here because if the file could not be resolved we need to throw an exception
                            if (string.IsNullOrEmpty(DirectIncludeFilenames[0].IncludeResolvedName) ||
                                // ignore any preexisting resolve cache if we are not configured to use it.
                                !BuildConfiguration.bUseIncludeDependencyResolveCache ||
                                // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                                BuildConfiguration.bTestIncludeDependencyResolveCache)
                            {
                                string SourceFilesDirectory = Path.GetDirectoryName(CPPFile.AbsolutePath);
                                // search the include paths to resolve the file.
                                FileItem PrecompiledHeaderIncludeFile = ModuleCompileEnvironment.FindIncludedFile(CPPFile.PCHHeaderNameInCode, !BuildConfiguration.bCheckExternalHeadersForModification, SourceFilesDirectory);
                                if (PrecompiledHeaderIncludeFile != null)
                                {
                                    CPPEnvironment.IncludeDependencyCache.CacheResolvedIncludeFullPath(CPPFile, 0, PrecompiledHeaderIncludeFile.AbsolutePath);
                                    CPPFile.PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFile.AbsolutePath;

                                    if (UniquePCHHeaderFile == null)
                                    {
                                        UniquePCHHeaderFile = PrecompiledHeaderIncludeFile;
                                    }
                                }
                                else
                                {
                                    throw new BuildException("The first include statement in source file '{0}' is trying to include the file '{1}' as the precompiled header for module '{2}', but that file could not be located in any of the module's include search paths.", CPPFile.AbsolutePath, CPPFile.PCHHeaderNameInCode, this.Name);
                                }
                            }
                            else
                            {
                                CPPFile.PrecompiledHeaderIncludeFilename = DirectIncludeFilenames[0].IncludeResolvedName;
                                if (UniquePCHHeaderFile == null)
                                {
                                    UniquePCHHeaderFile = FileItem.GetItemByFullPath(CPPFile.PrecompiledHeaderIncludeFilename);
                                }
                            }
                        }
                    }

                    if( CPPFile.PrecompiledHeaderIncludeFilename == null )
                    {
                        throw new BuildException( "No PCH usage for file \"{0}\" . Missing #include header?", CPPFile.AbsolutePath );
                    }

                    // Create a new entry if not in the pch usage map
                    List<FileItem> PCHSourceFiles = null;
                    if( !UsageMapPCH.TryGetValue( CPPFile.PrecompiledHeaderIncludeFilename, out PCHSourceFiles ) )
                    {
                        PCHSourceFiles = new List<FileItem>();
                        UsageMapPCH.Add( CPPFile.PrecompiledHeaderIncludeFilename, PCHSourceFiles );
                    }
                    PCHSourceFiles.Add( CPPFile );
                }

                if( BuildConfiguration.bPrintDebugInfo )
                {
                    Log.TraceVerbose( "{0} PCH files for module {1}:", UsageMapPCH.Count, Name );
                    int MostFilesIncluded = 0;
                    foreach( var CurPCH in UsageMapPCH )
                    {
                        if( CurPCH.Value.Count > MostFilesIncluded )
                        {
                            MostFilesIncluded = CurPCH.Value.Count;
                        }

                        Log.TraceVerbose("   {0}  ({1} files including it: {2}, ...)", CurPCH.Key, CurPCH.Value.Count, CurPCH.Value[0].AbsolutePath);
                    }
                }

                if( UsageMapPCH.Count > 1 )
                {
                    // Keep track of the PCH file that is most used within this module
                    string MostFilesAreIncludingPCH = string.Empty;
                    int MostFilesIncluded = 0;
                    foreach( var CurPCH in UsageMapPCH )
                    {
                        if( CurPCH.Value.Count > MostFilesIncluded )
                        {
                            MostFilesAreIncludingPCH = CurPCH.Key;
                            MostFilesIncluded = CurPCH.Value.Count;
                        }
                    }

                    // Find all of the files that are not including our "best" PCH header
                    var FilesNotIncludingBestPCH = new StringBuilder();
                    foreach( var CurPCH in UsageMapPCH )
                    {
                        if( CurPCH.Key != MostFilesAreIncludingPCH )
                        {
                            foreach( var SourceFile in CurPCH.Value )
                            {
                                FilesNotIncludingBestPCH.AppendFormat( "{0} (including {1})\n", SourceFile.AbsolutePath, CurPCH.Key );
                            }
                        }
                    }

                    // Bail out and let the user know which source files may need to be fixed up
                    throw new BuildException(
                        "All source files in module \"{0}\" must include the same precompiled header first.  Currently \"{1}\" is included by most of the source files.  The following source files are not including \"{1}\" as their first include:\n\n{2}",
                        Name,
                        MostFilesAreIncludingPCH,
                        FilesNotIncludingBestPCH );
                }

                // If there was one header that was included first by enough C++ files, use it as the precompiled header.
                // Only use precompiled headers for projects with enough files to make the PCH creation worthwhile.
                if( CPPFiles != null &&
                    ( SharedPCHHeaderFile != null || CPPFiles.Count >= MinFilesUsingPrecompiledHeader ) )
                {
                    if( SharedPCHHeaderFile != null )
                    {
                        // Check to see if we have a PCH header already setup that we can use
                        foreach( var SharedPCHEnvironment in GlobalCompileEnvironment.SharedPCHEnvironments )
                        {
                            if( SharedPCHEnvironment.PrecompiledHeaderIncludeFilename == SharedPCHHeaderFile )
                            {
                                // Don't mix CLR modes
                                if( SharedPCHEnvironment.CLRMode == ModuleCompileEnvironment.Config.CLRMode )
                                {
                                    // Don't mix non-optimized code with optimized code (PCHs won't be compatible)
                                    bool bIsDebugBuild = CompileEnvironment.Config.TargetConfiguration == CPPTargetConfiguration.Debug;
                                    var SharedPCHCodeOptimization = SharedPCHEnvironment.OptimizeCode;
                                    if( SharedPCHCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds && !bIsDebugBuild )
                                    {
                                        SharedPCHCodeOptimization = ModuleRules.CodeOptimization.Always;
                                    }
                                    var ModuleCodeOptimization = ModuleCompileEnvironment.Config.OptimizeCode;
                                    if( ModuleCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds && !bIsDebugBuild )
                                    {
                                        ModuleCodeOptimization = ModuleRules.CodeOptimization.Always;
                                    }

                                    if( SharedPCHCodeOptimization.Equals( ModuleCodeOptimization ) )
                                    {
                                        // Found a valid shared PCH header to use!

                                        // @todo SharedPCH: Ideally we would exhaustively check for a compatible compile environment (definitions, imports/exports, etc)
                                        //    Currently, it's possible for the shared PCH to be compiled differently depending on which module UBT happened to have
                                        //    include it first during the build phase.  This could create problems with determinstic builds, or turn up compile
                                        //    errors unexpectedly due to compile environment differences.
                                        ModulePCHEnvironment = SharedPCHEnvironment;
                                        Log.TraceVerbose( "Module " + Name + " uses existing SharedPCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "' (from module " + ModulePCHEnvironment.ModuleName + ")" );

                                        // Update all CPPFiles to point to the shared PCH
                                        foreach( var CPPFile in CPPFiles )
                                        {
                                            CPPFile.PCHHeaderNameInCode = SharedPCHHeaderFile.AbsolutePath;
                                            CPPFile.PrecompiledHeaderIncludeFilename = SharedPCHHeaderFile.AbsolutePath;
                                        }
                                    }
                                    else
                                    {
                                        Log.TraceVerbose( "Module {0} cannot use existing SharedPCH '{1}' (from module '{2}') because optimization levels don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName );
                                        SharedPCHHeaderFile = null;
                                    }
                                }
                                else
                                {
                                    Log.TraceVerbose( "Module {0} cannot use existing SharedPCH '{1}' (from module '{2}') because CLR modes don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName );
                                    SharedPCHHeaderFile = null;
                                }
                                break;
                            }
                        }
                    }

                    // A shared PCH was not already set up for us, so set one up.
                    if( ModulePCHEnvironment == null )
                    {
                        var PCHHeaderFile = UniquePCHHeaderFile;
                        var PCHModuleName = this.Name;
                        if( SharedPCHHeaderFile != null )
                        {
                            PCHHeaderFile = SharedPCHHeaderFile;
                            PCHModuleName = SharedPCHModuleName;
                        }
                        var PCHHeaderNameInCode = CPPFiles[ 0 ].PCHHeaderNameInCode;

                        ModulePCHEnvironment = new PrecompileHeaderEnvironment( PCHModuleName, PCHHeaderNameInCode, PCHHeaderFile, ModuleCompileEnvironment.Config.CLRMode, ModuleCompileEnvironment.Config.OptimizeCode );

                        Log.TraceVerbose( "PCH file \"{0}\" generated for module \"{1}\" .", PCHHeaderFile.AbsolutePath, Name );

                        if( SharedPCHHeaderFile != null )
                        {
                            // Add to list of shared PCH environments
                            GlobalCompileEnvironment.SharedPCHEnvironments.Add( ModulePCHEnvironment );
                            Log.TraceVerbose( "Module " + Name + " uses new SharedPCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'" );
                        }
                        else
                        {
                            Log.TraceVerbose( "Module " + Name + " uses a unique PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'" );
                        }
                    }
                }

                // Compile the C++ source or the unity C++ files that use a PCH environment.
                if( ModulePCHEnvironment != null )
                {
                    // Setup a new compile environment for this module's source files.  It's pretty much the exact same as the
                    // module's compile environment, except that it will include a PCH file.
                    var ModulePCHCompileEnvironment = new CPPEnvironment( ModuleCompileEnvironment );
                    {
                        ModulePCHCompileEnvironment.Config.PrecompiledHeaderAction = PrecompiledHeaderAction.Include;
                        ModulePCHCompileEnvironment.Config.PrecompiledHeaderIncludeFilename = ModulePCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath;
                        ModulePCHCompileEnvironment.Config.PCHHeaderNameInCode = ModulePCHEnvironment.PCHHeaderNameInCode;

                        if( SharedPCHHeaderFile != null )
                        {
                            // Shared PCH headers need to be force included, because we're basically forcing the module to use
                            // the precompiled header that we want, instead of the "first include" in each respective .cpp file
                            ModulePCHCompileEnvironment.Config.bForceIncludePrecompiledHeader = true;
                        }
                    }

                    var CPPFilesToBuild = CPPFiles;
                    if (bModuleUsesUnityBuild)
                    {
                        // unity files generated for only the set of files which share the same PCH environment
                        CPPFilesToBuild = Unity.GenerateUnityCPPs( CPPFilesToBuild, ModulePCHCompileEnvironment, Name );
                    }

                    // Check if there are enough unity files to warrant pch generation (and we haven't already generated the shared one)
                    if( ModulePCHEnvironment.PrecompiledHeaderFile == null &&
                        ( SharedPCHHeaderFile != null || CPPFilesToBuild.Count >= MinFilesUsingPrecompiledHeader ) )
                    {
                        bool bAllowDLLExports = true;
                        var PCHOutputDirectory = ModuleCompileEnvironment.Config.OutputDirectory;
                        var PCHModuleName = this.Name;

                        if( SharedPCHHeaderFile != null )
                        {
                            // Disallow DLLExports when generating shared PCHs.  These headers aren't able to export anything, because they're potentially shared between many modules.
                            bAllowDLLExports = false;

                            // Save shared PCHs to a specific folder
                            PCHOutputDirectory = Path.Combine( CompileEnvironment.Config.OutputDirectory, "SharedPCHs" );

                            // Use a fake module name for "shared" PCHs.  It may be used by many modules, so we don't want to use this module's name.
                            PCHModuleName = "Shared";
                        }

                        var PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction(
                            CPPFilesToBuild[0].PCHHeaderNameInCode,
                            ModulePCHEnvironment.PrecompiledHeaderIncludeFilename,
                            ModuleCompileEnvironment,
                            PCHOutputDirectory,
                            PCHModuleName,
                            bAllowDLLExports );
                        ModulePCHEnvironment.PrecompiledHeaderFile = PCHOutput.PrecompiledHeaderFile;

                        ModulePCHEnvironment.OutputObjectFiles.Clear();
                        ModulePCHEnvironment.OutputObjectFiles.AddRange( PCHOutput.ObjectFiles );
                    }

                    if( ModulePCHEnvironment.PrecompiledHeaderFile != null )
                    {
                        // Link in the object files produced by creating the precompiled header.
                        LinkInputFiles.AddRange( ModulePCHEnvironment.OutputObjectFiles );

                        // if pch action was generated for the environment then use pch
                        ModulePCHCompileEnvironment.PrecompiledHeaderFile = ModulePCHEnvironment.PrecompiledHeaderFile;
                        LinkInputFiles.AddRange( ModulePCHCompileEnvironment.CompileFiles( CPPFilesToBuild, Name ).ObjectFiles );
                    }
                    else
                    {
                        // otherwise, compile non-pch
                        LinkInputFiles.AddRange( ModuleCompileEnvironment.CompileFiles( CPPFilesToBuild, Name ).ObjectFiles );
                    }

                    bWasModuleCodeCompiled = true;
                }

                if( BuildConfiguration.bPrintPerformanceInfo )
                {
                var TotalPCHTime = DateTime.UtcNow - PCHTimerStart;
                    Trace.TraceInformation( "PCH time for " + Name + " is " + TotalPCHTime.TotalSeconds + "s (shared PCHs: " + SharedPCHTotalTime + "s)" );
                }
            }

            if( !bWasModuleCodeCompiled )
            {
                if( CPPFiles.Count > 0 )
                {
                    var CPPFilesToCompile = CPPFiles;
                    if (bModuleUsesUnityBuild)
                    {
                        CPPFilesToCompile = Unity.GenerateUnityCPPs( CPPFilesToCompile, ModuleCompileEnvironment, Name );
                    }
                    LinkInputFiles.AddRange( ModuleCompileEnvironment.CompileFiles( CPPFilesToCompile, Name ).ObjectFiles );
                }
            }

            // Compile C files directly.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileFiles(CFiles, Name).ObjectFiles);

            // Compile CC files directly.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileFiles(CCFiles, Name).ObjectFiles);

            // Compile MM files directly.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileFiles(MMFiles, Name).ObjectFiles);

            // If we're building Rocket, generate a static library for this module
            if(RedistStaticLibraryPath != null)
            {
                // Create a link environment for it
                LinkEnvironment RedistLinkEnvironment = new LinkEnvironment();
                RedistLinkEnvironment.InputFiles.AddRange(LinkInputFiles);
                RedistLinkEnvironment.Config.TargetArchitecture = CompileEnvironment.Config.TargetArchitecture;
                RedistLinkEnvironment.Config.TargetConfiguration = CompileEnvironment.Config.TargetConfiguration;
                RedistLinkEnvironment.Config.TargetPlatform = CompileEnvironment.Config.TargetPlatform;
                RedistLinkEnvironment.Config.bIsBuildingDLL = false;
                RedistLinkEnvironment.Config.bIsBuildingLibrary = true;
                RedistLinkEnvironment.Config.IntermediateDirectory = Binary.Config.IntermediateDirectory;
                RedistLinkEnvironment.Config.OutputFilePath = RedistStaticLibraryPath;

                // Replace the items built so far with the library
                FileItem RedistLibrary = RedistLinkEnvironment.LinkExecutable(false);
                LinkInputFiles.Clear();
            }

            // Compile RC files.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileRCFiles(RCFiles).ObjectFiles);

            // Keep track of this module's public and private UObject source files, so that we can pass those off to UHT if needed
            {
                string ModuleSourceFolder = Path.GetFullPath( this.ModuleDirectory );
                var ModuleClassesSourceFolder = Path.Combine( ModuleSourceFolder, "Classes" );	// @todo uht: Want to deprecate this eventually
                foreach( var SourceFile in SourceFiles )
                {
                    // Will always be a cache hit (we did this earlier during Compile())
                    var IncludedFiles = ModuleCompileEnvironment.GetIncludeDependencies( SourceFile );

                    // Also check for intrinsic classes like "Object.h", which are special cases because they are never included in compiled code and exist only for UHT to parse
                    {
                        // Runtime/CoreUObject/Classes/Object.h
                        {
                            var IntrinsicFileItem = FileItem.GetExistingItemByPath( Path.Combine( ProjectFileGenerator.EngineRelativePath, "Source", "Runtime", Path.Combine( "CoreUObject", "Classes", "Object.h" ) ) );	// @todo uht: In Classes folder right now
                            if( !IntrinsicFileItem.bExists )
                            {
                                throw new BuildException( "Expecting " + IntrinsicFileItem.AbsolutePath + " to exist" );
                            }
                            IntrinsicFileItem.HasUObjects = true;
                            IncludedFiles.Add( IntrinsicFileItem );
                        }

                        // Runtime/Engine/Classes/Model.h
                        {
                            var IntrinsicFileItem = FileItem.GetExistingItemByPath( Path.Combine( ProjectFileGenerator.EngineRelativePath, "Source", "Runtime", Path.Combine( "Engine", "Classes", "Intrinsic", "Model.h" ) ) );	// @todo uht: In Classes folder right now
                            if( !IntrinsicFileItem.bExists )
                            {
                                throw new BuildException( "Expecting " + IntrinsicFileItem.AbsolutePath + " to exist" );
                            }
                            IntrinsicFileItem.HasUObjects = true;
                            IncludedFiles.Add( IntrinsicFileItem );
                        }
                    }

                    // @todo uht: Could check SourceFile.HasUObjects if we want to include .cpps with USTRUCT/UCLASSES here
                    foreach( var IncludedFile in IncludedFiles )
                    {
                        if( IncludedFile.HasUObjects )
                        {
                            if( IncludedFile.AbsolutePath.StartsWith( ModuleSourceFolder + Path.DirectorySeparatorChar ) )
                            {
                                // Is it private or public?
                                bool bIsPublic = false;
                                {
                                    // Get the part of the path that is relative to the module source folder
                                    var RelativeSourceFilePath = IncludedFile.AbsolutePath.Substring( ModuleSourceFolder.Length + 1 );
                                    if( RelativeSourceFilePath.StartsWith( "Classes" + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase ) )
                                    {
                                        // Code files under the legacy 'Classes' directory are always considered public
                                        bIsPublic = true;
                                    }
                                    else if( RelativeSourceFilePath.StartsWith( "Public" + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase ) ||
                                             ( RelativeSourceFilePath.IndexOf( Path.DirectorySeparatorChar + "Public" + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase ) != -1 ) )
                                    {
                                        // Code is under a 'Public' subdirectory somewhere in the hierarchy
                                        bIsPublic = true;
                                    }
                                }

                                if( bIsPublic )
                                {
                                    PublicUObjectHeaders.Add( IncludedFile );
                                }
                                else
                                {
                                    PrivateUObjectHeaders.Add( IncludedFile );
                                }
                            }
                            else
                            {
                                // Not from this module, so we don't need to worry about UObjects
                            }
                        }
                    }

                }
            }

            return LinkInputFiles;
        }
Exemplo n.º 7
0
        public override CPPOutput CompileCPPFiles(CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
        {
            if (!bHasPrintedApiLevel)
            {
                Console.WriteLine("Compiling with NDK API '{0}'", GetNdkApiLevel());
                bHasPrintedApiLevel = true;
            }

            string Arguments = GetCLArguments_Global(CompileEnvironment);
            string PCHArguments = "";

            if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create)
            {
                Arguments += " -Werror";

            }
            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}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(".gch", ""));
            }

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.SystemIncludePaths)
            {
                Arguments += string.Format(" -I\"{0}\"", IncludePath);
            }
            foreach (string IncludePath in CompileEnvironment.Config.IncludePaths)
            {
                // we make this absolute because there are some edge cases when a code-based rocket project on the same dtive
                // as the engine will make relative paths that make clang fail to compile. Absolute will succeeed.
                Arguments += string.Format(" -I\"{0}\"", Path.GetFullPath(IncludePath));
            }

            // 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)
            {
                Arguments += string.Format(" -D \"{0}\"", Definition);
            }

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

                // 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.TargetConfiguration != CPPTargetConfiguration.Debug)
                {
                    Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath);
                }

                bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.TargetConfiguration == 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.
                CompileAction.PrerequisiteItems.Add(SourceFile);
                foreach (FileItem IncludedFile in CompileEnvironment.GetIncludeDependencies(SourceFile))
                {
                    CompileAction.PrerequisiteItems.Add(IncludedFile);
                }

                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(SourceFile.AbsolutePath) + ".gch"
                            )
                        );

                    CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
                    Result.PrecompiledHeaderFile = PrecompiledHeaderFile;

                    // Add the parameters needed to compile the precompiled header file to the command-line.
                    FileArguments += string.Format(" -o \"{0}\"", PrecompiledHeaderFile.AbsolutePath, false);
                }
                else
                {
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        CompileAction.bIsUsingPCH = true;
                        CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile);
                    }

                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ".o"
                            )
                        );
                    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}", Path.GetFileName(SourceFile.AbsolutePath));
                CompileAction.StatusDetailedDescription = SourceFile.Description;

                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;
        }