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

            if (!bHasPrintedApiLevel)
            {
                Console.WriteLine("Compiling 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
            if (!UnrealBuildTool.RunningRocket())
            {
                ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName);
            }

            // 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);
        }
Example #2
0
        public override FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            List <FileItem> Outputs = new List <FileItem>();

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

                    // Android will have an array of outputs
                    if (LinkEnvironment.Config.OutputFilePaths.Length < OutputPathIndex ||
                        !Path.GetFileNameWithoutExtension(LinkEnvironment.Config.OutputFilePaths[OutputPathIndex]).EndsWith(Arch + GPUArchitecture))
                    {
                        throw new BuildException("The OutputFilePaths array didn't match the Arches array in AndroidToolChain.LinkAllFiles");
                    }

                    // Create an action that invokes the linker.
                    Action LinkAction = new Action(ActionType.Link);
                    LinkAction.WorkingDirectory = Path.GetFullPath(".");

                    if (LinkEnvironment.Config.bIsBuildingLibrary)
                    {
                        LinkAction.CommandPath = Arch == "-armv7" ? ArPathArm : ArPathx86;
                    }
                    else
                    {
                        LinkAction.CommandPath = ClangPath;
                    }

                    string LinkerPath = LinkAction.WorkingDirectory;

                    LinkAction.WorkingDirectory = LinkEnvironment.Config.IntermediateDirectory;

                    // Get link arguments.
                    LinkAction.CommandArguments = LinkEnvironment.Config.bIsBuildingLibrary ? GetArArguments(LinkEnvironment) : GetLinkArguments(LinkEnvironment, Arch);

                    // Add the output file as a production of the link action.
                    FileItem OutputFile;
                    OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePaths[OutputPathIndex]);
                    Outputs.Add(OutputFile);
                    LinkAction.ProducedItems.Add(OutputFile);
                    LinkAction.StatusDescription = string.Format("{0}", Path.GetFileName(OutputFile.AbsolutePath));

                    // LinkAction.bPrintDebugInfo = true;

                    // Add the output file to the command-line.
                    if (LinkEnvironment.Config.bIsBuildingLibrary)
                    {
                        LinkAction.CommandArguments += string.Format(" \"{0}\"", OutputFile.AbsolutePath);
                    }
                    else
                    {
                        LinkAction.CommandArguments += string.Format(" -o \"{0}\"", OutputFile.AbsolutePath);
                    }

                    // Add the input files to a response file, and pass the response file on the command-line.
                    List <string> InputFileNames = new List <string>();
                    foreach (FileItem InputFile in LinkEnvironment.InputFiles)
                    {
                        // make sure it's for current Arch
                        if (Path.GetFileNameWithoutExtension(InputFile.AbsolutePath).EndsWith(Arch + GPUArchitecture))
                        {
                            string AbsolutePath = InputFile.AbsolutePath.Replace("\\", "/");

                            AbsolutePath = AbsolutePath.Replace(LinkEnvironment.Config.IntermediateDirectory.Replace("\\", "/"), "");
                            AbsolutePath = AbsolutePath.TrimStart(new char[] { '/' });

                            InputFileNames.Add(string.Format("\"{0}\"", AbsolutePath));
                            LinkAction.PrerequisiteItems.Add(InputFile);
                        }
                    }

                    string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);
                    LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, InputFileNames));

                    // libs don't link in other libs
                    if (!LinkEnvironment.Config.bIsBuildingLibrary)
                    {
                        // Add the library paths to the argument list.
                        foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
                        {
                            // LinkerPaths could be relative or absolute
                            string AbsoluteLibraryPath = ActionThread.ExpandEnvironmentVariables(LibraryPath);
                            if (IsDirectoryForArch(AbsoluteLibraryPath, Arch))
                            {
                                // environment variables aren't expanded when using the $( style
                                if (Path.IsPathRooted(AbsoluteLibraryPath) == false)
                                {
                                    AbsoluteLibraryPath = Path.Combine(LinkerPath, AbsoluteLibraryPath);
                                }
                                LinkAction.CommandArguments += string.Format(" -L\"{0}\"", AbsoluteLibraryPath);
                            }
                        }

                        // add libraries in a library group
                        LinkAction.CommandArguments += string.Format(" -Wl,--start-group");
                        foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
                        {
                            if (!ShouldSkipLib(AdditionalLibrary, Arch, GPUArchitecture))
                            {
                                if (String.IsNullOrEmpty(Path.GetDirectoryName(AdditionalLibrary)))
                                {
                                    LinkAction.CommandArguments += string.Format(" \"-l{0}\"", AdditionalLibrary);
                                }
                                else
                                {
                                    // full pathed libs are compiled by us, so we depend on linking them
                                    LinkAction.CommandArguments += string.Format(" \"{0}\"", AdditionalLibrary);
                                    LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
                                }
                            }
                        }
                        LinkAction.CommandArguments += string.Format(" -Wl,--end-group");
                    }

                    // Add the additional arguments specified by the environment.
                    LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
                    LinkAction.CommandArguments  = LinkAction.CommandArguments.Replace("\\", "/");

                    // Only execute linking on the local PC.
                    LinkAction.bCanExecuteRemotely = false;
                }
            }

            return(Outputs.ToArray());
        }
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            if (LinkEnvironment.Config.bIsBuildingDotNetAssembly)
            {
                return(FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePath));
            }

            bool bIsBuildingLibrary = LinkEnvironment.Config.bIsBuildingLibrary || bBuildImportLibraryOnly;
            bool bIncludeDependentLibrariesInLibrary = bIsBuildingLibrary && LinkEnvironment.Config.bIncludeDependentLibrariesInLibrary;

            // Create an action that invokes the linker.
            Action LinkAction = new Action(ActionType.Link);

            LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
            LinkAction.CommandPath      = GetVCToolPath(
                LinkEnvironment.Config.Target.Platform,
                LinkEnvironment.Config.Target.Configuration,
                bIsBuildingLibrary ? "lib" : "link");

            // Get link arguments.
            LinkAction.CommandArguments = bIsBuildingLibrary ?
                                          GetLibArguments(LinkEnvironment) :
                                          GetLinkArguments(LinkEnvironment);

            // Tell the action that we're building an import library here and it should conditionally be
            // ignored as a prerequisite for other actions
            LinkAction.bProducesImportLibrary = bBuildImportLibraryOnly || LinkEnvironment.Config.bIsBuildingDLL;

            // If we're only building an import library, add the '/DEF' option that tells the LIB utility
            // to simply create a .LIB file and .EXP file, and don't bother validating imports
            if (bBuildImportLibraryOnly)
            {
                LinkAction.CommandArguments += " /DEF";

                // Ensure that the import library references the correct filename for the linked binary.
                LinkAction.CommandArguments += string.Format(" /NAME:\"{0}\"", LinkEnvironment.Config.OutputFilePath.GetFileName());
            }

            if (!LinkEnvironment.Config.bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary))
            {
                // Add the library paths to the argument list.
                foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
                {
                    LinkAction.CommandArguments += string.Format(" /LIBPATH:\"{0}\"", LibraryPath);
                }

                // Add the excluded default libraries to the argument list.
                foreach (string ExcludedLibrary in LinkEnvironment.Config.ExcludedLibraries)
                {
                    LinkAction.CommandArguments += string.Format(" /NODEFAULTLIB:\"{0}\"", ExcludedLibrary);
                }
            }

            // For targets that are cross-referenced, we don't want to write a LIB file during the link step as that
            // file will clobber the import library we went out of our way to generate during an earlier step.  This
            // file is not needed for our builds, but there is no way to prevent MSVC from generating it when
            // linking targets that have exports.  We don't want this to clobber our LIB file and invalidate the
            // existing timstamp, so instead we simply emit it with a different name
            FileReference ImportLibraryFilePath = FileReference.Combine(LinkEnvironment.Config.IntermediateDirectory,
                                                                        LinkEnvironment.Config.OutputFilePath.GetFileNameWithoutExtension() + ".lib");

            if (LinkEnvironment.Config.bIsCrossReferenced && !bBuildImportLibraryOnly)
            {
                ImportLibraryFilePath += ".suppressed";
            }

            FileItem OutputFile;

            if (bBuildImportLibraryOnly)
            {
                OutputFile = FileItem.GetItemByFileReference(ImportLibraryFilePath);
            }
            else
            {
                OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePath);
                OutputFile.bNeedsHotReloadNumbersDLLCleanUp = LinkEnvironment.Config.bIsBuildingDLL;
            }
            LinkAction.ProducedItems.Add(OutputFile);
            LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath);

            // Add the input files to a response file, and pass the response file on the command-line.
            List <string> InputFileNames = new List <string>();

            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath));
                LinkAction.PrerequisiteItems.Add(InputFile);
            }

            if (!bBuildImportLibraryOnly)
            {
                // Add input libraries as prerequisites, too!
                foreach (FileItem InputLibrary in LinkEnvironment.InputLibraries)
                {
                    InputFileNames.Add(string.Format("\"{0}\"", InputLibrary.AbsolutePath));
                    LinkAction.PrerequisiteItems.Add(InputLibrary);
                }
            }

            if (!bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary))
            {
                foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
                {
                    InputFileNames.Add(string.Format("\"{0}\"", AdditionalLibrary));

                    // If the library file name has a relative path attached (rather than relying on additional
                    // lib directories), then we'll add it to our prerequisites list.  This will allow UBT to detect
                    // when the binary needs to be relinked because a dependent external library has changed.
                    //if( !String.IsNullOrEmpty( Path.GetDirectoryName( AdditionalLibrary ) ) )
                    {
                        LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
                    }
                }
            }

            // Create a response file for the linker
            FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);

            // Never create response files when we are only generating IntelliSense data
            if (!ProjectFileGenerator.bGenerateProjectFiles)
            {
                ResponseFile.Create(ResponseFileName, InputFileNames);
            }
            LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFileName);

            // Add the output file to the command-line.
            LinkAction.CommandArguments += string.Format(" /OUT:\"{0}\"", OutputFile.AbsolutePath);

            if (bBuildImportLibraryOnly || (LinkEnvironment.Config.bHasExports && !bIsBuildingLibrary))
            {
                // An export file is written to the output directory implicitly; add it to the produced items list.
                FileReference ExportFilePath = ImportLibraryFilePath.ChangeExtension(".exp");
                FileItem      ExportFile     = FileItem.GetItemByFileReference(ExportFilePath);
                LinkAction.ProducedItems.Add(ExportFile);
            }

            if (!bIsBuildingLibrary)
            {
                // There is anything to export
                if (LinkEnvironment.Config.bHasExports
                    // Shipping monolithic builds don't need exports
                    && (!((LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) && (LinkEnvironment.bShouldCompileMonolithic != false))))
                {
                    // Write the import library to the output directory for nFringe support.
                    FileItem ImportLibraryFile = FileItem.GetItemByFileReference(ImportLibraryFilePath);
                    LinkAction.CommandArguments += string.Format(" /IMPLIB:\"{0}\"", ImportLibraryFilePath);
                    LinkAction.ProducedItems.Add(ImportLibraryFile);
                }

                if (LinkEnvironment.Config.bCreateDebugInfo)
                {
                    // Write the PDB file to the output directory.
                    {
                        FileReference PDBFilePath = FileReference.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".pdb");
                        FileItem      PDBFile     = FileItem.GetItemByFileReference(PDBFilePath);
                        LinkAction.CommandArguments += string.Format(" /PDB:\"{0}\"", PDBFilePath);
                        LinkAction.ProducedItems.Add(PDBFile);
                    }

                    // Write the MAP file to the output directory.
#if false
                    if (true)
                    {
                        FileReference MAPFilePath = FileReference.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".map");
                        FileItem      MAPFile     = FileItem.GetItemByFileReference(MAPFilePath);
                        LinkAction.CommandArguments += string.Format(" /MAP:\"{0}\"", MAPFilePath);
                        LinkAction.ProducedItems.Add(MAPFile);
                    }
