/// <summary>
        /// Validates the configuration. E.g. some options are mutually exclusive whereof some imply others. Also
        /// some functionality is not available on all platforms.
        /// @warning: the order of validation is important
        /// </summary>
        /// <param name="Configuration">Current configuration (e.g. development, debug, ...)</param>
        /// <param name="Platform">Current platform (e.g. Win32, PS3, ...)</param>
        /// <param name="bCreateDebugInfo">True if debug info should be created</param>
        public static void ValidateConfiguration(CPPTargetConfiguration Configuration, CPPTargetPlatform Platform, bool bCreateDebugInfo)
        {
            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(Platform);

            // E&C support.
            if (bSupportEditAndContinue)
            {
                bUseIncrementalLinking = BuildPlatform.ShouldUseIncrementalLinking(Platform, Configuration);
            }

            // Incremental linking.
            if (bUseIncrementalLinking)
            {
                bUsePDBFiles = BuildPlatform.ShouldUsePDBFiles(Platform, Configuration, bCreateDebugInfo);
            }

            // Detailed stats
            if (bLogDetailedActionStats && bAllowXGE)
            {
                // Some build machines apparently have this turned on, so if you really want detailed stats, don't run with XGE
                bLogDetailedActionStats = false;
            }

            // PDB
            if (bUsePDBFiles)
            {
                // NOTE: Currently we allow XGE to run, even with PDBs, until we notice an issue with this
                bool bDisallowXGEWithPDBFiles = false;
                if (bDisallowXGEWithPDBFiles)
                {
                    // Force local execution as we have one PDB for all files using the same PCH. This currently doesn't
                    // scale well with XGE due to required networking bandwidth. Xoreax mentioned that this was going to
                    // be fixed in a future version of the software.
                    bAllowXGE = false;
                }
            }

            // Allow for the build platform to perform custom validation here...
            // NOTE: This CAN modify the static BuildConfiguration settings!!!!
            BuildPlatform.ValidateBuildConfiguration(Configuration, Platform, bCreateDebugInfo);

            if (!BuildPlatform.CanUseXGE())
            {
                bAllowXGE = false;
            }

            if (!BuildPlatform.CanUseDistcc())
            {
                bAllowDistcc = false;
            }

            if (!BuildPlatform.CanUseSNDBS())
            {
                bAllowSNDBS = false;
            }
        }
Esempio n. 2
0
        public FileItem CachePCHUsageForCPPFile(FileItem CPPFile, CppIncludePaths IncludePaths, CppPlatform Platform)
        {
            // @todo ubtmake: We don't really need to scan every file looking for PCH headers, just need one.  The rest is just for error checking.
            // @todo ubtmake: We don't need all of the direct includes either.  We just need the first, unless we want to check for errors.
            List <DependencyInclude> DirectIncludeFilenames = GetDirectIncludeDependencies(CPPFile, bOnlyCachedDependencies: false);

            if (UnrealBuildTool.bPrintDebugInfo)
            {
                Log.TraceVerbose("Found direct includes for {0}: {1}", Path.GetFileName(CPPFile.AbsolutePath), string.Join(", ", DirectIncludeFilenames.Select(F => F.IncludeName)));
            }

            if (DirectIncludeFilenames.Count == 0)
            {
                return(null);
            }

            DependencyInclude FirstInclude = DirectIncludeFilenames[0];

            // 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 (FirstInclude.IncludeResolvedNameIfSuccessful != null &&
                // ignore any preexisting resolve cache if we are not configured to use it.
                bUseIncludeDependencyResolveCache &&
                // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                !bTestIncludeDependencyResolveCache)
            {
                CPPFile.PrecompiledHeaderIncludeFilename = FirstInclude.IncludeResolvedNameIfSuccessful;
                return(FileItem.GetItemByFileReference(CPPFile.PrecompiledHeaderIncludeFilename));
            }

            // search the include paths to resolve the file.
            string          FirstIncludeName = FirstInclude.IncludeName;
            UEBuildPlatform BuildPlatform    = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(Platform);

            // convert back from relative to host path if needed
            if (!BuildPlatform.UseAbsolutePathsInUnityFiles())
            {
                FirstIncludeName = RemoteExports.UnconvertPath(FirstIncludeName);
            }

            FileItem PrecompiledHeaderIncludeFile = CPPHeaders.FindIncludedFile(CPPFile.Reference, FirstIncludeName, IncludePaths);

            if (PrecompiledHeaderIncludeFile == null)
            {
                FirstIncludeName = RemoteExports.UnconvertPath(FirstInclude.IncludeName);
                throw new BuildException("The first include statement in source file '{0}' is trying to include the file '{1}' as the precompiled header, but that file could not be located in any of the module's include search paths.", CPPFile.AbsolutePath, FirstIncludeName);
            }

            IncludeDependencyCache.CacheResolvedIncludeFullPath(CPPFile, 0, PrecompiledHeaderIncludeFile.Reference, bUseIncludeDependencyResolveCache, bTestIncludeDependencyResolveCache);
            CPPFile.PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFile.Reference;

            return(PrecompiledHeaderIncludeFile);
        }
