예제 #1
0
        /// <summary>
        /// Builds the binary.
        /// </summary>
        /// <param name="CompileEnvironment">The environment to compile the binary in</param>
        /// <param name="LinkEnvironment">The environment to link the binary in</param>
        /// <returns></returns>
        public override IEnumerable<FileItem> Build(ISTToolChain TargetToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment)
        {
            // Determine the type of binary we're linking.
            switch (Config.Type)
            {
                case STBuildBinaryType.DynamicLinkLibrary:
                    CompileEnvironment.Config.bIsBuildingDLL = true;
                    CompileEnvironment.Config.bIsBuildingLibrary = false;
                    break;
                case STBuildBinaryType.StaticLibrary:
                    CompileEnvironment.Config.bIsBuildingDLL = false;
                    CompileEnvironment.Config.bIsBuildingLibrary = true;
                    break;
                default:
                    CompileEnvironment.Config.bIsBuildingDLL = false;
                    CompileEnvironment.Config.bIsBuildingLibrary = false;
                    break;
            };

            var OutputFiles = new List<FileItem>();

            var BinaryCompileEnvironment = CompileEnvironment.DeepCopy();
            var BinaryLinkEnvironment = LinkEnvironment.DeepCopy();

            // Process each module that is linked into the binary.
            var BinaryDependencies = new List<STBuildBinary>();
            var LinkEnvironmentVisitedModules = new Dictionary<STBuildModule, bool>();

            // @Hack: This to prevent UHT from listing CoreUObject.generated.cpp as its dependency.
            // We flag the compile environment when we build UHT so that we don't need to check
            // this for each file when generating their dependencies.
            BinaryCompileEnvironment.bHackHeaderGenerator = (Target.GetAppName() == "UnrealHeaderTool");

            // @todo: This should be in some Windows code somewhere...
            // Set the original file name macro; used in PCLaunch.rc to set the binary metadata fields.
            var OriginalFilename = (Config.OriginalOutputFilePaths != null) ?
                Path.GetFileName(Config.OriginalOutputFilePaths[0]) :
                Path.GetFileName(Config.OutputFilePaths[0]);
            BinaryCompileEnvironment.Config.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"");

            foreach (var ModuleName in ModuleNames)
            {
                var Module = Target.GetModuleByName(ModuleName);

                // Compile each module.
                Log.TraceVerbose("Compile module: " + ModuleName);

                var LinkInputFiles = Module.Compile(CompileEnvironment, BinaryCompileEnvironment, Config.bCompileMonolithic);

                // NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input
                // multiple times for a single binary.  We'll check for that here, and only add it once.  This avoids
                // a linker warning about redundant .obj files.
                foreach (var LinkInputFile in LinkInputFiles)
                {
                    if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile))
                    {
                        BinaryLinkEnvironment.InputFiles.Add(LinkInputFile);
                    }
                }

                // Allow the module to modify the link environment for the binary.
                Module.SetupPrivateLinkEnvironment(ref BinaryLinkEnvironment, ref BinaryDependencies, ref LinkEnvironmentVisitedModules);
            }

            // Remove the default resource file on Windows (PCLaunch.rc) if the user has specified their own
            if (BinaryLinkEnvironment.InputFiles.Select(Item => Path.GetFileName(Item.AbsolutePath).ToLower()).Any(Name => Name.EndsWith(".res") && !Name.EndsWith(".inl.res") && Name != "pclaunch.rc.res"))
            {
                BinaryLinkEnvironment.InputFiles.RemoveAll(x => Path.GetFileName(x.AbsolutePath).ToLower() == "pclaunch.rc.res");
            }

            // Allow the binary dependencies to modify the link environment.
            foreach (var BinaryDependency in BinaryDependencies)
            {
                BinaryDependency.SetupDependentLinkEnvironment(ref BinaryLinkEnvironment);
            }

            // Set the link output file.
            BinaryLinkEnvironment.Config.OutputFilePaths = Config.OutputFilePaths != null ? (string[])Config.OutputFilePaths.Clone() : null;

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.Config.bHasExports = Config.bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.Config.IntermediateDirectory = Config.IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.Config.OutputDirectory = Path.GetDirectoryName(Config.OutputFilePaths[0]);

            // Determine the type of binary we're linking.
            switch (Config.Type)
            {
                case STBuildBinaryType.DynamicLinkLibrary:
                    BinaryLinkEnvironment.Config.bIsBuildingDLL = true;
                    BinaryLinkEnvironment.Config.bIsBuildingLibrary = false;
                    break;
                case STBuildBinaryType.StaticLibrary:
                    BinaryLinkEnvironment.Config.bIsBuildingDLL = false;
                    BinaryLinkEnvironment.Config.bIsBuildingLibrary = true;
                    break;
                default:
                    BinaryLinkEnvironment.Config.bIsBuildingDLL = false;
                    BinaryLinkEnvironment.Config.bIsBuildingLibrary = false;
                    break;
            };

            if (ProjectFileGenerator.bGenerateProjectFiles)
            {
                // We're generating projects.  Since we only need include paths and definitions, there is no need
                // to go ahead and run through the linking logic.
                OutputFiles = BinaryLinkEnvironment.InputFiles;
            }
            else if (BuildConfiguration.bEnableCodeAnalysis)
            {
                // We're only analyzing code, so we won't actually link any executables.  Instead, our output
                // files will simply be the .obj files that were compiled during static analysis.
                OutputFiles = BinaryLinkEnvironment.InputFiles;
            }
            else
            {
                if (bCreateImportLibrarySeparately)
                {
                    // Mark the link environment as cross-referenced.
                    BinaryLinkEnvironment.Config.bIsCrossReferenced = true;

                    if (BinaryLinkEnvironment.Config.Target.Platform != CPPTargetPlatform.Mac && BinaryLinkEnvironment.Config.Target.Platform != CPPTargetPlatform.Linux)
                    {
                        // Create the import library.
                        OutputFiles.AddRange(BinaryLinkEnvironment.LinkExecutable(true));
                    }
                }

                BinaryLinkEnvironment.Config.bIncludeDependentLibrariesInLibrary = bIncludeDependentLibrariesInLibrary;

                // Link the binary.
                FileItem[] Executables = BinaryLinkEnvironment.LinkExecutable(false);
                OutputFiles.AddRange(Executables);

                // Produce additional console app if requested
                if (BinaryLinkEnvironment.Config.CanProduceAdditionalConsoleApp && STBuildConfiguration.bBuildEditor)
                {
                    // Produce additional binary but link it as a console app
                    var ConsoleAppLinkEvironment = BinaryLinkEnvironment.DeepCopy();
                    ConsoleAppLinkEvironment.Config.bIsBuildingConsoleApplication = true;
                    ConsoleAppLinkEvironment.Config.WindowsEntryPointOverride = "WinMainCRTStartup";		// For WinMain() instead of "main()" for Launch module
                    for (int Index = 0; Index < Config.OutputFilePaths.Length; Index++)
                    {
                        ConsoleAppLinkEvironment.Config.OutputFilePaths[Index] = GetAdditionalConsoleAppPath(ConsoleAppLinkEvironment.Config.OutputFilePaths[Index]);
                    }

                    // Link the console app executable
                    OutputFiles.AddRange(ConsoleAppLinkEvironment.LinkExecutable(false));
                }

                foreach (var Executable in Executables)
                {
                    OutputFiles.AddRange(TargetToolChain.PostBuild(Executable, BinaryLinkEnvironment));
                }
            }

            return OutputFiles;
        }