#endif
                }

                // Add the additional arguments specified by the environment.
                LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
            }

            Log.TraceVerbose("     Linking: " + LinkAction.StatusDescription);
            Log.TraceVerbose("     Command: " + LinkAction.CommandArguments);

            // Only execute linking on the local PC.
            LinkAction.bCanExecuteRemotely = false;

            return(OutputFile);
        }
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph)
        {
            FileItem OutputFile;

            // Make the final javascript file
            Action LinkAction = ActionGraph.Add(ActionType.Link);

            LinkAction.CommandDescription = "Link";
//			LinkAction.bPrintDebugInfo = true;

            // ResponseFile lines.
            List <string> ReponseLines = new List <string>();

            LinkAction.bCanExecuteRemotely = false;
            LinkAction.WorkingDirectory    = UnrealBuildTool.EngineSourceDirectory.FullName;
            LinkAction.CommandPath         = HTML5SDKInfo.Python();
            LinkAction.CommandArguments    = HTML5SDKInfo.EmscriptenCompiler();
//			bool bIsBuildingLibrary = LinkEnvironment.bIsBuildingLibrary || bBuildImportLibraryOnly;
//			ReponseLines.Add(
//					bIsBuildingLibrary ?
//					GetLibArguments(LinkEnvironment) :
//					GetLinkArguments(LinkEnvironment)
//				);
            ReponseLines.Add(GetLinkArguments(LinkEnvironment));

            // Add the input files to a response file, and pass the response file on the command-line.
            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                //System.Console.WriteLine("File  {0} ", InputFile.AbsolutePath);
                ReponseLines.Add(string.Format(" \"{0}\"", InputFile.AbsolutePath));
                LinkAction.PrerequisiteItems.Add(InputFile);
            }

            if (!LinkEnvironment.bIsBuildingLibrary)
            {
                // Make sure ThirdParty libs are at the end.
                List <string> ThirdParty = (from Lib in LinkEnvironment.AdditionalLibraries
                                            where Lib.Contains("ThirdParty")
                                            select Lib).ToList();

                LinkEnvironment.AdditionalLibraries.RemoveAll(Element => Element.Contains("ThirdParty"));
                LinkEnvironment.AdditionalLibraries.AddRange(ThirdParty);

                foreach (string InputFile in LinkEnvironment.AdditionalLibraries)
                {
                    FileItem Item = FileItem.GetItemByPath(InputFile);

                    if (Item.AbsolutePath.Contains(".lib"))
                    {
                        continue;
                    }

                    if (Item.ToString().EndsWith(".js"))
                    {
                        ReponseLines.Add(string.Format(" --js-library \"{0}\"", Item.AbsolutePath));
                    }


                    // WARNING: With --pre-js and --post-js, the order in which these directives are passed to
                    // the compiler is very critical, because that dictates the order in which they are appended.
                    //
                    // Set environment variable [ EMCC_DEBUG=1 ] to see the linker order used in packaging.
                    //     See GetSharedArguments_Global() above to set this environment variable

                    else if (Item.ToString().EndsWith(".jspre"))
                    {
                        ReponseLines.Add(string.Format(" --pre-js \"{0}\"", Item.AbsolutePath));
                    }

                    else if (Item.ToString().EndsWith(".jspost"))
                    {
                        ReponseLines.Add(string.Format(" --post-js \"{0}\"", Item.AbsolutePath));
                    }


                    else
                    {
                        ReponseLines.Add(string.Format(" \"{0}\"", Item.AbsolutePath));
                    }

                    LinkAction.PrerequisiteItems.Add(Item);
                }
            }
            // make the file we will create


            OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.OutputFilePath);
            LinkAction.ProducedItems.Add(OutputFile);
            ReponseLines.Add(string.Format(" -o \"{0}\"", OutputFile.AbsolutePath));

            FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.OutputFilePath.FullName.Replace(".js", ".bc").Replace(".html", ".bc"));

            LinkAction.ProducedItems.Add(OutputBC);
            ReponseLines.Add(string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath));

            LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath);

            FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);


            LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, ReponseLines));

            LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);

            return(OutputFile);
        }
        /// <summary>
        /// Reads dependencies from the given file.
        /// </summary>
        /// <param name="InputFile">The file to read from</param>
        /// <returns>List of included dependencies</returns>
        static List <FileItem> ReadDependenciesFile(FileReference InputFile)
        {
            if (InputFile.HasExtension(".txt"))
            {
                string[] Lines = FileReference.ReadAllLines(InputFile);

                HashSet <FileItem> DependencyItems = new HashSet <FileItem>();
                foreach (string Line in Lines)
                {
                    if (Line.Length > 0)
                    {
                        // Ignore *.tlh and *.tli files generated by the compiler from COM DLLs
                        if (!Line.EndsWith(".tlh", StringComparison.OrdinalIgnoreCase) && !Line.EndsWith(".tli", StringComparison.OrdinalIgnoreCase))
                        {
                            DependencyItems.Add(FileItem.GetItemByPath(Line));
                        }
                    }
                }
                return(DependencyItems.ToList());
            }
            else if (InputFile.HasExtension(".d"))
            {
                string Text = FileReference.ReadAllText(InputFile);

                List <string> Tokens = new List <string>();

                StringBuilder Token = new StringBuilder();
                for (int Idx = 0; TryReadMakefileToken(Text, ref Idx, Token);)
                {
                    Tokens.Add(Token.ToString());
                }

                int TokenIdx = 0;
                while (TokenIdx < Tokens.Count && Tokens[TokenIdx] == "\n")
                {
                    TokenIdx++;
                }

                if (TokenIdx + 1 >= Tokens.Count || Tokens[TokenIdx + 1] != ":")
                {
                    throw new BuildException("Unable to parse dependency file");
                }

                TokenIdx += 2;

                List <FileItem> NewDependencyFiles = new List <FileItem>();
                for (; TokenIdx < Tokens.Count && Tokens[TokenIdx] != "\n"; TokenIdx++)
                {
                    NewDependencyFiles.Add(FileItem.GetItemByPath(Tokens[TokenIdx]));
                }

                while (TokenIdx < Tokens.Count && Tokens[TokenIdx] == "\n")
                {
                    TokenIdx++;
                }

                if (TokenIdx != Tokens.Count)
                {
                    throw new BuildException("Unable to parse dependency file");
                }

                return(NewDependencyFiles);
            }
            else
            {
                throw new BuildException("Unknown dependency list file type: {0}", InputFile);
            }
        }
