예제 #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(IUEToolChain TargetToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment)
        {
            // Determine the type of binary we're linking.
            switch (Config.Type)
            {
            case UEBuildBinaryType.DynamicLinkLibrary:
                CompileEnvironment.Config.bIsBuildingDLL     = true;
                CompileEnvironment.Config.bIsBuildingLibrary = false;
                break;

            case UEBuildBinaryType.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 <UEBuildBinary>();
            var LinkEnvironmentVisitedModules = new Dictionary <UEBuildModule, 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 UEBuildBinaryType.DynamicLinkLibrary:
                BinaryLinkEnvironment.Config.bIsBuildingDLL     = true;
                BinaryLinkEnvironment.Config.bIsBuildingLibrary = false;
                break;

            case UEBuildBinaryType.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 && UEBuildConfiguration.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
        // UEBuildModule interface.
        public override List<FileItem> Compile( CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment )
        {
            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 );
        }
예제 #3
0
        private LinkEnvironment SetupBinaryLinkEnvironment(LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment)
        {
            var BinaryLinkEnvironment         = LinkEnvironment.DeepCopy();
            var LinkEnvironmentVisitedModules = new Dictionary <UEBuildModule, bool>();
            var BinaryDependencies            = new List <UEBuildBinary>();

            CompileEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            CompileEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            var BinaryCompileEnvironment = CompileEnvironment.DeepCopy();

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

                List <FileItem> LinkInputFiles;
                if (Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + ModuleName);
                    LinkInputFiles = Module.Compile(CompileEnvironment, BinaryCompileEnvironment);

                    // 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);
                        }
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    // Allow the module to modify the link environment for the binary.
                    Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules);
                }
            }


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

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

            // Set the link output file.
            BinaryLinkEnvironment.Config.OutputFilePaths = Config.OutputFilePaths.ToList();

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

            // Setup link output type
            BinaryLinkEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            BinaryLinkEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            return(BinaryLinkEnvironment);
        }