Esempio n. 3
0
        public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List <FileItem> RCFiles)
        {
            var EnvVars = VCEnvironment.SetEnvironment(Environment.Config.Target.Platform, false);

            CPPOutput Result = new CPPOutput();

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

            foreach (FileItem RCFile in RCFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                CompileAction.CommandDescription = "Resource";
                CompileAction.WorkingDirectory   = UnrealBuildTool.EngineSourceDirectory.FullName;
                CompileAction.CommandPath        = EnvVars.ResourceCompilerPath;
                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.
                CompileAction.CommandArguments += " /D_WIN64";

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

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

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

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

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

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

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

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

            StringBuilder Arguments = new StringBuilder();

            AppendCLArguments_Global(CompileEnvironment, EnvVars, Arguments);

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
            {
                string IncludePathRelative = Utils.CleanDirectorySeparators(Utils.MakePathRelativeTo(IncludePath, Path.Combine(ProjectFileGenerator.RootRelativePath, "Engine/Source")), '/');
                Arguments.AppendFormat(" /I \"{0}\"", IncludePathRelative);
            }
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
            {
                string IncludePathRelative = Utils.CleanDirectorySeparators(Utils.MakePathRelativeTo(IncludePath, Path.Combine(ProjectFileGenerator.RootRelativePath, "Engine/Source")), '/');
                Arguments.AppendFormat(" /I \"{0}\"", IncludePathRelative);
            }


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

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

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


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

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

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                CompileAction.CommandDescription = "Compile";

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

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

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

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

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

                    var PrecompiledFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.UWP).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
                    // Add the precompiled header file to the produced items list.
                    FileItem PrecompiledHeaderFile = FileItem.GetItemByFileReference(
                        FileReference.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + PrecompiledFileExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
                    Result.PrecompiledHeaderFile = PrecompiledHeaderFile;

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

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

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

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

                        FileArguments.AppendFormat(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                        FileArguments.AppendFormat(" /Fp\"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath);

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

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

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

                if (bEmitsObjectFile)
                {
                    var ObjectFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.UWP).GetBinaryExtension(UEBuildBinaryType.Object);
                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByFileReference(
                        FileReference.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(ObjectFile);
                    Result.ObjectFiles.Add(ObjectFile);
                    FileArguments.AppendFormat(" /Fo\"{0}\"", ObjectFile.AbsolutePath);
                }

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

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

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

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

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

                CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
                CompileAction.CommandPath      = EnvVars.CompilerPath;
                CompileAction.CommandArguments = Arguments.ToString() + FileArguments.ToString() + CompileEnvironment.Config.AdditionalArguments;

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

                // 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);
        }
Esempio n. 5
0
        /// <summary>
        /// Given a set of C++ files, generates another set of C++ files that #include all the original
        /// files, the goal being to compile the same code in fewer translation units.
        /// The "unity" files are written to the CompileEnvironment's OutputDirectory.
        /// </summary>
        /// <param name="Target">The target we're building</param>
        /// <param name="CPPFiles">The C++ files to #include.</param>
        /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param>
        /// <param name="BaseName">Base name to use for the Unity files</param>
        /// <returns>The "unity" C++ files.</returns>
        public static List <FileItem> GenerateUnityCPPs(
            UEBuildTarget Target,
            List <FileItem> CPPFiles,
            CPPEnvironment CompileEnvironment,
            string BaseName
            )
        {
            var ToolChain = UEToolChain.GetPlatformToolChain(CompileEnvironment.Config.Target.Platform);

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

            // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not.
            long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Info.Length);

            // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This
            // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X
            // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file.
            //
            // Optimization only makes sense if PCH files are enabled.
            bool bForceIntoSingleUnityFile = BuildConfiguration.bStressTestUnity || (TotalBytesInCPPFiles < BuildConfiguration.NumIncludedBytesPerUnityCPP * 2 && CompileEnvironment.ShouldUsePCHs());

            // Build the list of unity files.
            List <FileCollection> AllUnityFiles;
            {
                var CPPUnityFileBuilder = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : BuildConfiguration.NumIncludedBytesPerUnityCPP);
                foreach (var CPPFile in CPPFiles)
                {
                    if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.Contains(".GeneratedWrapper."))
                    {
                        CPPUnityFileBuilder.EndCurrentUnityFile();
                        CPPUnityFileBuilder.AddFile(CPPFile);
                        CPPUnityFileBuilder.EndCurrentUnityFile();
                    }
                    else
                    {
                        CPPUnityFileBuilder.AddFile(CPPFile);
                    }

                    // Now that the CPPFile is part of this unity file, we will no longer need to treat it like a root level prerequisite for our
                    // dependency cache, as it is now an "indirect include" from the unity file.  We'll clear out the compile environment
                    // attached to this file.  This prevents us from having to cache all of the indirect includes from these files inside our
                    // dependency cache, which speeds up iterative builds a lot!
                    CPPFile.CachedCPPIncludeInfo = null;
                }
                AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles();
            }

            //THIS CHANGE WAS MADE TO FIX THE BUILD IN OUR BRANCH
            //DO NOT MERGE THIS BACK TO MAIN
            string PCHHeaderNameInCode = CPPFiles.Count > 0 ? CPPFiles[0].PCHHeaderNameInCode : "";

            if (CompileEnvironment.Config.PrecompiledHeaderIncludeFilename != null)
            {
                PCHHeaderNameInCode = ToolChain.ConvertPath(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);

                // Generated unity .cpp files always include the PCH using an absolute path, so we need to update
                // our compile environment's PCH header name to use this instead of the text it pulled from the original
                // C++ source files
                CompileEnvironment.Config.PCHHeaderNameInCode = PCHHeaderNameInCode;
            }

            // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding
            // actions to compile them.
            int CurrentUnityFileCount = 0;
            var UnityCPPFiles         = new List <FileItem>();

            foreach (var UnityFile in AllUnityFiles)
            {
                ++CurrentUnityFileCount;

                StringWriter OutputUnityCPPWriter      = new StringWriter();
                StringWriter OutputUnityCPPWriterExtra = null;

                // add an extra file for UBT to get the #include dependencies from
                if (BuildPlatform.RequiresExtraUnityCPPWriter() == true)
                {
                    OutputUnityCPPWriterExtra = new StringWriter();
                }

                OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files.");

                // Explicitly include the precompiled header first, since Visual C++ expects the first top-level #include to be the header file
                // that was used to create the PCH.
                if (CompileEnvironment.Config.PrecompiledHeaderIncludeFilename != null)
                {
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", PCHHeaderNameInCode);
                    if (OutputUnityCPPWriterExtra != null)
                    {
                        OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", PCHHeaderNameInCode);
                    }
                }

                // Add source files to the unity file
                foreach (var CPPFile in UnityFile.Files)
                {
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", ToolChain.ConvertPath(CPPFile.AbsolutePath));
                    if (OutputUnityCPPWriterExtra != null)
                    {
                        OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath);
                    }
                }

                // Determine unity file path name
                string UnityCPPFilePath;
                if (AllUnityFiles.Count > 1)
                {
                    UnityCPPFilePath = string.Format("Module.{0}.{1}_of_{2}.cpp", BaseName, CurrentUnityFileCount, AllUnityFiles.Count);
                }
                else
                {
                    UnityCPPFilePath = string.Format("Module.{0}.cpp", BaseName);
                }
                UnityCPPFilePath = Path.Combine(CompileEnvironment.Config.OutputDirectory, UnityCPPFilePath);

                // Write the unity file to the intermediate folder.
                FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString());
                if (OutputUnityCPPWriterExtra != null)
                {
                    FileItem.CreateIntermediateTextFile(UnityCPPFilePath + ".ex", OutputUnityCPPWriterExtra.ToString());
                }

                UnityCPPFile.RelativeCost        = UnityFile.TotalLength;
                UnityCPPFile.PCHHeaderNameInCode = PCHHeaderNameInCode;
                UnityCPPFiles.Add(UnityCPPFile);

                // Cache information about the unity .cpp dependencies
                // @todo ubtmake urgent: Fails when building remotely for Mac because unity .cpp has an include for a PCH on the REMOTE machine
                UEBuildModuleCPP.CachePCHUsageForModuleSourceFile(Target, CompileEnvironment, UnityCPPFile);
            }

            return(UnityCPPFiles);
        }
		public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
		{
			if (Arches.Count == 0)
			{
				throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build");
			}

			if (!bHasPrintedApiLevel)
			{
				Console.WriteLine("Compiling Native code with NDK API '{0}'", GetNdkApiLevel());
				bHasPrintedApiLevel = true;
			}

			string BaseArguments = "";

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

			}

			// Directly added NDK files for NDK extensions
			ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName);

			// Deal with dynamic modules removed by architecture
			GenerateEmptyLinkFunctionsForRemovedModules(SourceFiles, ModuleName, CompileEnvironment.Config.OutputDirectory);

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

			var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);
			var NDKRoot = Environment.GetEnvironmentVariable("NDKROOT").Replace("\\", "/");

			string BasePCHName = "";
			var PCHExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
			if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
			{
				BasePCHName = RemoveArchName(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath).Replace(PCHExtension, "");
			}

			// Create a compile action for each source file.
			CPPOutput Result = new CPPOutput();
			foreach (string Arch in Arches)
			{
				if (ShouldSkipModule(ModuleName, Arch))
				{
					continue;
				}

				foreach (string GPUArchitecture in GPUArchitectures)
				{
					// which toolchain to use
					string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments;

					switch (Arch)
					{
						case "-armv7": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break;
						case "-arm64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_ARM64=1"; break;
						case "-x86": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_X86=1"; break;
						case "-x64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_X64=1"; break;
						default: Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break;
					}

                    if (GPUArchitecture == "-esdeferred")
					{
						Arguments += " -DPLATFORM_ANDROIDESDEFERRED=1";
					}

					// which PCH file to include
					string PCHArguments = "";
					if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
					{
						// Add the precompiled header file's path to the include path so Clang can find it.
						// This needs to be before the other include paths to ensure Clang uses it instead of the source header file.
						PCHArguments += string.Format(" -include \"{0}\"", InlineArchName(BasePCHName, Arch, GPUArchitecture));
					}

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

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

						// should we disable optimizations on this file?
						// @todo android - We wouldn't need this if we could disable optimizations per function (via pragma)
						bool bDisableOptimizations = false;// SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1;
						if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
						{
							Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath);
						}

						bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug;

						// Add C or C++ specific compiler arguments.
						if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
						{
							FileArguments += GetCompileArguments_PCH(bDisableOptimizations);
						}
						else if (bIsPlainCFile)
						{
							FileArguments += GetCompileArguments_C(bDisableOptimizations);

							// remove shadow variable warnings for NDK files
							if (SourceFile.AbsolutePath.Replace("\\", "/").StartsWith(NDKRoot))
							{
								bDisableShadowWarning = true;
							}
						}
						else
						{
							FileArguments += GetCompileArguments_CPP(bDisableOptimizations);

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

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

						if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
						{
							// Add the precompiled header file to the produced item list.
							FileItem PrecompiledHeaderFile = FileItem.GetItemByFileReference(
								FileReference.Combine(
									CompileEnvironment.Config.OutputDirectory,
									Path.GetFileName(InlineArchName(SourceFile.AbsolutePath, Arch, GPUArchitecture) + PCHExtension)
									)
								);

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

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

							var ObjectFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.Object);

							// Add the object file to the produced item list.
							FileItem ObjectFile = FileItem.GetItemByFileReference(
								FileReference.Combine(
									CompileEnvironment.Config.OutputDirectory,
									InlineArchName(Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension, Arch, GPUArchitecture)
									)
								);
							CompileAction.ProducedItems.Add(ObjectFile);
							Result.ObjectFiles.Add(ObjectFile);

							FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false);
						}

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

						// Build a full argument list
						string AllArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
						AllArguments = ActionThread.ExpandEnvironmentVariables(AllArguments);
						AllArguments = AllArguments.Replace("\\", "/");

						// Remove shadow warning for this file if requested
						if (bDisableShadowWarning)
						{
							int WarningIndex = AllArguments.IndexOf(" -Wshadow");
							if (WarningIndex > 0)
							{
								AllArguments = AllArguments.Remove(WarningIndex, 9);
							}
						}

						// Create the response file
						FileReference ResponseFileName = CompileAction.ProducedItems[0].Reference + "_" + AllArguments.GetHashCode().ToString("X") + ".response";
						string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List<string> { AllArguments }).FullName);

						CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
						CompileAction.CommandPath = ClangPath;
						CompileAction.CommandArguments = ResponseArgument;
						CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", ""));

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

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

			return Result;
		}
 /**
  * Whether to use PCH files with the current target
  *
  * @return	true if PCH files should be used, false otherwise
  */
 public bool ShouldUsePCHs()
 {
     return(UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(Config.Target.Platform).ShouldUsePCHFiles(Config.Target.Platform, Config.Target.Configuration));
 }