Example #6
0
        /// <summary>
        /// Checks to see if the assembly needs compilation
        /// </summary>
        /// <param name="SourceFiles">Set of source files</param>
        /// <param name="AssemblyManifestFilePath">File containing information about this assembly, like which source files it was built with and engine version</param>
        /// <param name="OutputAssemblyPath">Output path for the assembly</param>
        /// <returns>True if the assembly needs to be built</returns>
        private static bool RequiresCompilation(HashSet <FileReference> SourceFiles, FileReference AssemblyManifestFilePath, FileReference OutputAssemblyPath)
        {
            // HACK: We cannot do this without breaking marketplace plugins. Need to distribute separate rules assemblies for those.
//			// Do not compile the file if it's installed
//			if (UnrealBuildTool.IsFileInstalled(OutputAssemblyPath))
//			{
//				Log.TraceLog("Skipping {0}: File is installed", OutputAssemblyPath);
//				return false;
//			}

            // Check to see if we already have a compiled assembly file on disk
            FileItem OutputAssemblyInfo = FileItem.GetItemByFileReference(OutputAssemblyPath);

            if (!OutputAssemblyInfo.Exists)
            {
                Log.TraceLog("Compiling {0}: Assembly does not exist", OutputAssemblyPath);
                return(true);
            }

            // Check the time stamp of the UnrealBuildTool.exe file.  If Unreal Build Tool was compiled more
            // recently than the dynamically-compiled assembly, then we'll always recompile it.  This is
            // because Unreal Build Tool's code may have changed in such a way that invalidate these
            // previously-compiled assembly files.
            FileItem ExecutableItem = FileItem.GetItemByFileReference(UnrealBuildTool.GetUBTPath());

            if (ExecutableItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc)
            {
                Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, ExecutableItem.Name);
                return(true);
            }


            // Make sure we have a manifest of source files used to compile the output assembly.  If it doesn't exist
            // for some reason (not an expected case) then we'll need to recompile.
            FileItem AssemblySourceListFile = FileItem.GetItemByFileReference(AssemblyManifestFilePath);

            if (!AssemblySourceListFile.Exists)
            {
                Log.TraceLog("Compiling {0}: Missing source file list ({1})", OutputAssemblyPath, AssemblyManifestFilePath);
                return(true);
            }

            JsonObject Manifest = JsonObject.Read(AssemblyManifestFilePath);

            // check if the engine version is different
            string EngineVersionManifest = Manifest.GetStringField("EngineVersion");
            string EngineVersionCurrent  = FormatVersionNumber(ReadOnlyBuildVersion.Current);

            if (EngineVersionManifest != EngineVersionCurrent)
            {
                Log.TraceLog("Compiling {0}: Engine Version changed from {1} to {2}", OutputAssemblyPath, EngineVersionManifest, EngineVersionCurrent);
                return(true);
            }


            // Make sure the source files we're compiling are the same as the source files that were compiled
            // for the assembly that we want to load
            HashSet <FileItem> CurrentSourceFileItems = new HashSet <FileItem>();

            foreach (string Line in Manifest.GetStringArrayField("SourceFiles"))
            {
                CurrentSourceFileItems.Add(FileItem.GetItemByPath(Line));
            }

            // Get the new source files
            HashSet <FileItem> SourceFileItems = new HashSet <FileItem>();

            foreach (FileReference SourceFile in SourceFiles)
            {
                SourceFileItems.Add(FileItem.GetItemByFileReference(SourceFile));
            }

            // Check if there are any differences between the sets
            foreach (FileItem CurrentSourceFileItem in CurrentSourceFileItems)
            {
                if (!SourceFileItems.Contains(CurrentSourceFileItem))
                {
                    Log.TraceLog("Compiling {0}: Removed source file ({1})", OutputAssemblyPath, CurrentSourceFileItem);
                    return(true);
                }
            }
            foreach (FileItem SourceFileItem in SourceFileItems)
            {
                if (!CurrentSourceFileItems.Contains(SourceFileItem))
                {
                    Log.TraceLog("Compiling {0}: Added source file ({1})", OutputAssemblyPath, SourceFileItem);
                    return(true);
                }
            }

            // Check if any of the timestamps are newer
            foreach (FileItem SourceFileItem in SourceFileItems)
            {
                if (SourceFileItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc)
                {
                    Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, SourceFileItem);
                    return(true);
                }
            }

            return(false);
        }