예제 #4
0
        // UEBuildModule interface.
        public override List<FileItem> Compile(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment)
        {
            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);

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

            var ModuleCompileEnvironment = CreateModuleCompileEnvironment(CompileEnvironment);
            IncludeSearchPaths = ModuleCompileEnvironment.Config.CPPIncludeInfo.IncludePaths.ToList();
            IncludeSearchPaths.AddRange(ModuleCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.ToList());

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

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

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

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

                // Always compile in the API version resource separately. This is required for the module manager to detect compatible API versions.
                string ModuleVersionRC = Utils.CleanDirectorySeparators( Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "Runtime/Core/Resources/Windows/ModuleVersionResource.rc.inl")) );
                FileItem ModuleVersionItem = FileItem.GetItemByFullPath(ModuleVersionRC);
                if( !SourceFilesToBuild.RCFiles.Contains(ModuleVersionItem) )
                {
                    SourceFilesToBuild.RCFiles.Add(ModuleVersionItem);
                }
            }

            {
                // Process all of the header file dependencies for this module
                this.CachePCHUsageForModuleSourceFiles( ModuleCompileEnvironment );

                // Make sure our RC files have cached includes.
                foreach( var RCFile in SourceFilesToBuild.RCFiles )
                {
                    RCFile.CachedCPPIncludeInfo = ModuleCompileEnvironment.Config.CPPIncludeInfo;
                }
            }

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

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

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

            // The environment with which to compile the CPP files
            var CPPCompileEnvironment = ModuleCompileEnvironment;

            // Precompiled header support.
            bool bWasModuleCodeCompiled = false;
            if (BuildPlatform.ShouldUsePCHFiles(CompileEnvironment.Config.Target.Platform, CompileEnvironment.Config.Target.Configuration))
            {
                var PCHGenTimerStart = DateTime.UtcNow;

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

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

                if( BuildConfiguration.bUseSharedPCHs && CompileEnvironment.Config.bIsBuildingLibrary )
                {
                    Log.TraceVerbose("Module '{0}' was not allowed to use Shared PCHs, because we're compiling to a library", this.Name );
                }

                bool bUseSharedPCHFiles  = BuildConfiguration.bUseSharedPCHs && !CompileEnvironment.Config.bIsBuildingLibrary && GlobalCompileEnvironment.SharedPCHHeaderFiles.Count > 0;

                if( bUseSharedPCHFiles )
                {
                    string SharingPCHHeaderFilePath = null;
                    bool bIsASharedPCHModule = bUseSharedPCHFiles && GlobalCompileEnvironment.SharedPCHHeaderFiles.Any( PCH => PCH.Module == this );
                    if( bIsASharedPCHModule )
                    {
                        SharingPCHHeaderFilePath = Path.GetFullPath( Path.Combine( ProjectFileGenerator.RootRelativePath, "Engine", "Source", this.SharedPCHHeaderFile ) );
                    }

                    // We can't use a shared PCH file when compiling a module
                    // with exports, because the shared PCH can only have imports in it to work correctly.
                    bool bCanModuleUseOwnSharedPCH = bAllowSharedPCH && bIsASharedPCHModule && !Binary.Config.bAllowExports && ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath.Equals( SharingPCHHeaderFilePath, StringComparison.InvariantCultureIgnoreCase );
                    if( bAllowSharedPCH && ( !bIsASharedPCHModule || bCanModuleUseOwnSharedPCH ) )
                    {
                        // Figure out which shared PCH tier we're in
                        var ReferencedModules = new CaselessDictionary<ModuleIndexPair>();
                        {
                            this.GetAllDependencyModules( ReferencedModules, bIncludeDynamicallyLoaded:false, bForceCircular:false, bOnlyDirectDependencies:true );
                        }

                        int LargestSharedPCHHeaderFileIndex = -1;
                        foreach( var DependencyModule in ReferencedModules.Values.OrderBy(P => P.Index).Select(P => P.Module) )
                        {
                            // These Shared PCHs are ordered from least complex to most complex.  We'll start at the last one and search backwards.
                            for( var SharedPCHHeaderFileIndex = GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1; SharedPCHHeaderFileIndex > LargestSharedPCHHeaderFileIndex; --SharedPCHHeaderFileIndex )
                            {
                                var CurSharedPCHHeaderFile = GlobalCompileEnvironment.SharedPCHHeaderFiles[ SharedPCHHeaderFileIndex ];

                                if( DependencyModule == CurSharedPCHHeaderFile.Module ||
                                    ( bIsASharedPCHModule && CurSharedPCHHeaderFile.Module == this ) )	// If we ourselves are a shared PCH module, always at least use our own module as our shared PCH header if we can't find anything better
                                {
                                    SharedPCHModuleName = CurSharedPCHHeaderFile.Module.Name;
                                    SharedPCHHeaderFile = CurSharedPCHHeaderFile.PCHHeaderFile;
                                    LargestSharedPCHHeaderFileIndex = SharedPCHHeaderFileIndex;
                                    break;
                                }
                            }

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

                        // Did we not find a shared PCH header that is being included by this module?  This could happen if the module is not including Core.h, even indirectly.
                        if( String.IsNullOrEmpty( SharedPCHModuleName ) )
                        {
                            throw new BuildException( "Module {0} doesn't use a Shared PCH!  Please add a dependency on a Shared PCH module to this module's dependency list", this.Name);
                        }

                        // Keep track of how many modules make use of this PCH for performance diagnostics
                        var LargestSharedPCHHeader = GlobalCompileEnvironment.SharedPCHHeaderFiles[ LargestSharedPCHHeaderFileIndex ];
                        ++LargestSharedPCHHeader.NumModulesUsingThisPCH;

                    }
                    else
                    {
                        Log.TraceVerbose("Module '{0}' cannot create or use Shared PCHs, because it needs its own private PCH", this.Name);
                    }
                }

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

                // If there was one header that was included first by enough C++ files, use it as the precompiled header.
                // Only use precompiled headers for projects with enough files to make the PCH creation worthwhile.
                if( SharedPCHHeaderFile != null || SourceFilesToBuild.CPPFiles.Count >= MinFilesUsingPrecompiledHeader )
                {
                    FileItem PCHToUse;

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

                        PCHToUse = SharedPCHHeaderFile;
                    }
                    else
                    {
                        PCHToUse = ProcessedDependencies.UniquePCHHeaderFile;
                    }

                    if (PCHToUse != null)
                    {
                        // Update all CPPFiles to point to the PCH
                        foreach (var CPPFile in SourceFilesToBuild.CPPFiles)
                        {
                            CPPFile.PCHHeaderNameInCode              = PCHToUse.AbsolutePath;
                            CPPFile.PrecompiledHeaderIncludeFilename = PCHToUse.AbsolutePath;
                        }
                    }

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

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

                        if( SharedPCHHeaderFile != null )
                        {
                            // Add to list of shared PCH environments
                            GlobalCompileEnvironment.SharedPCHEnvironments.Add( ModulePCHEnvironment );
                            Log.TraceVerbose( "Module " + Name + " uses new Shared PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'" );
                        }
                        else
                        {
                            Log.TraceVerbose( "Module " + Name + " uses a Unique PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'" );
                        }
                    }
                }
                else
                {
                    Log.TraceVerbose( "Module " + Name + " doesn't use a Shared PCH, and only has " + SourceFilesToBuild.CPPFiles.Count.ToString() + " source file(s).  No Unique PCH will be generated." );
                }

                // Compile the C++ source or the unity C++ files that use a PCH environment.
                if( ModulePCHEnvironment != null )
                {
                    // Setup a new compile environment for this module's source files.  It's pretty much the exact same as the
                    // module's compile environment, except that it will include a PCH file.

                    var ModulePCHCompileEnvironment = ModuleCompileEnvironment.DeepCopy();
                    ModulePCHCompileEnvironment.Config.PrecompiledHeaderAction          = PrecompiledHeaderAction.Include;
                    ModulePCHCompileEnvironment.Config.PrecompiledHeaderIncludeFilename = ModulePCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath;
                    ModulePCHCompileEnvironment.Config.PCHHeaderNameInCode              = ModulePCHEnvironment.PCHHeaderNameInCode;

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

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

                    // Check if there are enough unity files to warrant pch generation (and we haven't already generated the shared one)
                    if( ModulePCHEnvironment.PrecompiledHeaderFile == null )
                    {
                        if( SharedPCHHeaderFile != null || CPPFilesToBuild.Count >= MinFilesUsingPrecompiledHeader )
                        {
                            CPPOutput PCHOutput;
                            if (SharedPCHHeaderFile == null)
                            {
                                PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction(
                                    Target,
                                    CPPFilesToBuild[0].PCHHeaderNameInCode,
                                    ModulePCHEnvironment.PrecompiledHeaderIncludeFilename,
                                    ModuleCompileEnvironment,
                                    ModuleCompileEnvironment.Config.OutputDirectory,
                                    Name,
                                    true );
                            }
                            else
                            {
                                UEBuildModuleCPP SharedPCHModule = (UEBuildModuleCPP)Target.FindOrCreateModuleByName(SharedPCHModuleName);

                                CPPEnvironment SharedPCHCompileEnvironment = GlobalCompileEnvironment.DeepCopy();
                                SharedPCHCompileEnvironment.Config.bEnableShadowVariableWarning = SharedPCHModule.bEnableShadowVariableWarnings;

                                SharedPCHModule.SetupPublicCompileEnvironment(
                                    Binary,
                                    false,
                                    SharedPCHCompileEnvironment.Config.CPPIncludeInfo.IncludePaths,
                                    SharedPCHCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths,
                                    SharedPCHCompileEnvironment.Config.Definitions,
                                    SharedPCHCompileEnvironment.Config.AdditionalFrameworks,
                                    new Dictionary<UEBuildModule,bool>());

                                PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction(
                                    Target,
                                    CPPFilesToBuild[0].PCHHeaderNameInCode,
                                    ModulePCHEnvironment.PrecompiledHeaderIncludeFilename,
                                    SharedPCHCompileEnvironment,
                                    Path.Combine( CompileEnvironment.Config.OutputDirectory, "SharedPCHs" ),
                                    "Shared",
                                    false );
                            }

                            ModulePCHEnvironment.PrecompiledHeaderFile = PCHOutput.PrecompiledHeaderFile;

                            ModulePCHEnvironment.OutputObjectFiles.Clear();
                            ModulePCHEnvironment.OutputObjectFiles.AddRange( PCHOutput.ObjectFiles );
                        }
                        else if( CPPFilesToBuild.Count < MinFilesUsingPrecompiledHeader )
                        {
                            Log.TraceVerbose( "Module " + Name + " doesn't use a Shared PCH, and only has " + CPPFilesToBuild.Count.ToString() + " unity source file(s).  No Unique PCH will be generated." );
                        }
                    }

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

                        // if pch action was generated for the environment then use pch
                        ModulePCHCompileEnvironment.PrecompiledHeaderFile = ModulePCHEnvironment.PrecompiledHeaderFile;

                        // Use this compile environment from now on
                        CPPCompileEnvironment = ModulePCHCompileEnvironment;
                    }

                    LinkInputFiles.AddRange( CPPCompileEnvironment.CompileFiles( Target, CPPFilesToBuild, Name ).ObjectFiles );
                    bWasModuleCodeCompiled = true;
                }

                if( BuildConfiguration.bPrintPerformanceInfo )
                {
                    var PCHGenTime = ( DateTime.UtcNow - PCHGenTimerStart ).TotalSeconds;
                    TotalPCHGenTime += PCHGenTime;
                }
            }

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

            if (AutoGenerateCppInfo != null && AutoGenerateCppInfo.BuildInfo != null && !CPPCompileEnvironment.bHackHeaderGenerator)
            {
                string[] GeneratedFiles = Directory.GetFiles(Path.GetDirectoryName(AutoGenerateCppInfo.BuildInfo.FileWildcard), Path.GetFileName(AutoGenerateCppInfo.BuildInfo.FileWildcard));
                foreach (string GeneratedFilename in GeneratedFiles)
                {
                    var GeneratedCppFileItem = FileItem.GetItemByPath(GeneratedFilename);

                    CachePCHUsageForModuleSourceFile(this.Target, CPPCompileEnvironment, GeneratedCppFileItem);

                    // @todo ubtmake: Check for ALL other places where we might be injecting .cpp or .rc files for compiling without caching CachedCPPIncludeInfo first (anything platform specific?)
                    LinkInputFiles.AddRange(CPPCompileEnvironment.CompileFiles(Target, new List<FileItem> { GeneratedCppFileItem }, Name).ObjectFiles);
                }
            }

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

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

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

            // Compile RC files.
            LinkInputFiles.AddRange(CPPCompileEnvironment.CompileRCFiles(Target, SourceFilesToBuild.RCFiles).ObjectFiles);

            return LinkInputFiles;
        }