예제 #2
0
        // STBuildModule interface.
        public override List<FileItem> Compile(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment, bool bCompileMonolithic)
        {
            var ModuleCLREnvironment = CompileEnvironment.DeepCopy();

            // Setup the module environment for the project CLR mode
            ModuleCLREnvironment.Config.CLRMode = CPPCLRMode.CLREnabled;

            // Add the private assembly references to the compile environment.
            foreach (var PrivateAssemblyReference in PrivateAssemblyReferences)
            {
                ModuleCLREnvironment.AddPrivateAssembly(PrivateAssemblyReference);
            }

            // Pass the CLR compilation environment to the standard C++ module compilation code.
            return base.Compile(GlobalCompileEnvironment, ModuleCLREnvironment, bCompileMonolithic);
        }
예제 #3
0
        /// <summary>
        /// Creates a precompiled header action to generate a new pch file 
        /// </summary>
        /// <param name="PCHHeaderNameInCode">The precompiled header name as it appeared in an #include statement</param>
        /// <param name="PrecompiledHeaderIncludeFilename">Name of the header used for pch.</param>
        /// <param name="ProjectCPPEnvironment">The environment the C/C++ files in the project are compiled with.</param>
        /// <param name="OutputDirectory">The folder to save the generated PCH file to</param>
        /// <param name="ModuleName">Name of the module this PCH is being generated for</param>
        /// <param name="bAllowDLLExports">True if we should allow DLLEXPORT definitions for this PCH</param>
        /// <returns>the compilation output result of the created pch.</returns>
        public static CPPOutput GeneratePCHCreationAction(STBuildTarget Target, string PCHHeaderNameInCode, FileItem PrecompiledHeaderIncludeFilename, CPPEnvironment ProjectCPPEnvironment, string OutputDirectory, string ModuleName, bool bAllowDLLExports)
        {
            // Find the header file to be precompiled. Don't skip external headers
            if (PrecompiledHeaderIncludeFilename.bExists)
            {
                // Create a Dummy wrapper around the PCH to avoid problems with #pragma once on clang
                var ToolChain = STToolChain.GetPlatformToolChain(ProjectCPPEnvironment.Config.Target.Platform);
                string PCHGuardDefine = Path.GetFileNameWithoutExtension(PrecompiledHeaderIncludeFilename.AbsolutePath).ToUpper();
                string LocalPCHHeaderNameInCode = ToolChain.ConvertPath(PrecompiledHeaderIncludeFilename.AbsolutePath);
                string TmpPCHHeaderContents = String.Format("#ifndef __AUTO_{0}_H__\n#define __AUTO_{0}_H__\n//Last Write: {2}\n#include \"{1}\"\n#endif//__AUTO_{0}_H__", PCHGuardDefine, LocalPCHHeaderNameInCode, PrecompiledHeaderIncludeFilename.LastWriteTime);
                string DummyPath = Path.Combine(
                    ProjectCPPEnvironment.Config.OutputDirectory,
                    Path.GetFileName(PrecompiledHeaderIncludeFilename.AbsolutePath));
                FileItem DummyPCH = FileItem.CreateIntermediateTextFile(DummyPath, TmpPCHHeaderContents);

                // Create a new C++ environment that is used to create the PCH.
                var ProjectPCHEnvironment = ProjectCPPEnvironment.DeepCopy();
                ProjectPCHEnvironment.Config.PrecompiledHeaderAction = PrecompiledHeaderAction.Create;
                ProjectPCHEnvironment.Config.PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFilename.AbsolutePath;
                ProjectPCHEnvironment.Config.PCHHeaderNameInCode = PCHHeaderNameInCode;
                ProjectPCHEnvironment.Config.OutputDirectory = OutputDirectory;

                if (!bAllowDLLExports)
                {
                    for (var CurDefinitionIndex = 0; CurDefinitionIndex < ProjectPCHEnvironment.Config.Definitions.Count; ++CurDefinitionIndex)
                    {
                        // We change DLLEXPORT to DLLIMPORT for "shared" PCH headers
                        var OldDefinition = ProjectPCHEnvironment.Config.Definitions[CurDefinitionIndex];
                        if (OldDefinition.EndsWith("=DLLEXPORT"))
                        {
                            ProjectPCHEnvironment.Config.Definitions[CurDefinitionIndex] = OldDefinition.Replace("DLLEXPORT", "DLLIMPORT");
                        }
                    }
                }

                // Cache our CPP environment so that we can check for outdatedness quickly.  Only files that have includes need this.
                DummyPCH.CachedCPPIncludeInfo = ProjectPCHEnvironment.Config.CPPIncludeInfo;

                Log.TraceVerbose("Found PCH file \"{0}\".", PrecompiledHeaderIncludeFilename);

                // Create the action to compile the PCH file.
                return ProjectPCHEnvironment.CompileFiles(Target, new List<FileItem>() { DummyPCH }, ModuleName);
            }
            throw new BuildException("Couldn't find PCH file \"{0}\".", PrecompiledHeaderIncludeFilename);
        }