Esempio n. 8
0
        /// <summary>
        /// Given a set of C++ files, generates another set of C++ files that #include all the original
        /// files, the goal being to compile the same code in fewer translation units.
        /// The "unity" files are written to the CompileEnvironment's OutputDirectory.
        /// </summary>
        /// <param name="Target">The target we're building</param>
        /// <param name="CPPFiles">The C++ files to #include.</param>
        /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param>
        /// <param name="BaseName">Base name to use for the Unity files</param>
        /// <returns>The "unity" C++ files.</returns>
        public static List <FileItem> GenerateUnityCPPs(
            UEToolChain ToolChain,
            UEBuildTarget Target,
            List <FileItem> CPPFiles,
            CPPEnvironment CompileEnvironment,
            string BaseName
            )
        {
            List <FileItem> NewCPPFiles = new List <FileItem>();

            UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Platform);

            // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not.
            long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Info.Length);

            // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This
            // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X
            // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file.


            // When enabled, UnrealBuildTool will try to determine source files that you are actively iteratively changing, and break those files
            // out of their unity blobs so that you can compile them as individual translation units, much faster than recompiling the entire
            // unity blob each time.
            bool bUseAdaptiveUnityBuild = BuildConfiguration.bUseAdaptiveUnityBuild && !BuildConfiguration.bStressTestUnity;

            // Optimization only makes sense if PCH files are enabled.
            bool bForceIntoSingleUnityFile = BuildConfiguration.bStressTestUnity || (TotalBytesInCPPFiles < BuildConfiguration.NumIncludedBytesPerUnityCPP * 2 && CompileEnvironment.ShouldUsePCHs());

            // Build the list of unity files.
            List <FileCollection> AllUnityFiles;
            {
                // Sort the incoming file paths alphabetically, so there will be consistency in unity blobs across multiple machines.
                // Note that we're relying on this not only sorting files within each directory, but also the directories
                // themselves, so the whole list of file paths is the same across computers.
                List <FileItem> SortedCPPFiles = CPPFiles.GetRange(0, CPPFiles.Count);
                {
                    // Case-insensitive file path compare, because you never know what is going on with local file systems
                    Comparison <FileItem> FileItemComparer = (FileA, FileB) => { return(FileA.AbsolutePath.ToLowerInvariant().CompareTo(FileB.AbsolutePath.ToLowerInvariant())); };
                    SortedCPPFiles.Sort(FileItemComparer);
                }


                // Figure out whether we REALLY want to use adaptive unity for this module.  If nearly every file in the module appears in the working
                // set, we'll just go ahead and let unity build do its thing.
                if (bUseAdaptiveUnityBuild)
                {
                    int CandidateWorkingSetSourceFileCount = 0;
                    int WorkingSetSourceFileCount          = 0;
                    foreach (FileItem CPPFile in SortedCPPFiles)
                    {
                        // Don't include writable source files into unity blobs
                        if (!CPPFile.Reference.IsUnderDirectory(Target.EngineIntermediateDirectory) &&
                            !CPPFile.Reference.IsUnderDirectory(Target.ProjectIntermediateDirectory))
                        {
                            ++CandidateWorkingSetSourceFileCount;

                            if (UnrealBuildTool.ShouldSourceFileBePartOfWorkingSet(CPPFile.AbsolutePath))
                            {
                                ++WorkingSetSourceFileCount;

                                // Mark this file as part of the working set.  This will be saved into the UBT Makefile so that
                                // the assembler can automatically invalidate the Makefile when the working set changes (allowing this
                                // code to run again, to build up new unity blobs.)
                                SourceFileWorkingSet.Add(CPPFile);
                            }
                        }
                    }

                    if (WorkingSetSourceFileCount >= CandidateWorkingSetSourceFileCount)
                    {
                        // Every single file in the module appears in the working set, so don't bother using adaptive unity for this
                        // module.  Otherwise it would make full builds really slow.
                        bUseAdaptiveUnityBuild = false;
                    }
                }

                UnityFileBuilder CPPUnityFileBuilder          = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : BuildConfiguration.NumIncludedBytesPerUnityCPP);
                StringBuilder    AdaptiveUnityBuildInfoString = new StringBuilder();
                foreach (FileItem CPPFile in SortedCPPFiles)
                {
                    if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.IndexOf(".GeneratedWrapper.", StringComparison.InvariantCultureIgnoreCase) != -1)
                    {
                        NewCPPFiles.Add(CPPFile);
                    }

                    // When adaptive unity is enabled, go ahead and exclude any source files that we're actively working with
                    if (bUseAdaptiveUnityBuild && SourceFileWorkingSet.Contains(CPPFile))
                    {
                        // Just compile this file normally, not as part of the unity blob
                        NewCPPFiles.Add(CPPFile);

                        // Let the unity file builder know about the file, so that we can retain the existing size of the unity blobs.
                        // This won't actually make the source file part of the unity blob, but it will keep track of how big the
                        // file is so that other existing unity blobs from the same module won't be invalidated.  This prevents much
                        // longer compile times the first time you build after your working file set changes.
                        CPPUnityFileBuilder.AddVirtualFile(CPPFile);

                        string CPPFileName = Path.GetFileName(CPPFile.AbsolutePath);
                        if (AdaptiveUnityBuildInfoString.Length == 0)
                        {
                            AdaptiveUnityBuildInfoString.Append(String.Format("[Adaptive unity build] Excluded from {0} unity file: {1}", BaseName, CPPFileName));
                        }
                        else
                        {
                            AdaptiveUnityBuildInfoString.Append(", " + CPPFileName);
                        }
                    }

                    else
                    {
                        // If adaptive unity build is enabled for this module, add this source file to the set that will invalidate the makefile
                        if (bUseAdaptiveUnityBuild)
                        {
                            CandidateSourceFilesForWorkingSet.Add(CPPFile);
                        }

                        // Compile this file as part of the unity blob
                        CPPUnityFileBuilder.AddFile(CPPFile);

                        // Now that the CPPFile is part of this unity file, we will no longer need to treat it like a root level prerequisite for our
                        // dependency cache, as it is now an "indirect include" from the unity file.  We'll clear out the compile environment
                        // attached to this file.  This prevents us from having to cache all of the indirect includes from these files inside our
                        // dependency cache, which speeds up iterative builds a lot!
                        CPPFile.CachedCPPIncludeInfo = null;
                    }
                }

                if (AdaptiveUnityBuildInfoString.Length > 0)
                {
                    Log.TraceInformation(AdaptiveUnityBuildInfoString.ToString());
                }

                AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles();
            }

            // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding
            // actions to compile them.
            int CurrentUnityFileCount = 0;

            foreach (FileCollection UnityFile in AllUnityFiles)
            {
                ++CurrentUnityFileCount;

                StringWriter OutputUnityCPPWriter      = new StringWriter();
                StringWriter OutputUnityCPPWriterExtra = null;

                // add an extra file for UBT to get the #include dependencies from
                if (BuildPlatform.RequiresExtraUnityCPPWriter() == true)
                {
                    OutputUnityCPPWriterExtra = new StringWriter();
                }

                OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files.");

                // Add source files to the unity file
                foreach (FileItem CPPFile in UnityFile.Files)
                {
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", ToolChain.ConvertPath(CPPFile.AbsolutePath));
                    if (OutputUnityCPPWriterExtra != null)
                    {
                        OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath);
                    }
                }

                // Determine unity file path name
                string UnityCPPFileName;
                if (AllUnityFiles.Count > 1)
                {
                    UnityCPPFileName = string.Format("{0}{1}.{2}_of_{3}.cpp", ModulePrefix, BaseName, CurrentUnityFileCount, AllUnityFiles.Count);
                }
                else
                {
                    UnityCPPFileName = string.Format("{0}{1}.cpp", ModulePrefix, BaseName);
                }
                FileReference UnityCPPFilePath = FileReference.Combine(CompileEnvironment.Config.OutputDirectory, UnityCPPFileName);

                // Write the unity file to the intermediate folder.
                FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString());
                if (OutputUnityCPPWriterExtra != null)
                {
                    FileItem.CreateIntermediateTextFile(UnityCPPFilePath + ".ex", OutputUnityCPPWriterExtra.ToString());
                }

                UnityCPPFile.RelativeCost = UnityFile.TotalLength;
                NewCPPFiles.Add(UnityCPPFile);

                // Cache information about the unity .cpp dependencies
                // @todo ubtmake urgent: Fails when building remotely for Mac because unity .cpp has an include for a PCH on the REMOTE machine
                UEBuildModuleCPP.CachePCHUsageForModuleSourceFile(CompileEnvironment, UnityCPPFile);
            }

            return(NewCPPFiles);
        }
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            if (Arches.Length == 0)
            {
                throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build");
            }

            if (!bHasPrintedApiLevel)
            {
                Console.WriteLine("Compiling with NDK API '{0}'", GetNdkApiLevel());
                bHasPrintedApiLevel = true;
            }

            string BaseArguments = "";

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

            // Directly added NDK files for NDK extensions
            if (!UnrealBuildTool.RunningRocket())
            {
                ConditionallyAddNDKSourceFiles(SourceFiles);
            }

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

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



            string BasePCHName  = "";
            var    PCHExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Android].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);

            if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
            {
                BasePCHName = RemoveArchName(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath).Replace(PCHExtension, "");
            }

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (string Arch in Arches)
            {
                foreach (string GPUArchitecture in GPUArchitectures)
                {
                    // which toolchain to use
                    string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments;

                    if (GPUArchitecture == "-gl4")
                    {
                        Arguments += " -DPLATFORM_ANDROIDGL4=1";
                    }
                    else if (GPUArchitecture == "-es31")
                    {
                        Arguments += " -DPLATFORM_ANDROIDES31=1";
                    }

                    // which PCH file to include
                    string PCHArguments = "";
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        // Add the precompiled header file's path to the include path so Clang can find it.
                        // This needs to be before the other include paths to ensure Clang uses it instead of the source header file.
                        PCHArguments += string.Format(" -include \"{0}\"", InlineArchName(BasePCHName, Arch, GPUArchitecture));
                    }

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

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

                        // should we disable optimizations on this file?
                        // @todo android - We wouldn't need this if we could disable optimizations per function (via pragma)
                        bool bDisableOptimizations = false;                        // SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1;
                        if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
                        {
                            Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath);
                        }

                        bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug;

                        // Add C or C++ specific compiler arguments.
                        if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                        {
                            FileArguments += GetCompileArguments_PCH(bDisableOptimizations);
                        }
                        else if (bIsPlainCFile)
                        {
                            FileArguments += GetCompileArguments_C(bDisableOptimizations);
                        }
                        else
                        {
                            FileArguments += GetCompileArguments_CPP(bDisableOptimizations);

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

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

                        if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                        {
                            // Add the precompiled header file to the produced item list.
                            FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                                Path.Combine(
                                    CompileEnvironment.Config.OutputDirectory,
                                    Path.GetFileName(InlineArchName(SourceFile.AbsolutePath, Arch, GPUArchitecture) + PCHExtension)
                                    )
                                );

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

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

                            var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Android].GetBinaryExtension(UEBuildBinaryType.Object);

                            // Add the object file to the produced item list.
                            FileItem ObjectFile = FileItem.GetItemByPath(
                                InlineArchName(Path.Combine(
                                                   CompileEnvironment.Config.OutputDirectory,
                                                   Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension), Arch, GPUArchitecture
                                               )
                                );
                            CompileAction.ProducedItems.Add(ObjectFile);
                            Result.ObjectFiles.Add(ObjectFile);

                            FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false);
                        }

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

                        // Build a full argument list
                        string AllArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                        AllArguments = ActionThread.ExpandEnvironmentVariables(AllArguments);
                        AllArguments = AllArguments.Replace("\\", "/");

                        // Create the response file
                        string ResponseFileName = CompileAction.ProducedItems[0].AbsolutePath + ".response";
                        string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List <string> {
                            AllArguments
                        }));

                        CompileAction.WorkingDirectory  = Path.GetFullPath(".");
                        CompileAction.CommandPath       = ClangPath;
                        CompileAction.CommandArguments  = ResponseArgument;
                        CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", ""));

                        CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler);

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

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

            return(Result);
        }