예제 #5
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.bUseAVX                                = bUseAVX;
            Result.Config.bEnableBufferSecurityChecks            = bEnableBufferSecurityChecks;
            Result.Config.bFasterWithoutUnity                    = bFasterWithoutUnity;
            Result.Config.MinFilesUsingPrecompiledHeaderOverride = MinFilesUsingPrecompiledHeaderOverride;
            Result.Config.bBuildLocallyWithSNDBS				 = bBuildLocallyWithSNDBS;
            Result.Config.bEnableExceptions                      = bEnableExceptions;
            Result.Config.bEnableShadowVariableWarning          = bEnableShadowVariableWarnings;
            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 == UnrealTargetConfiguration.DebugGame)
            {
                if(!Utils.IsFileUnderDirectory(ModuleDirectory, BuildConfiguration.RelativeEnginePath))
                {
                    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(Result.Config.CPPIncludeInfo.IncludePaths, Result.Config.CPPIncludeInfo.SystemIncludePaths, Result.Config.Definitions, Result.Config.AdditionalFrameworks);

            // @hack to skip adding definitions to compile environment, they will be baked into source code files
            if (bSkipDefinitionsForCompileEnvironment)
            {
                Result.Config.Definitions.Clear();
                Result.Config.CPPIncludeInfo.IncludePaths = new HashSet<string>(BaseCompileEnvironment.Config.CPPIncludeInfo.IncludePaths);
            }

            return Result;
        }
예제 #6
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(UEBuildTarget 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 = UEToolChain.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 );
        }