Example #7
0
        /// <summary>
        /// Patch the action graph for hot reloading, mapping files according to the given dictionary.
        /// </summary>
        public static void PatchActionGraph(IEnumerable <Action> Actions, Dictionary <FileReference, FileReference> OriginalFileToHotReloadFile)
        {
            // Gather all of the response files for link actions.  We're going to need to patch 'em up after we figure out new
            // names for all of the output files and import libraries
            List <string> ResponseFilePaths = new List <string>();

            // Same as Response files but for all of the link.sh files for link actions.
            // Only used on BuildHostPlatform Linux
            List <string> LinkScriptFilePaths = new List <string>();

            // Keep a map of the original file names and their new file names, so we can fix up response files after
            Dictionary <string, string> OriginalFileNameAndNewFileNameList_NoExtensions = new Dictionary <string, string>();

            // Finally, we'll keep track of any file items that we had to create counterparts for change file names, so we can fix those up too
            Dictionary <FileItem, FileItem> AffectedOriginalFileItemAndNewFileItemMap = new Dictionary <FileItem, FileItem>();

            foreach (Action Action in Actions.Where((Action) => Action.ActionType == ActionType.Link))
            {
                // Assume that the first produced item (with no extension) is our output file name
                FileReference HotReloadFile;
                if (!OriginalFileToHotReloadFile.TryGetValue(Action.ProducedItems[0].Location, out HotReloadFile))
                {
                    continue;
                }

                string OriginalFileNameWithoutExtension = Utils.GetFilenameWithoutAnyExtensions(Action.ProducedItems[0].AbsolutePath);
                string NewFileNameWithoutExtension      = Utils.GetFilenameWithoutAnyExtensions(HotReloadFile.FullName);

                // Find the response file in the command line.  We'll need to make a copy of it with our new file name.
                string ResponseFileExtension  = ".response";
                int    ResponseExtensionIndex = Action.CommandArguments.IndexOf(ResponseFileExtension, StringComparison.InvariantCultureIgnoreCase);
                if (ResponseExtensionIndex != -1)
                {
                    int ResponseFilePathIndex = Action.CommandArguments.LastIndexOf("@\"", ResponseExtensionIndex);
                    if (ResponseFilePathIndex == -1)
                    {
                        throw new BuildException("Couldn't find response file path in action's command arguments when hot reloading");
                    }

                    string OriginalResponseFilePathWithoutExtension = Action.CommandArguments.Substring(ResponseFilePathIndex + 2, (ResponseExtensionIndex - ResponseFilePathIndex) - 2);
                    string OriginalResponseFilePath = OriginalResponseFilePathWithoutExtension + ResponseFileExtension;

                    string NewResponseFilePath = ReplaceBaseFileName(OriginalResponseFilePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);

                    // Copy the old response file to the new path
                    if (String.Compare(OriginalResponseFilePath, NewResponseFilePath, StringComparison.OrdinalIgnoreCase) != 0)
                    {
                        File.Copy(OriginalResponseFilePath, NewResponseFilePath, overwrite: true);
                    }

                    // Keep track of the new response file name.  We'll have to do some edits afterwards.
                    ResponseFilePaths.Add(NewResponseFilePath);
                }

                // Find the *.link.sh file in the command line.  We'll need to make a copy of it with our new file name.
                // Only currently used on Linux
                if (UEBuildPlatform.IsPlatformInGroup(BuildHostPlatform.Current.Platform, UnrealPlatformGroup.Unix))
                {
                    string LinkScriptFileExtension  = ".link.sh";
                    int    LinkScriptExtensionIndex = Action.CommandArguments.IndexOf(LinkScriptFileExtension, StringComparison.InvariantCultureIgnoreCase);
                    if (LinkScriptExtensionIndex != -1)
                    {
                        // We expect the script invocation to be quoted
                        int LinkScriptFilePathIndex = Action.CommandArguments.LastIndexOf("\"", LinkScriptExtensionIndex);
                        if (LinkScriptFilePathIndex == -1)
                        {
                            throw new BuildException("Couldn't find link script file path in action's command arguments when hot reloading. Is the path quoted?");
                        }

                        string OriginalLinkScriptFilePathWithoutExtension = Action.CommandArguments.Substring(LinkScriptFilePathIndex + 1, (LinkScriptExtensionIndex - LinkScriptFilePathIndex) - 1);
                        string OriginalLinkScriptFilePath = OriginalLinkScriptFilePathWithoutExtension + LinkScriptFileExtension;

                        string NewLinkScriptFilePath = ReplaceBaseFileName(OriginalLinkScriptFilePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);

                        // Copy the old response file to the new path
                        File.Copy(OriginalLinkScriptFilePath, NewLinkScriptFilePath, overwrite: true);

                        // Keep track of the new response file name.  We'll have to do some edits afterwards.
                        LinkScriptFilePaths.Add(NewLinkScriptFilePath);
                    }

                    // Update this action's list of prerequisite items too
                    for (int ItemIndex = 0; ItemIndex < Action.PrerequisiteItems.Count; ++ItemIndex)
                    {
                        FileItem OriginalPrerequisiteItem    = Action.PrerequisiteItems[ItemIndex];
                        string   NewPrerequisiteItemFilePath = ReplaceBaseFileName(OriginalPrerequisiteItem.AbsolutePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);

                        if (OriginalPrerequisiteItem.AbsolutePath != NewPrerequisiteItemFilePath)
                        {
                            // OK, the prerequisite item's file name changed so we'll update it to point to our new file
                            FileItem NewPrerequisiteItem = FileItem.GetItemByPath(NewPrerequisiteItemFilePath);
                            Action.PrerequisiteItems[ItemIndex] = NewPrerequisiteItem;

                            // Keep track of it so we can fix up dependencies in a second pass afterwards
                            AffectedOriginalFileItemAndNewFileItemMap.Add(OriginalPrerequisiteItem, NewPrerequisiteItem);

                            ResponseExtensionIndex = OriginalPrerequisiteItem.AbsolutePath.IndexOf(ResponseFileExtension, StringComparison.InvariantCultureIgnoreCase);
                            if (ResponseExtensionIndex != -1)
                            {
                                string OriginalResponseFilePathWithoutExtension = OriginalPrerequisiteItem.AbsolutePath.Substring(0, ResponseExtensionIndex);
                                string OriginalResponseFilePath = OriginalResponseFilePathWithoutExtension + ResponseFileExtension;

                                string NewResponseFilePath = ReplaceBaseFileName(OriginalResponseFilePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);

                                // Copy the old response file to the new path
                                File.Copy(OriginalResponseFilePath, NewResponseFilePath, overwrite: true);

                                // Keep track of the new response file name.  We'll have to do some edits afterwards.
                                ResponseFilePaths.Add(NewResponseFilePath);
                            }
                        }
                    }
                }

                // Update this action's list of produced items too
                for (int ItemIndex = 0; ItemIndex < Action.ProducedItems.Count; ++ItemIndex)
                {
                    FileItem OriginalProducedItem = Action.ProducedItems[ItemIndex];

                    string NewProducedItemFilePath = ReplaceBaseFileName(OriginalProducedItem.AbsolutePath, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);
                    if (OriginalProducedItem.AbsolutePath != NewProducedItemFilePath)
                    {
                        // OK, the produced item's file name changed so we'll update it to point to our new file
                        FileItem NewProducedItem = FileItem.GetItemByPath(NewProducedItemFilePath);
                        Action.ProducedItems[ItemIndex] = NewProducedItem;

                        // Keep track of it so we can fix up dependencies in a second pass afterwards
                        AffectedOriginalFileItemAndNewFileItemMap.Add(OriginalProducedItem, NewProducedItem);
                    }
                }

                // Fix up the list of items to delete too
                for (int Idx = 0; Idx < Action.DeleteItems.Count; Idx++)
                {
                    FileItem NewItem;
                    if (AffectedOriginalFileItemAndNewFileItemMap.TryGetValue(Action.DeleteItems[Idx], out NewItem))
                    {
                        Action.DeleteItems[Idx] = NewItem;
                    }
                }

                // The status description of the item has the file name, so we'll update it too
                Action.StatusDescription = ReplaceBaseFileName(Action.StatusDescription, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);

                // Keep track of the file names, so we can fix up response files afterwards.
                if (!OriginalFileNameAndNewFileNameList_NoExtensions.ContainsKey(OriginalFileNameWithoutExtension))
                {
                    OriginalFileNameAndNewFileNameList_NoExtensions[OriginalFileNameWithoutExtension] = NewFileNameWithoutExtension;
                }
                else if (OriginalFileNameAndNewFileNameList_NoExtensions[OriginalFileNameWithoutExtension] != NewFileNameWithoutExtension)
                {
                    throw new BuildException("Unexpected conflict in renaming files; {0} maps to {1} and {2}", OriginalFileNameWithoutExtension, OriginalFileNameAndNewFileNameList_NoExtensions[OriginalFileNameWithoutExtension], NewFileNameWithoutExtension);
                }
            }


            // Do another pass and update any actions that depended on the original file names that we changed
            foreach (Action Action in Actions)
            {
                for (int ItemIndex = 0; ItemIndex < Action.PrerequisiteItems.Count; ++ItemIndex)
                {
                    FileItem OriginalFileItem = Action.PrerequisiteItems[ItemIndex];

                    FileItem NewFileItem;
                    if (AffectedOriginalFileItemAndNewFileItemMap.TryGetValue(OriginalFileItem, out NewFileItem))
                    {
                        // OK, looks like we need to replace this file item because we've renamed the file
                        Action.PrerequisiteItems[ItemIndex] = NewFileItem;
                    }
                }
            }


            if (OriginalFileNameAndNewFileNameList_NoExtensions.Count > 0)
            {
                // Update all the paths in link actions
                foreach (Action Action in Actions.Where((Action) => Action.ActionType == ActionType.Link))
                {
                    foreach (KeyValuePair <string, string> FileNameTuple in OriginalFileNameAndNewFileNameList_NoExtensions)
                    {
                        string OriginalFileNameWithoutExtension = FileNameTuple.Key;
                        string NewFileNameWithoutExtension      = FileNameTuple.Value;

                        Action.CommandArguments = ReplaceBaseFileName(Action.CommandArguments, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);
                    }
                }

                foreach (string ResponseFilePath in ResponseFilePaths)
                {
                    // Load the file up
                    string FileContents = Utils.ReadAllText(ResponseFilePath);

                    // Replace all of the old file names with new ones
                    foreach (KeyValuePair <string, string> FileNameTuple in OriginalFileNameAndNewFileNameList_NoExtensions)
                    {
                        string OriginalFileNameWithoutExtension = FileNameTuple.Key;
                        string NewFileNameWithoutExtension      = FileNameTuple.Value;

                        FileContents = ReplaceBaseFileName(FileContents, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);
                    }

                    // Overwrite the original file
                    File.WriteAllText(ResponseFilePath, FileContents, new System.Text.UTF8Encoding(false));
                }

                if (UEBuildPlatform.IsPlatformInGroup(BuildHostPlatform.Current.Platform, UnrealPlatformGroup.Unix))
                {
                    foreach (string LinkScriptFilePath in LinkScriptFilePaths)
                    {
                        // Load the file up
                        string FileContents = Utils.ReadAllText(LinkScriptFilePath);

                        // Replace all of the old file names with new ones
                        foreach (KeyValuePair <string, string> FileNameTuple in OriginalFileNameAndNewFileNameList_NoExtensions)
                        {
                            string OriginalFileNameWithoutExtension = FileNameTuple.Key;
                            string NewFileNameWithoutExtension      = FileNameTuple.Value;

                            FileContents = ReplaceBaseFileName(FileContents, OriginalFileNameWithoutExtension, NewFileNameWithoutExtension);
                        }

                        // Overwrite the original file
                        File.WriteAllText(LinkScriptFilePath, FileContents, new System.Text.UTF8Encoding(false));
                    }
                }
            }

            // Update the action that writes out the module manifests
            foreach (Action Action in Actions)
            {
                if (Action.ActionType == ActionType.WriteMetadata)
                {
                    string Arguments = Action.CommandArguments;

                    // Find the argument for the metadata file
                    const string InputArgument = "-Input=";

                    int InputIdx = Arguments.IndexOf(InputArgument);
                    if (InputIdx == -1)
                    {
                        throw new Exception("Missing -Input= argument to WriteMetadata command when patching action graph.");
                    }

                    int FileNameIdx = InputIdx + InputArgument.Length;
                    if (Arguments[FileNameIdx] == '\"')
                    {
                        FileNameIdx++;
                    }

                    int FileNameEndIdx = FileNameIdx;
                    while (FileNameEndIdx < Arguments.Length && (Arguments[FileNameEndIdx] != ' ' || Arguments[FileNameIdx - 1] == '\"') && Arguments[FileNameEndIdx] != '\"')
                    {
                        FileNameEndIdx++;
                    }

                    // Read the metadata file
                    FileReference TargetInfoFile = new FileReference(Arguments.Substring(FileNameIdx, FileNameEndIdx - FileNameIdx));
                    if (!FileReference.Exists(TargetInfoFile))
                    {
                        throw new Exception(String.Format("Unable to find metadata file to patch action graph ({0})", TargetInfoFile));
                    }

                    // Update the module names
                    WriteMetadataTargetInfo TargetInfo = BinaryFormatterUtils.Load <WriteMetadataTargetInfo>(TargetInfoFile);
                    foreach (KeyValuePair <FileReference, ModuleManifest> FileNameToVersionManifest in TargetInfo.FileToManifest)
                    {
                        KeyValuePair <string, string>[] ManifestEntries = FileNameToVersionManifest.Value.ModuleNameToFileName.ToArray();
                        foreach (KeyValuePair <string, string> Manifest in ManifestEntries)
                        {
                            FileReference OriginalFile = FileReference.Combine(FileNameToVersionManifest.Key.Directory, Manifest.Value);

                            FileReference HotReloadFile;
                            if (OriginalFileToHotReloadFile.TryGetValue(OriginalFile, out HotReloadFile))
                            {
                                FileNameToVersionManifest.Value.ModuleNameToFileName[Manifest.Key] = HotReloadFile.GetFileName();
                            }
                        }
                    }

                    // Write the hot-reload metadata file and update the argument list
                    FileReference HotReloadTargetInfoFile = FileReference.Combine(TargetInfoFile.Directory, "Metadata-HotReload.dat");
                    BinaryFormatterUtils.SaveIfDifferent(HotReloadTargetInfoFile, TargetInfo);

                    Action.PrerequisiteItems.RemoveAll(x => x.Location == TargetInfoFile);
                    Action.PrerequisiteItems.Add(FileItem.GetItemByFileReference(HotReloadTargetInfoFile));

                    Action.CommandArguments = Arguments.Substring(0, FileNameIdx) + HotReloadTargetInfoFile + Arguments.Substring(FileNameEndIdx);
                }
            }
        }