예제 #4
0
        /// <summary>
        /// Creates a compile environment from a base environment based on the module settings.
        /// </summary>
        /// <param name="BaseCompileEnvironment">An existing environment to base the module compile environment on.</param>
        /// <returns>The new module compile environment.</returns>
        public CPPEnvironment CreateModuleCompileEnvironment(CPPEnvironment BaseCompileEnvironment)
        {
            var Result = BaseCompileEnvironment.DeepCopy();

            // Override compile environment
            Result.Config.bFasterWithoutUnity = bFasterWithoutUnity;
            Result.Config.OptimizeCode = OptimizeCode;
            Result.Config.bUseRTTI = bUseRTTI;
            Result.Config.bEnableBufferSecurityChecks = bEnableBufferSecurityChecks;
            Result.Config.bFasterWithoutUnity = bFasterWithoutUnity;
            Result.Config.MinFilesUsingPrecompiledHeaderOverride = MinFilesUsingPrecompiledHeaderOverride;
            Result.Config.bEnableExceptions = bEnableExceptions;
            Result.Config.bUseStaticCRT = (Target.Rules != null && Target.Rules.bUseStaticCRT);
            Result.Config.OutputDirectory = Path.Combine(Binary.Config.IntermediateDirectory, Name);

            // Switch the optimization flag if we're building a game module. Also pass the definition for building in DebugGame along (see ModuleManager.h for notes).
            if (Target.Configuration == STTargetConfiguration.DebugGame)
            {
                PluginInfo Plugin = Plugins.GetPluginInfoForModule(Name);
                if ((Plugin != null && Plugin.LoadedFrom == PluginInfo.LoadedFromType.GameProject) || Type == STBuildModuleType.Game)
                {
                    Result.Config.Target.Configuration = CPPTargetConfiguration.Debug;
                    Result.Config.Definitions.Add("UE_BUILD_DEVELOPMENT_WITH_DEBUGGAME=1");
                }
            }

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

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

            return Result;
        }