예제 #7
0
파일: UEBuildBinary.cs 프로젝트: mymei/UE4
        private LinkEnvironment SetupBinaryLinkEnvironment(LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment)
        {
            var BinaryLinkEnvironment = LinkEnvironment.DeepCopy();
            var LinkEnvironmentVisitedModules = new Dictionary<UEBuildModule, bool>();
            var BinaryDependencies = new List<UEBuildBinary>();
            CompileEnvironment.Config.bIsBuildingDLL = IsBuildingDll(Config.Type);
            CompileEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            var BinaryCompileEnvironment = CompileEnvironment.DeepCopy();
            // @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);

                List<FileItem> LinkInputFiles;
                if(Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + ModuleName);
                    LinkInputFiles = Module.Compile(CompileEnvironment, BinaryCompileEnvironment);

                    // 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);
                        }
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    // Allow the module to modify the link environment for the binary.
                    Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules);
                }
            }

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

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

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

            // Setup link output type
            BinaryLinkEnvironment.Config.bIsBuildingDLL = IsBuildingDll(Config.Type);
            BinaryLinkEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            return BinaryLinkEnvironment;
        }
예제 #8
0
        private LinkEnvironment SetupBinaryLinkEnvironment(UEBuildTarget Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            LinkEnvironment         BinaryLinkEnvironment         = LinkEnvironment.DeepCopy();
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CompileEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            CompileEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            CPPEnvironment BinaryCompileEnvironment = CompileEnvironment.DeepCopy();

            // @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.
            string OriginalFilename = (Config.OriginalOutputFilePaths != null) ?
                                      Config.OriginalOutputFilePaths[0].GetFileName() :
                                      Config.OutputFilePaths[0].GetFileName();

            BinaryCompileEnvironment.Config.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"");

            foreach (UEBuildModule Module in Modules)
            {
                List <FileItem> LinkInputFiles;
                if (Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + Module.Name);
                    LinkInputFiles = Module.Compile(Target, ToolChain, BinaryCompileEnvironment, SharedPCHs, ActionGraph);

                    // 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 (FileItem LinkInputFile in LinkInputFiles)
                    {
                        if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile))
                        {
                            BinaryLinkEnvironment.InputFiles.Add(LinkInputFile);
                        }
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    // Allow the module to modify the link environment for the binary.
                    Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules);
                }
            }


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

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

            // Set the link output file.
            BinaryLinkEnvironment.Config.OutputFilePaths = Config.OutputFilePaths.ToList();

            // 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 = Config.OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            BinaryLinkEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            BinaryLinkEnvironment.Config.ProjectFile = Target.ProjectFile;

            // Add the default resources for dlls
            if (Config.Type == UEBuildBinaryType.DynamicLinkLibrary)
            {
                // Check if there's already a custom resource file
                if (!BinaryLinkEnvironment.InputFiles.Any(x => x.Reference.HasExtension(".res")))
                {
                    if (UEBuildConfiguration.bFormalBuild)
                    {
                        // For formal builds, compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        CPPEnvironment BinaryResourceCompileEnvironment = BinaryCompileEnvironment.DeepCopy();
                        BinaryResourceCompileEnvironment.Config.OutputDirectory = DirectoryReference.Combine(BinaryResourceCompileEnvironment.Config.OutputDirectory, Modules.First().Name);
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(BinaryResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ActionGraph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                    else
                    {
                        // For non-formal builds, we just want to share the default resource file between modules
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                }

                // Add all the common resource files
                BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);
            }

            return(BinaryLinkEnvironment);
        }
예제 #9
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(UEBuildTarget Target, CPPEnvironment BaseCompileEnvironment)
		{
			CPPEnvironment Result = BaseCompileEnvironment.DeepCopy();

            if (Binary == null)
            {
                // Adding this check here as otherwise the call to Binary.Config.IntermediateDirectory will give an 
                // unhandled exception
                throw new BuildException("UEBuildBinary not set up for module {0}", this.ToString());
            }

			// Override compile environment
			Result.Config.bFasterWithoutUnity = Rules.bFasterWithoutUnity;
			Result.Config.OptimizeCode = Rules.OptimizeCode;
			Result.Config.bUseRTTI = Rules.bUseRTTI;
			Result.Config.bUseAVX = Rules.bUseAVX;
			Result.Config.bEnableBufferSecurityChecks = Rules.bEnableBufferSecurityChecks;
			Result.Config.MinSourceFilesForUnityBuildOverride = Rules.MinSourceFilesForUnityBuildOverride;
			Result.Config.MinFilesUsingPrecompiledHeaderOverride = Rules.MinFilesUsingPrecompiledHeaderOverride;
			Result.Config.bBuildLocallyWithSNDBS = Rules.bBuildLocallyWithSNDBS;
			Result.Config.bEnableExceptions = Rules.bEnableExceptions;
			Result.Config.bEnableShadowVariableWarning = Rules.bEnableShadowVariableWarnings;
			Result.Config.bUseStaticCRT = (Target.Rules != null && Target.Rules.bUseStaticCRT);
			Result.Config.OutputDirectory = DirectoryReference.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 == UnrealTargetConfiguration.DebugGame)
			{
				if (!ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory))
				{
					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(Result.Config.CPPIncludeInfo.IncludePaths, Result.Config.CPPIncludeInfo.SystemIncludePaths, Result.Config.Definitions, Result.Config.AdditionalFrameworks);

			// @hack to skip adding definitions to compile environment, they will be baked into source code files
			if (bSkipDefinitionsForCompileEnvironment)
			{
				Result.Config.Definitions.Clear();
				Result.Config.CPPIncludeInfo.IncludePaths = new HashSet<string>(BaseCompileEnvironment.Config.CPPIncludeInfo.IncludePaths);
			}

			return Result;
		}
예제 #10
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 == UnrealTargetConfiguration.DebugGame)
            {
                PluginInfo Plugin = Plugins.GetPluginInfoForModule(Name);
                if((Plugin != null && Plugin.LoadedFrom == PluginInfo.LoadedFromType.GameProject) || Type == UEBuildModuleType.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);

            // @hack to skip adding definitions to compile environment, they will be baked into source code files
            if (bSkipDefinitionsForCompileEnvironment)
            {
                Result.Config.Definitions.Clear();
                Result.Config.CPPIncludeInfo.IncludePaths = new HashSet<string>(BaseCompileEnvironment.Config.CPPIncludeInfo.IncludePaths);
            }

            return Result;
        }