Example #8
0
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            Debug.Assert(!bBuildImportLibraryOnly);

            List <string> RPaths = new List <string>();

            if (LinkEnvironment.Config.bIsBuildingLibrary || bBuildImportLibraryOnly)
            {
                return(CreateArchiveAndIndex(LinkEnvironment));
            }

            // Create an action that invokes the linker.
            Action LinkAction = new Action(ActionType.Link);

            LinkAction.WorkingDirectory = Path.GetFullPath(".");
            if (String.IsNullOrEmpty(ClangPath))
            {
                LinkAction.CommandPath = GCCPath;
            }
            else
            {
                LinkAction.CommandPath = ClangPath;
            }

            // Get link arguments.
            LinkAction.CommandArguments = GetLinkArguments(LinkEnvironment);

            // Tell the action that we're building an import library here and it should conditionally be
            // ignored as a prerequisite for other actions
            LinkAction.bProducesImportLibrary = LinkEnvironment.Config.bIsBuildingDLL;

            // Add the output file as a production of the link action.
            FileItem OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath);

            LinkAction.ProducedItems.Add(OutputFile);
            LinkAction.CommandDescription = "Link";
            LinkAction.StatusDescription  = Path.GetFileName(OutputFile.AbsolutePath);

            // Add the output file to the command-line.
            LinkAction.CommandArguments += string.Format(" -o \"{0}\"", OutputFile.AbsolutePath);

            // Add the input files to a response file, and pass the response file on the command-line.
            List <string> InputFileNames = new List <string>();

            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath.Replace("\\", "/")));
                LinkAction.PrerequisiteItems.Add(InputFile);
            }

            string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);

            LinkAction.CommandArguments += string.Format(" -Wl,@\"{0}\"", ResponseFile.Create(ResponseFileName, InputFileNames));

            if (LinkEnvironment.Config.bIsBuildingDLL)
            {
                LinkAction.CommandArguments += string.Format(" -Wl,-soname={0}", OutputFile);
            }

            // Start with the configured LibraryPaths and also add paths to any libraries that
            // we depend on (libraries that we've build ourselves).
            List <string> AllLibraryPaths = LinkEnvironment.Config.LibraryPaths;

            foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
            {
                string PathToLib = Path.GetDirectoryName(AdditionalLibrary);
                if (!String.IsNullOrEmpty(PathToLib))
                {
                    // make path absolute, because FixDependencies script may be executed in a different directory
                    string AbsolutePathToLib = Path.GetFullPath(PathToLib);
                    if (!AllLibraryPaths.Contains(AbsolutePathToLib))
                    {
                        AllLibraryPaths.Add(AbsolutePathToLib);
                    }
                }

                if ((AdditionalLibrary.Contains("Plugins") || AdditionalLibrary.Contains("Binaries/ThirdParty") || AdditionalLibrary.Contains("Binaries\\ThirdParty")) && Path.GetDirectoryName(AdditionalLibrary) != Path.GetDirectoryName(OutputFile.AbsolutePath))
                {
                    string RelativePath = Utils.MakePathRelativeTo(Path.GetDirectoryName(AdditionalLibrary), Path.GetDirectoryName(OutputFile.AbsolutePath));
                    if (!RPaths.Contains(RelativePath))
                    {
                        RPaths.Add(RelativePath);
                        LinkAction.CommandArguments += string.Format(" -Wl,-rpath=\"${{ORIGIN}}/{0}\"", RelativePath);
                    }
                }
            }

            LinkAction.CommandArguments += string.Format(" -Wl,-rpath-link=\"{0}\"", Path.GetDirectoryName(OutputFile.AbsolutePath));

            // Add the library paths to the argument list.
            foreach (string LibraryPath in AllLibraryPaths)
            {
                // use absolute paths because of FixDependencies script again
                LinkAction.CommandArguments += string.Format(" -L\"{0}\"", Path.GetFullPath(LibraryPath));
            }

            // add libraries in a library group
            LinkAction.CommandArguments += string.Format(" -Wl,--start-group");

            List <string> EngineAndGameLibraries = new List <string>();

            foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
            {
                if (String.IsNullOrEmpty(Path.GetDirectoryName(AdditionalLibrary)))
                {
                    // library was passed just like "jemalloc", turn it into -ljemalloc
                    LinkAction.CommandArguments += string.Format(" -l{0}", AdditionalLibrary);
                }
                else if (Path.GetExtension(AdditionalLibrary) == ".a")
                {
                    // static library passed in, pass it along but make path absolute, because FixDependencies script may be executed in a different directory
                    string AbsoluteAdditionalLibrary = Path.GetFullPath(AdditionalLibrary);
                    if (AbsoluteAdditionalLibrary.Contains(" "))
                    {
                        AbsoluteAdditionalLibrary = string.Format("\"{0}\"", AbsoluteAdditionalLibrary);
                    }
                    LinkAction.CommandArguments += (" " + AbsoluteAdditionalLibrary);
                    LinkAction.PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
                }
                else
                {
                    // Skip over full-pathed library dependencies when building DLLs to avoid circular
                    // dependencies.
                    FileItem LibraryDependency = FileItem.GetItemByPath(AdditionalLibrary);

                    var LibName = Path.GetFileNameWithoutExtension(AdditionalLibrary);
                    if (LibName.StartsWith("lib"))
                    {
                        // Remove lib prefix
                        LibName = LibName.Remove(0, 3);
                    }
                    string LibLinkFlag = string.Format(" -l{0}", LibName);

                    if (LinkEnvironment.Config.bIsBuildingDLL && LinkEnvironment.Config.bIsCrossReferenced)
                    {
                        // We are building a cross referenced DLL so we can't actually include
                        // dependencies at this point. Instead we add it to the list of
                        // libraries to be used in the FixDependencies step.
                        EngineAndGameLibraries.Add(LibLinkFlag);
                        if (!LinkAction.CommandArguments.Contains("--allow-shlib-undefined"))
                        {
                            LinkAction.CommandArguments += string.Format(" -Wl,--allow-shlib-undefined");
                        }
                    }
                    else
                    {
                        LinkAction.PrerequisiteItems.Add(LibraryDependency);
                        LinkAction.CommandArguments += LibLinkFlag;
                    }
                }
            }
            LinkAction.CommandArguments += " -lrt"; // needed for clock_gettime()
            LinkAction.CommandArguments += " -lm";  // math
            LinkAction.CommandArguments += string.Format(" -Wl,--end-group");

            // Add the additional arguments specified by the environment.
            LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
            LinkAction.CommandArguments  = LinkAction.CommandArguments.Replace("\\\\", "/");
            LinkAction.CommandArguments  = LinkAction.CommandArguments.Replace("\\", "/");

            // prepare a linker script
            string LinkerScriptPath = Path.Combine(LinkEnvironment.Config.LocalShadowDirectory, "remove-sym.ldscript");

            if (!Directory.Exists(LinkEnvironment.Config.LocalShadowDirectory))
            {
                Directory.CreateDirectory(LinkEnvironment.Config.LocalShadowDirectory);
            }
            if (File.Exists(LinkerScriptPath))
            {
                File.Delete(LinkerScriptPath);
            }

            using (StreamWriter Writer = File.CreateText(LinkerScriptPath))
            {
                Writer.WriteLine("UE4 {");
                Writer.WriteLine("  global: *;");
                Writer.WriteLine("  local: _Znwm;");
                Writer.WriteLine("         _Znam;");
                Writer.WriteLine("         _ZdaPv;");
                Writer.WriteLine("         _ZdlPv;");
                Writer.WriteLine("};");
            };

            LinkAction.CommandArguments += string.Format(" -Wl,--version-script=\"{0}\"", LinkerScriptPath);

            // Only execute linking on the local PC.
            LinkAction.bCanExecuteRemotely = false;

            // Prepare a script that will run later, once all shared libraries and the executable
            // are created. This script will be called by action created in FixDependencies()
            if (LinkEnvironment.Config.bIsCrossReferenced && LinkEnvironment.Config.bIsBuildingDLL)
            {
                bool   bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32;
                string ScriptName = bUseCmdExe ? "FixDependencies.bat" : "FixDependencies.sh";

                string FixDepsScriptPath = Path.Combine(LinkEnvironment.Config.LocalShadowDirectory, ScriptName);
                if (!bHasWipedFixDepsScript)
                {
                    bHasWipedFixDepsScript = true;
                    Log.TraceVerbose("Creating script: {0}", FixDepsScriptPath);
                    StreamWriter Writer = File.CreateText(FixDepsScriptPath);

                    if (bUseCmdExe)
                    {
                        Writer.Write("@echo off\n");
                        Writer.Write("rem Automatically generated by UnrealBuildTool\n");
                        Writer.Write("rem *DO NOT EDIT*\n\n");
                    }
                    else
                    {
                        Writer.Write("#!/bin/sh\n");
                        Writer.Write("# Automatically generated by UnrealBuildTool\n");
                        Writer.Write("# *DO NOT EDIT*\n\n");
                        Writer.Write("set -o errexit\n");
                    }
                    Writer.Close();
                }

                StreamWriter FixDepsScript = File.AppendText(FixDepsScriptPath);

                string EngineAndGameLibrariesString = "";
                foreach (string Library in EngineAndGameLibraries)
                {
                    EngineAndGameLibrariesString += Library;
                }

                FixDepsScript.Write(string.Format("echo Fixing {0}\n", Path.GetFileName(OutputFile.AbsolutePath)));
                if (!bUseCmdExe)
                {
                    FixDepsScript.Write(string.Format("TIMESTAMP=`stat --format %y \"{0}\"`\n", OutputFile.AbsolutePath));
                }
                string FixDepsLine = LinkAction.CommandPath + " " + LinkAction.CommandArguments;
                string Replace     = "-Wl,--allow-shlib-undefined";

                FixDepsLine = FixDepsLine.Replace(Replace, EngineAndGameLibrariesString);
                string OutputFileForwardSlashes = OutputFile.AbsolutePath.Replace("\\", "/");
                FixDepsLine = FixDepsLine.Replace(OutputFileForwardSlashes, OutputFileForwardSlashes + ".fixed");
                FixDepsLine = FixDepsLine.Replace("$", "\\$");
                FixDepsScript.Write(FixDepsLine + "\n");
                if (bUseCmdExe)
                {
                    FixDepsScript.Write(string.Format("move /Y \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath));
                }
                else
                {
                    FixDepsScript.Write(string.Format("mv \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath));
                    FixDepsScript.Write(string.Format("touch -d \"$TIMESTAMP\" \"{0}\"\n\n", OutputFile.AbsolutePath));
                }
                FixDepsScript.Close();
            }

            //LinkAction.CommandArguments += " -v";

            return(OutputFile);
        }
Example #9
0
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            var EnvVars = VCEnvironment.SetEnvironment(LinkEnvironment.Config.Target.Platform);

            if (LinkEnvironment.Config.bIsBuildingDotNetAssembly)
            {
                return(FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath));
            }

            bool bIsBuildingLibrary = LinkEnvironment.Config.bIsBuildingLibrary || bBuildImportLibraryOnly;
            bool bIncludeDependentLibrariesInLibrary = bIsBuildingLibrary && LinkEnvironment.Config.bIncludeDependentLibrariesInLibrary;

            // Get link arguments.
            StringBuilder Arguments = new StringBuilder();

            if (bIsBuildingLibrary)
            {
                AppendLibArguments(LinkEnvironment, Arguments);
            }
            else
            {
                AppendLinkArguments(LinkEnvironment, Arguments);
            }



            // If we're only building an import library, add the '/DEF' option that tells the LIB utility
            // to simply create a .LIB file and .EXP file, and don't bother validating imports
            if (bBuildImportLibraryOnly)
            {
                Arguments.Append(" /DEF");

                // Ensure that the import library references the correct filename for the linked binary.
                Arguments.AppendFormat(" /NAME:\"{0}\"", Path.GetFileName(LinkEnvironment.Config.OutputFilePath));
            }


            // Add delay loaded DLLs.
            if (!bIsBuildingLibrary)
            {
                // Delay-load these DLLs.
                foreach (string DelayLoadDLL in LinkEnvironment.Config.DelayLoadDLLs)
                {
                    Arguments.AppendFormat(" /DELAYLOAD:\"{0}\"", DelayLoadDLL);
                }
            }

            // @todo UE4 DLL: Why do I need LIBPATHs to build only export libraries with /DEF? (tbbmalloc.lib)
            if (!LinkEnvironment.Config.bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary))
            {
                // Add the library paths to the argument list.
                foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
                {
                    Arguments.AppendFormat(" /LIBPATH:\"{0}\"", LibraryPath);
                }

                // Add the excluded default libraries to the argument list.
                foreach (string ExcludedLibrary in LinkEnvironment.Config.ExcludedLibraries)
                {
                    Arguments.AppendFormat(" /NODEFAULTLIB:\"{0}\"", ExcludedLibrary);
                }
            }

            // For targets that are cross-referenced, we don't want to write a LIB file during the link step as that
            // file will clobber the import library we went out of our way to generate during an earlier step.  This
            // file is not needed for our builds, but there is no way to prevent MSVC from generating it when
            // linking targets that have exports.  We don't want this to clobber our LIB file and invalidate the
            // existing timstamp, so instead we simply emit it with a different name
            string ImportLibraryFilePath = Path.Combine(LinkEnvironment.Config.IntermediateDirectory,
                                                        Path.GetFileNameWithoutExtension(LinkEnvironment.Config.OutputFilePath) + ".lib");

            if (LinkEnvironment.Config.bIsCrossReferenced && !bBuildImportLibraryOnly)
            {
                ImportLibraryFilePath += ".suppressed";
            }

            FileItem OutputFile;

            if (bBuildImportLibraryOnly)
            {
                OutputFile = FileItem.GetItemByPath(ImportLibraryFilePath);
            }
            else
            {
                OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath);
                OutputFile.bNeedsHotReloadNumbersDLLCleanUp = LinkEnvironment.Config.bIsBuildingDLL;
            }

            List <FileItem> ProducedItems = new List <FileItem>();

            ProducedItems.Add(OutputFile);

            List <FileItem> PrerequisiteItems = new List <FileItem>();

            // Add the input files to a response file, and pass the response file on the command-line.
            List <string> InputFileNames = new List <string>();

            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath));
                PrerequisiteItems.Add(InputFile);
            }

            if (!bBuildImportLibraryOnly)
            {
                // Add input libraries as prerequisites, too!
                foreach (FileItem InputLibrary in LinkEnvironment.InputLibraries)
                {
                    InputFileNames.Add(string.Format("\"{0}\"", InputLibrary.AbsolutePath));
                    PrerequisiteItems.Add(InputLibrary);
                }
            }

            if (!bIsBuildingLibrary || (LinkEnvironment.Config.bIsBuildingLibrary && bIncludeDependentLibrariesInLibrary))
            {
                foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
                {
                    InputFileNames.Add(string.Format("\"{0}\"", AdditionalLibrary));

                    // If the library file name has a relative path attached (rather than relying on additional
                    // lib directories), then we'll add it to our prerequisites list.  This will allow UBT to detect
                    // when the binary needs to be relinked because a dependent external library has changed.
                    //if( !String.IsNullOrEmpty( Path.GetDirectoryName( AdditionalLibrary ) ) )
                    {
                        PrerequisiteItems.Add(FileItem.GetItemByPath(AdditionalLibrary));
                    }
                }
            }

            // Create a response file for the linker
            string ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);

            // Never create response files when we are only generating IntelliSense data
            if (!ProjectFileGenerator.bGenerateProjectFiles)
            {
                ResponseFile.Create(ResponseFileName, InputFileNames);
            }
            Arguments.AppendFormat(" @\"{0}\"", ResponseFileName);

            // Add the output file to the command-line.
            Arguments.AppendFormat(" /OUT:\"{0}\"", OutputFile.AbsolutePath);

            if (bBuildImportLibraryOnly || (LinkEnvironment.Config.bHasExports && !bIsBuildingLibrary))
            {
                // An export file is written to the output directory implicitly; add it to the produced items list.
                string   ExportFilePath = Path.ChangeExtension(ImportLibraryFilePath, ".exp");
                FileItem ExportFile     = FileItem.GetItemByPath(ExportFilePath);
                ProducedItems.Add(ExportFile);
            }

            if (!bIsBuildingLibrary)
            {
                // Xbox 360 LTCG does not seem to produce those.
                if (LinkEnvironment.Config.bHasExports &&
                    (LinkEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Shipping))
                {
                    // Write the import library to the output directory for nFringe support.
                    FileItem ImportLibraryFile = FileItem.GetItemByPath(ImportLibraryFilePath);
                    Arguments.AppendFormat(" /IMPLIB:\"{0}\"", ImportLibraryFilePath);
                    ProducedItems.Add(ImportLibraryFile);
                }

                if (LinkEnvironment.Config.bCreateDebugInfo)
                {
                    // Write the PDB file to the output directory.
                    string   PDBFilePath = Path.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".pdb");
                    FileItem PDBFile     = FileItem.GetItemByPath(PDBFilePath);
                    Arguments.AppendFormat(" /PDB:\"{0}\"", PDBFilePath);
                    ProducedItems.Add(PDBFile);

                    // Write the MAP file to the output directory.
#if false
                    if (true)
                    {
                        string   MAPFilePath = Path.Combine(LinkEnvironment.Config.OutputDirectory, Path.GetFileNameWithoutExtension(OutputFile.AbsolutePath) + ".map");
                        FileItem MAPFile     = FileItem.GetItemByPath(MAPFilePath);
                        LinkAction.CommandArguments += string.Format(" /MAP:\"{0}\"", MAPFilePath);
                        LinkAction.ProducedItems.Add(MAPFile);
                    }
#endif
                }

                // Add the additional arguments specified by the environment.
                Arguments.Append(LinkEnvironment.Config.AdditionalArguments);
            }

            // Create an action that invokes the linker.
            Action LinkAction = new Action(ActionType.Link);
            LinkAction.CommandDescription = "Link";
            LinkAction.WorkingDirectory   = Path.GetFullPath(".");
            LinkAction.CommandPath        = bIsBuildingLibrary ? EnvVars.LibraryLinkerPath : EnvVars.LinkerPath;
            LinkAction.CommandArguments   = Arguments.ToString();
            LinkAction.ProducedItems.AddRange(ProducedItems);
            LinkAction.PrerequisiteItems.AddRange(PrerequisiteItems);
            LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath);

            // Tell the action that we're building an import library here and it should conditionally be
            // ignored as a prerequisite for other actions
            LinkAction.bProducesImportLibrary = bBuildImportLibraryOnly || LinkEnvironment.Config.bIsBuildingDLL;

            // Only execute linking on the local PC.
            LinkAction.bCanExecuteRemotely = false;

            Log.TraceVerbose("     Linking: " + LinkAction.StatusDescription);
            Log.TraceVerbose("     Command: " + LinkAction.CommandArguments);

            return(OutputFile);
        }