Esempio n. 10
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, 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.CPPIncludeInfo.IncludePaths)
            {
                Arguments += string.Format(" /I \"{0}\"", IncludePath);
            }
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.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);

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

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

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

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

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

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

                    var PCHExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.WinRT].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);

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

                    // Add the parameters needed to compile the precompiled header file to the command-line.
                    FileArguments += string.Format(" /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);

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

                var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.WinRT].GetBinaryExtension(UEBuildBinaryType.Object);

                // Add the object file to the produced item list.
                FileItem ObjectFile = FileItem.GetItemByPath(
                    Path.Combine(
                        CompileEnvironment.Config.OutputDirectory,
                        Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                        )
                    );
                CompileAction.ProducedItems.Add(ObjectFile);
                Result.ObjectFiles.Add(ObjectFile);
                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.Target.Platform, CompileEnvironment.Config.Target.Configuration, "cl");
                CompileAction.CommandArguments  = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath));

                // 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);
        }
Esempio n. 11
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            string Arguments    = GetCLArguments_Global(CompileEnvironment);
            string PCHArguments = "";

            if (CompileEnvironment.Config.bIsBuildingDLL)
            {
                Arguments += " -fPIC";
            }

            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.
                var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Linux].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
                PCHArguments += string.Format(" -include \"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(PrecompiledFileExtension, ""));
            }

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

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

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

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                string FileArguments = "";
                string Extension     = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant();

                // Add C or C++ specific compiler arguments.
                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    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
                {
                    FileArguments += GetCompileArguments_CPP();

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

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

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

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

                    var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Linux].GetBinaryExtension(UEBuildBinaryType.Object);
                    // Add the object file to the produced item list.
                    FileItem ObjectFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(ObjectFile);
                    Result.ObjectFiles.Add(ObjectFile);

                    FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false);
                }

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

                CompileAction.WorkingDirectory = Path.GetFullPath(".");
                if (!UsingClang())
                {
                    CompileAction.CommandPath = GCCPath;
                }
                else
                {
                    CompileAction.CommandPath = ClangPath;
                }
                CompileAction.CommandArguments   = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.CommandDescription = "Compile";
                CompileAction.StatusDescription  = Path.GetFileName(SourceFile.AbsolutePath);
                CompileAction.bIsGCCCompiler     = 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;

                CompileAction.OutputEventHandler = new DataReceivedEventHandler(CompileOutputReceivedDataEventHandler);
            }

            return(Result);
        }