Example #10
0
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            if (LinkEnvironment.Config.Target.Architecture == "-win32")             // simulator
            {
                return(base.LinkFiles(LinkEnvironment, bBuildImportLibraryOnly));
            }

            FileItem OutputFile;

            // Make the final javascript file
            Action LinkAction = new Action(ActionType.Link);

            // ResponseFile lines.
            List <string> ReponseLines = new List <string>();

            LinkAction.bCanExecuteRemotely = false;
            LinkAction.WorkingDirectory    = UnrealBuildTool.EngineSourceDirectory.FullName;
            LinkAction.CommandPath         = HTML5SDKInfo.Python();
            LinkAction.CommandArguments    = HTML5SDKInfo.EmscriptenCompiler();
            ReponseLines.Add(GetLinkArguments(LinkEnvironment));

            // Add the input files to a response file, and pass the response file on the command-line.
            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                //System.Console.WriteLine("File  {0} ", InputFile.AbsolutePath);
                ReponseLines.Add(string.Format(" \"{0}\"", InputFile.AbsolutePath));
                LinkAction.PrerequisiteItems.Add(InputFile);
            }

            if (!LinkEnvironment.Config.bIsBuildingLibrary)
            {
                // Make sure ThirdParty libs are at the end.
                List <string> ThirdParty = (from Lib in LinkEnvironment.Config.AdditionalLibraries
                                            where Lib.Contains("ThirdParty")
                                            select Lib).ToList();

                LinkEnvironment.Config.AdditionalLibraries.RemoveAll(Element => Element.Contains("ThirdParty"));
                LinkEnvironment.Config.AdditionalLibraries.AddRange(ThirdParty);

                foreach (string InputFile in LinkEnvironment.Config.AdditionalLibraries)
                {
                    FileItem Item = FileItem.GetItemByPath(InputFile);

                    if (Item.AbsolutePath.Contains(".lib"))
                    {
                        continue;
                    }

                    if (Item != null)
                    {
                        if (Item.ToString().Contains(".js"))
                        {
                            ReponseLines.Add(string.Format(" --js-library \"{0}\"", Item.AbsolutePath));
                        }
                        else
                        {
                            ReponseLines.Add(string.Format(" \"{0}\"", Item.AbsolutePath));
                        }
                        LinkAction.PrerequisiteItems.Add(Item);
                    }
                }
            }
            // make the file we will create


            OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.Config.OutputFilePath);
            LinkAction.ProducedItems.Add(OutputFile);
            ReponseLines.Add(string.Format(" -o \"{0}\"", OutputFile.AbsolutePath));

            FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath.FullName.Replace(".js", ".bc").Replace(".html", ".bc"));

            LinkAction.ProducedItems.Add(OutputBC);
            ReponseLines.Add(" --emit-symbol-map " + string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath));

            LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath);

            FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);


            LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFile.Create(ResponseFileName, ReponseLines));

            LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);

            return(OutputFile);
        }
Example #11
0
        public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List <FileItem> RCFiles)
        {
            var EnvVars = VCEnvironment.SetEnvironment(Environment.Config.Target.Platform);

            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   = Path.GetFullPath(".");
                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.GetItemByPath(
                    Path.Combine(
                        Environment.Config.OutputDirectory,
                        Path.GetFileName(RCFile.AbsolutePath) + ".res"
                        )
                    );
                CompileAction.ProducedItems.Add(CompiledResourceFile);
                CompileAction.CommandArguments += string.Format(" /fo \"{0}\"", CompiledResourceFile.AbsolutePath);
                Result.ObjectFiles.Add(CompiledResourceFile);

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

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

            return(Result);
        }
Example #12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ProjectFile"></param>
        /// <param name="Executable"></param>
        /// <param name="StageDirectory"></param>
        /// <param name="PlatformType"></param>
        public static void GenerateAssetCatalog(FileReference ProjectFile, string Executable, string StageDirectory, UnrealTargetPlatform PlatformType)
        {
            // Initialize the toolchain.
            IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(PlatformType)).ReadProjectSettings(null);
            IOSToolChain       ToolChain       = new IOSToolChain(ProjectFile, ProjectSettings);

            // Determine whether the user has modified icons that require a remote Mac to build.
            CppPlatform Platform         = PlatformType == UnrealTargetPlatform.IOS ? CppPlatform.IOS : CppPlatform.TVOS;
            bool        bUserImagesExist = false;

            ToolChain.GenerateAssetCatalog(Platform, ref bUserImagesExist);

            // Don't attempt to do anything remotely if the user is using the default UE4 images.
            if (!bUserImagesExist)
            {
                return;
            }

            // Also don't attempt to use a remote Mac if packaging for TVOS on PC.
            if (Platform == CppPlatform.TVOS && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                return;
            }

            // Save off the current bUseRPCUtil setting to restore at the end of this function.
            // At this time, iPhonePackager needs to be called with bUseRPCUtil == true.
            bool bSaveUseRPCUtil = RemoteToolChain.bUseRPCUtil;

            // Initialize the remote calling environment, taking into account the user's SSH setting.
            ToolChain.SetUpGlobalEnvironment(false);

            // Build the asset catalog ActionGraph.
            ActionGraph     ActionGraph = new ActionGraph();
            List <FileItem> OutputFiles = new List <FileItem>();

            ToolChain.CompileAssetCatalog(FileItem.GetItemByPath(Executable), Platform, ActionGraph, OutputFiles);

            ActionGraph.FinalizeActionGraph();

            // I'm not sure how to derive the UE4Game and Development arguments programmatically.
            string[] Arguments = new string[] { "UE4Game", (PlatformType == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "Development", "-UniqueBuildEnvironment" };

            // Perform all of the setup necessary to actually execute the ActionGraph instance.
            ReadOnlyBuildVersion Version        = new ReadOnlyBuildVersion(BuildVersion.ReadDefault());
            List <string[]>      TargetSettings = new List <string[]>();

            TargetSettings.Add(Arguments);
            var Targets = new List <UEBuildTarget>();
            Dictionary <UEBuildTarget, CPPHeaders> TargetToHeaders = new Dictionary <UEBuildTarget, CPPHeaders>();
            List <TargetDescriptor> TargetDescs = new List <TargetDescriptor>();

            foreach (string[] TargetSetting in TargetSettings)
            {
                TargetDescs.AddRange(TargetDescriptor.ParseCommandLine(TargetSetting, ref ProjectFile));
            }
            foreach (TargetDescriptor TargetDesc in TargetDescs)
            {
                UEBuildTarget Target = UEBuildTarget.CreateTarget(TargetDesc, Arguments, false, Version);
                if (Target == null)
                {
                    continue;
                }
                Targets.Add(Target);
                TargetToHeaders.Add(Target, null);
            }

            bool bIsRemoteCompile = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac;

            // Create the build configuration object, and read the settings
            BuildConfiguration BuildConfiguration = new BuildConfiguration();

            XmlConfig.ApplyTo(BuildConfiguration);
            CommandLine.ParseArguments(Arguments, BuildConfiguration);
            BuildConfiguration.bUseUBTMakefiles = false;

            Action[] PrerequisiteActions;
            {
                HashSet <Action> PrerequisiteActionsSet = new HashSet <Action>();
                foreach (FileItem OutputFile in OutputFiles)
                {
                    ActionGraph.GatherPrerequisiteActions(OutputFile, ref PrerequisiteActionsSet);
                }
                PrerequisiteActions = PrerequisiteActionsSet.ToArray();
            }

            // Copy any asset catalog files to the remote Mac, if necessary.
            foreach (UEBuildTarget Target in Targets)
            {
                UEBuildPlatform.GetBuildPlatform(Target.Platform).PreBuildSync();
            }

            // Begin execution of the ActionGraph.
            Dictionary <UEBuildTarget, List <FileItem> > TargetToOutdatedPrerequisitesMap;
            List <Action> ActionsToExecute = ActionGraph.GetActionsToExecute(BuildConfiguration, PrerequisiteActions, Targets, TargetToHeaders, true, true, out TargetToOutdatedPrerequisitesMap);
            string        ExecutorName     = "Unknown";
            bool          bSuccess         = ActionGraph.ExecuteActions(BuildConfiguration, ActionsToExecute, bIsRemoteCompile, out ExecutorName, "", EHotReload.Disabled);

            if (bSuccess)
            {
                if (bIsRemoteCompile)
                {
                    // Copy the remotely built AssetCatalog directory locally.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string   RemoteDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        FileItem LocalExecutable = ToolChain.RemoteToLocalFileItem(FileItem.GetItemByPath(Executable));
                        string   LocalDirectory  = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(LocalExecutable.AbsolutePath), "AssetCatalog");
                        LocalDirectory = StageDirectory;
                        RPCUtilHelper.CopyDirectory(RemoteDirectory, LocalDirectory, RPCUtilHelper.ECopyOptions.DoNotReplace);
                    }
                }
                else
                {
                    // Copy the built AssetCatalog directory to the StageDirectory.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string SourceDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        System.IO.DirectoryInfo SourceDirectoryInfo = new System.IO.DirectoryInfo(SourceDirectory);
                        if (!System.IO.Directory.Exists(StageDirectory))
                        {
                            System.IO.Directory.CreateDirectory(StageDirectory);
                        }
                        System.IO.FileInfo[] SourceFiles = SourceDirectoryInfo.GetFiles();
                        foreach (System.IO.FileInfo SourceFile in SourceFiles)
                        {
                            string DestinationPath = System.IO.Path.Combine(StageDirectory, SourceFile.Name);
                            SourceFile.CopyTo(DestinationPath, true);
                        }
                    }
                }
            }

            // Restore the former bUseRPCUtil setting.
            RemoteToolChain.bUseRPCUtil = bSaveUseRPCUtil;
        }
Example #13
0
        /// <summary>
        /// Writes an action to a json file
        /// </summary>
        /// <param name="Object">The object to parse</param>
        public static Action ImportJson(JsonObject Object)
        {
            Action Action = new Action(Object.GetEnumField <ActionType>("Type"));

            string WorkingDirectory;

            if (Object.TryGetStringField("WorkingDirectory", out WorkingDirectory))
            {
                Action.WorkingDirectory = new DirectoryReference(WorkingDirectory);
            }

            string CommandPath;

            if (Object.TryGetStringField("CommandPath", out CommandPath))
            {
                Action.CommandPath = new FileReference(CommandPath);
            }

            string CommandArguments;

            if (Object.TryGetStringField("CommandArguments", out CommandArguments))
            {
                Action.CommandArguments = CommandArguments;
            }

            string CommandDescription;

            if (Object.TryGetStringField("CommandDescription", out CommandDescription))
            {
                Action.CommandDescription = CommandDescription;
            }

            string StatusDescription;

            if (Object.TryGetStringField("StatusDescription", out StatusDescription))
            {
                Action.StatusDescription = StatusDescription;
            }

            bool bPrintDebugInfo;

            if (Object.TryGetBoolField("bPrintDebugInfo", out bPrintDebugInfo))
            {
                Action.bPrintDebugInfo = bPrintDebugInfo;
            }

            bool bCanExecuteRemotely;

            if (Object.TryGetBoolField("bCanExecuteRemotely", out bCanExecuteRemotely))
            {
                Action.bCanExecuteRemotely = bCanExecuteRemotely;
            }

            bool bCanExecuteRemotelyWithSNDBS;

            if (Object.TryGetBoolField("bCanExecuteRemotelyWithSNDBS", out bCanExecuteRemotelyWithSNDBS))
            {
                Action.bCanExecuteRemotelyWithSNDBS = bCanExecuteRemotelyWithSNDBS;
            }

            bool bIsGCCCompiler;

            if (Object.TryGetBoolField("bIsGCCCompiler", out bIsGCCCompiler))
            {
                Action.bIsGCCCompiler = bIsGCCCompiler;
            }

            bool bShouldOutputStatusDescription;

            if (Object.TryGetBoolField("bShouldOutputStatusDescription", out bShouldOutputStatusDescription))
            {
                Action.bShouldOutputStatusDescription = bShouldOutputStatusDescription;
            }

            bool bProducesImportLibrary;

            if (Object.TryGetBoolField("bProducesImportLibrary", out bProducesImportLibrary))
            {
                Action.bProducesImportLibrary = bProducesImportLibrary;
            }

            string[] PrerequisiteItems;
            if (Object.TryGetStringArrayField("PrerequisiteItems", out PrerequisiteItems))
            {
                Action.PrerequisiteItems.AddRange(PrerequisiteItems.Select(x => FileItem.GetItemByPath(x)));
            }

            string[] ProducedItems;
            if (Object.TryGetStringArrayField("ProducedItems", out ProducedItems))
            {
                Action.ProducedItems.AddRange(ProducedItems.Select(x => FileItem.GetItemByPath(x)));
            }

            string[] DeleteItems;
            if (Object.TryGetStringArrayField("DeleteItems", out DeleteItems))
            {
                Action.DeleteItems.AddRange(DeleteItems.Select(x => FileItem.GetItemByPath(x)));
            }

            string DependencyListFile;

            if (Object.TryGetStringField("DependencyListFile", out DependencyListFile))
            {
                Action.DependencyListFile = FileItem.GetItemByPath(DependencyListFile);
            }

            return(Action);
        }