Esempio n. 12
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            if (CompileEnvironment.Config.Target.Architecture == "-win32")
            {
                return(base.CompileCPPFiles(Target, CompileEnvironment, SourceFiles, ModuleName));
            }

            string Arguments = GetCLArguments_Global(CompileEnvironment);

            CPPOutput Result = new CPPOutput();

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


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


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

            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.
                AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);

                // Add the source file path to the command-line.
                string FileArguments       = string.Format(" \"{0}\"", SourceFile.AbsolutePath);
                var    ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.HTML5].GetBinaryExtension(UEBuildBinaryType.Object);
                // Add the object file to the produced item list.
                FileItem ObjectFile = FileItem.GetItemByPath(
                    Path.Combine(
                        CompileEnvironment.Config.OutputDirectory,
                        Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                        )
                    );
                CompileAction.ProducedItems.Add(ObjectFile);
                FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath);

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

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

                CompileAction.CommandArguments = EMCCPath + " " + Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;

                System.Console.WriteLine(CompileAction.CommandArguments);
                CompileAction.StatusDescription  = Path.GetFileName(SourceFile.AbsolutePath);
                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);
        }
Esempio n. 13
0
        /// <summary>
        /// Given a set of C++ files, generates another set of C++ files that #include all the original
        /// files, the goal being to compile the same code in fewer translation units.
        /// The "unity" files are written to the CompileEnvironment's OutputDirectory.
        /// </summary>
        /// <param name="Target">The target we're building</param>
        /// <param name="CPPFiles">The C++ files to #include.</param>
        /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param>
        /// <param name="WorkingSet">Interface to query files which belong to the working set</param>
        /// <param name="BaseName">Base name to use for the Unity files</param>
        /// <param name="IntermediateDirectory">Intermediate directory for unity cpp files</param>
        /// <param name="Makefile">The makefile being built</param>
        /// <param name="SourceFileToUnityFile">Receives a mapping of source file to unity file</param>
        /// <returns>The "unity" C++ files.</returns>
        public static List <FileItem> GenerateUnityCPPs(
            ReadOnlyTargetRules Target,
            List <FileItem> CPPFiles,
            CppCompileEnvironment CompileEnvironment,
            ISourceFileWorkingSet WorkingSet,
            string BaseName,
            DirectoryReference IntermediateDirectory,
            TargetMakefile Makefile,
            Dictionary <FileItem, FileItem> SourceFileToUnityFile
            )
        {
            List <FileItem> NewCPPFiles = new List <FileItem>();

            UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Platform);

            // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not.
            long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Length);

            // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This
            // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X
            // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file.


            // When enabled, UnrealBuildTool will try to determine source files that you are actively iteratively changing, and break those files
            // out of their unity blobs so that you can compile them as individual translation units, much faster than recompiling the entire
            // unity blob each time.
            bool bUseAdaptiveUnityBuild = Target.bUseAdaptiveUnityBuild && !Target.bStressTestUnity;

            // Optimization only makes sense if PCH files are enabled.
            bool bForceIntoSingleUnityFile = Target.bStressTestUnity || (TotalBytesInCPPFiles < Target.NumIncludedBytesPerUnityCPP * 2 && Target.bUsePCHFiles);

            // Build the list of unity files.
            List <FileCollection> AllUnityFiles;
            {
                // Sort the incoming file paths alphabetically, so there will be consistency in unity blobs across multiple machines.
                // Note that we're relying on this not only sorting files within each directory, but also the directories
                // themselves, so the whole list of file paths is the same across computers.
                List <FileItem> SortedCPPFiles = CPPFiles.GetRange(0, CPPFiles.Count);
                {
                    // Case-insensitive file path compare, because you never know what is going on with local file systems
                    Comparison <FileItem> FileItemComparer = (FileA, FileB) => { return(FileA.AbsolutePath.ToLowerInvariant().CompareTo(FileB.AbsolutePath.ToLowerInvariant())); };
                    SortedCPPFiles.Sort(FileItemComparer);
                }


                // Figure out whether we REALLY want to use adaptive unity for this module.  If nearly every file in the module appears in the working
                // set, we'll just go ahead and let unity build do its thing.
                if (bUseAdaptiveUnityBuild)
                {
                    int CandidateWorkingSetSourceFileCount = 0;
                    int WorkingSetSourceFileCount          = 0;
                    foreach (FileItem CPPFile in SortedCPPFiles)
                    {
                        ++CandidateWorkingSetSourceFileCount;

                        // Don't include writable source files into unity blobs
                        if (WorkingSet.Contains(CPPFile))
                        {
                            ++WorkingSetSourceFileCount;

                            // Mark this file as part of the working set.  This will be saved into the UBT Makefile so that
                            // the assembler can automatically invalidate the Makefile when the working set changes (allowing this
                            // code to run again, to build up new unity blobs.)
                            Makefile.WorkingSet.Add(CPPFile);
                        }
                    }

                    if (WorkingSetSourceFileCount >= CandidateWorkingSetSourceFileCount)
                    {
                        // Every single file in the module appears in the working set, so don't bother using adaptive unity for this
                        // module.  Otherwise it would make full builds really slow.
                        bUseAdaptiveUnityBuild = false;
                    }
                }

                UnityFileBuilder CPPUnityFileBuilder          = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : Target.NumIncludedBytesPerUnityCPP);
                StringBuilder    AdaptiveUnityBuildInfoString = new StringBuilder();
                foreach (FileItem CPPFile in SortedCPPFiles)
                {
                    if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.IndexOf(".GeneratedWrapper.", StringComparison.InvariantCultureIgnoreCase) != -1)
                    {
                        NewCPPFiles.Add(CPPFile);
                    }

                    // When adaptive unity is enabled, go ahead and exclude any source files that we're actively working with
                    if (bUseAdaptiveUnityBuild && Makefile.WorkingSet.Contains(CPPFile))
                    {
                        // Just compile this file normally, not as part of the unity blob
                        NewCPPFiles.Add(CPPFile);

                        // Let the unity file builder know about the file, so that we can retain the existing size of the unity blobs.
                        // This won't actually make the source file part of the unity blob, but it will keep track of how big the
                        // file is so that other existing unity blobs from the same module won't be invalidated.  This prevents much
                        // longer compile times the first time you build after your working file set changes.
                        CPPUnityFileBuilder.AddVirtualFile(CPPFile);

                        string CPPFileName = Path.GetFileName(CPPFile.AbsolutePath);
                        if (AdaptiveUnityBuildInfoString.Length == 0)
                        {
                            AdaptiveUnityBuildInfoString.Append(String.Format("[Adaptive unity build] Excluded from {0} unity file: {1}", BaseName, CPPFileName));
                        }
                        else
                        {
                            AdaptiveUnityBuildInfoString.Append(", " + CPPFileName);
                        }
                    }
                    else
                    {
                        // If adaptive unity build is enabled for this module, add this source file to the set that will invalidate the makefile
                        if (bUseAdaptiveUnityBuild)
                        {
                            Makefile.CandidatesForWorkingSet.Add(CPPFile);
                        }

                        // Compile this file as part of the unity blob
                        CPPUnityFileBuilder.AddFile(CPPFile);
                    }
                }

                if (AdaptiveUnityBuildInfoString.Length > 0)
                {
                    if (PrintedSettingsForTargets.Add(Target.Name))
                    {
                        if (Target.bAdaptiveUnityCreatesDedicatedPCH)
                        {
                            Log.TraceInformation("[Adaptive unity build] Creating dedicated PCH for each excluded file. Set bAdaptiveUnityCreatesDedicatedPCH to false in BuildConfiguration.xml to change this behavior.");
                        }
                        else if (Target.bAdaptiveUnityDisablesPCH)
                        {
                            Log.TraceInformation("[Adaptive unity build] Disabling PCH for excluded files. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to change this behavior.");
                        }

                        if (Target.bAdaptiveUnityDisablesOptimizations)
                        {
                            Log.TraceInformation("[Adaptive unity build] Disabling optimizations for excluded files. Set bAdaptiveUnityDisablesOptimizations to false in BuildConfiguration.xml to change this behavior.");
                        }
                        if (Target.bAdaptiveUnityEnablesEditAndContinue)
                        {
                            Log.TraceInformation("[Adaptive unity build] Enabling Edit & Continue for excluded files. Set bAdaptiveUnityEnablesEditAndContinue to false in BuildConfiguration.xml to change this behavior.");
                        }
                    }
                    Log.TraceInformation(AdaptiveUnityBuildInfoString.ToString());
                }

                AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles();
            }

            // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding
            // actions to compile them.
            int CurrentUnityFileCount = 0;

            foreach (FileCollection UnityFile in AllUnityFiles)
            {
                ++CurrentUnityFileCount;

                StringWriter OutputUnityCPPWriter = new StringWriter();

                OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files.");

                // Add source files to the unity file
                foreach (FileItem CPPFile in UnityFile.Files)
                {
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath);
                }

                // Determine unity file path name
                string UnityCPPFileName;
                if (AllUnityFiles.Count > 1)
                {
                    UnityCPPFileName = string.Format("{0}{1}.{2}_of_{3}.cpp", ModulePrefix, BaseName, CurrentUnityFileCount, AllUnityFiles.Count);
                }
                else
                {
                    UnityCPPFileName = string.Format("{0}{1}.cpp", ModulePrefix, BaseName);
                }
                FileReference UnityCPPFilePath = FileReference.Combine(IntermediateDirectory, UnityCPPFileName);

                // Write the unity file to the intermediate folder.
                FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString());
                NewCPPFiles.Add(UnityCPPFile);

                // Store the mapping of source files to unity files in the makefile
                foreach (FileItem SourceFile in UnityFile.Files)
                {
                    SourceFileToUnityFile[SourceFile] = UnityCPPFile;
                }
                foreach (FileItem SourceFile in UnityFile.VirtualFiles)
                {
                    SourceFileToUnityFile[SourceFile] = UnityCPPFile;
                }
            }

            return(NewCPPFiles);
        }