Example #14
0
        /// <summary>
        /// Checks to see if the assembly needs compilation
        /// </summary>
        /// <param name="SourceFiles">Set of source files</param>
        /// <param name="AssemblySourceListFilePath">File to use to cache source file names</param>
        /// <param name="OutputAssemblyPath">Output path for the assembly</param>
        /// <returns>True if the assembly needs to be built</returns>
        private static bool RequiresCompilation(HashSet <FileReference> SourceFiles, FileReference AssemblySourceListFilePath, FileReference OutputAssemblyPath)
        {
            // Check to see if we already have a compiled assembly file on disk
            FileItem OutputAssemblyInfo = FileItem.GetItemByFileReference(OutputAssemblyPath);

            if (!OutputAssemblyInfo.Exists)
            {
                Log.TraceLog("Compiling {0}: Assembly does not exist", OutputAssemblyPath);
                return(true);
            }

            // Check the time stamp of the UnrealBuildTool.exe file.  If Unreal Build Tool was compiled more
            // recently than the dynamically-compiled assembly, then we'll always recompile it.  This is
            // because Unreal Build Tool's code may have changed in such a way that invalidate these
            // previously-compiled assembly files.
            FileItem ExecutableItem = FileItem.GetItemByFileReference(UnrealBuildTool.GetUBTPath());

            if (ExecutableItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc)
            {
                Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, ExecutableItem.Name);
                return(true);
            }

            // Make sure we have a manifest of source files used to compile the output assembly.  If it doesn't exist
            // for some reason (not an expected case) then we'll need to recompile.
            FileItem AssemblySourceListFile = FileItem.GetItemByFileReference(AssemblySourceListFilePath);

            if (!AssemblySourceListFile.Exists)
            {
                Log.TraceLog("Compiling {0}: Missing source file list ({1})", OutputAssemblyPath, AssemblySourceListFilePath);
                return(true);
            }

            // Make sure the source files we're compiling are the same as the source files that were compiled
            // for the assembly that we want to load
            HashSet <FileItem> CurrentSourceFileItems = new HashSet <FileItem>();

            foreach (string Line in FileReference.ReadAllLines(AssemblySourceListFile.Location))
            {
                CurrentSourceFileItems.Add(FileItem.GetItemByPath(Line));
            }

            // Get the new source files
            HashSet <FileItem> SourceFileItems = new HashSet <FileItem>();

            foreach (FileReference SourceFile in SourceFiles)
            {
                SourceFileItems.Add(FileItem.GetItemByFileReference(SourceFile));
            }

            // Check if there are any differences between the sets
            foreach (FileItem CurrentSourceFileItem in CurrentSourceFileItems)
            {
                if (!SourceFileItems.Contains(CurrentSourceFileItem))
                {
                    Log.TraceLog("Compiling {0}: Removed source file ({1})", OutputAssemblyPath, AssemblySourceListFilePath);
                    return(true);
                }
            }
            foreach (FileItem SourceFileItem in SourceFileItems)
            {
                if (!CurrentSourceFileItems.Contains(SourceFileItem))
                {
                    Log.TraceLog("Compiling {0}: Added source file ({1})", OutputAssemblyPath, AssemblySourceListFilePath);
                    return(true);
                }
            }

            // Check if any of the timestamps are newer
            foreach (FileItem SourceFileItem in SourceFileItems)
            {
                if (SourceFileItem.LastWriteTimeUtc > OutputAssemblyInfo.LastWriteTimeUtc)
                {
                    Log.TraceLog("Compiling {0}: {1} is newer", OutputAssemblyPath, SourceFileItem);
                    return(true);
                }
            }

            return(false);
        }
Example #15
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);
        }
Example #16
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);
        }
Example #17
0
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
        {
            if (LinkEnvironment.Config.Target.Architecture == "-win32")
            {
                return(base.LinkFiles(LinkEnvironment, bBuildImportLibraryOnly));
            }

            FileItem OutputFile;

            // Make the final javascript file
            Action LinkAction = new Action(ActionType.Link);

            LinkAction.bCanExecuteRemotely = false;
            LinkAction.WorkingDirectory    = Path.GetFullPath(".");
            LinkAction.CommandPath         = PythonPath;
            LinkAction.CommandArguments    = EMCCPath;
            LinkAction.CommandArguments   += GetLinkArguments(LinkEnvironment);

            // Add the input files to a response file, and pass the response file on the command-line.
            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                System.Console.WriteLine("File  {0} ", InputFile.AbsolutePath);
                LinkAction.CommandArguments += string.Format(" \"{0}\"", InputFile.AbsolutePath);
                LinkAction.PrerequisiteItems.Add(InputFile);
            }
            foreach (string InputFile in LinkEnvironment.Config.AdditionalLibraries)
            {
                FileItem Item = FileItem.GetItemByPath(InputFile);

                if (Item.AbsolutePath.Contains(".lib"))
                {
                    continue;
                }

                if (Item != null)
                {
                    if (Item.ToString().Contains(".js"))
                    {
                        LinkAction.CommandArguments += string.Format(" --js-library \"{0}\"", Item.AbsolutePath);
                    }
                    else
                    {
                        LinkAction.CommandArguments += string.Format(" \"{0}\"", Item.AbsolutePath);
                    }
                    LinkAction.PrerequisiteItems.Add(Item);
                }
            }
            // make the file we will create
            OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath);
            LinkAction.ProducedItems.Add(OutputFile);
            LinkAction.CommandArguments += string.Format(" -o \"{0}\"", OutputFile.AbsolutePath);

            FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath.Replace(".js", ".bc").Replace(".html", ".bc"));

            LinkAction.ProducedItems.Add(OutputBC);
            LinkAction.CommandArguments += string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath);

            LinkAction.StatusDescription  = Path.GetFileName(OutputFile.AbsolutePath);
            LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);

            return(OutputFile);
        }
Example #18
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);
        }
Example #19
0
        /** Creates an action to archive all the .o files into single .a file */
        public FileItem CreateArchiveAndIndex(LinkEnvironment LinkEnvironment)
        {
            // Create an archive action
            Action ArchiveAction = new Action(ActionType.Link);

            ArchiveAction.WorkingDirectory = Path.GetFullPath(".");
            bool bUsingSh = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win64 && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Win32;

            if (bUsingSh)
            {
                ArchiveAction.CommandPath      = "/bin/sh";
                ArchiveAction.CommandArguments = "-c '";
            }
            else
            {
                ArchiveAction.CommandPath      = "cmd.exe";
                ArchiveAction.CommandArguments = "/c \"";
            }

            // this will produce a final library
            ArchiveAction.bProducesImportLibrary = true;

            // Add the output file as a production of the link action.
            FileItem OutputFile = FileItem.GetItemByPath(LinkEnvironment.Config.OutputFilePath);

            ArchiveAction.ProducedItems.Add(OutputFile);
            ArchiveAction.CommandDescription = "Archive";
            ArchiveAction.StatusDescription  = Path.GetFileName(OutputFile.AbsolutePath);
            ArchiveAction.CommandArguments  += string.Format("\"{0}\" {1} \"{2}\"", GetArPath(LinkEnvironment.Config.Target.Architecture), GetArchiveArguments(LinkEnvironment), OutputFile.AbsolutePath);

            // Add the input files to a response file, and pass the response file on the command-line.
            List <string> InputFileNames = new List <string>();

            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                string InputAbsolutePath = InputFile.AbsolutePath.Replace("\\", "/");
                InputFileNames.Add(string.Format("\"{0}\"", InputAbsolutePath));
                ArchiveAction.PrerequisiteItems.Add(InputFile);
                ArchiveAction.CommandArguments += string.Format(" \"{0}\"", InputAbsolutePath);
            }

            // add ranlib
            ArchiveAction.CommandArguments += string.Format(" && \"{0}\" \"{1}\"", GetRanlibPath(LinkEnvironment.Config.Target.Architecture), OutputFile.AbsolutePath);

            // Add the additional arguments specified by the environment.
            ArchiveAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
            ArchiveAction.CommandArguments.Replace("\\", "/");

            if (bUsingSh)
            {
                ArchiveAction.CommandArguments += "'";
            }
            else
            {
                ArchiveAction.CommandArguments += "\"";
            }

            // Only execute linking on the local PC.
            ArchiveAction.bCanExecuteRemotely = false;

            return(OutputFile);
        }