protected void AddPrerequisiteSourceFile(UEBuildTarget Target, IUEBuildPlatform BuildPlatform, CPPEnvironment CompileEnvironment, FileItem SourceFile, List <FileItem> PrerequisiteItems) { PrerequisiteItems.Add(SourceFile); var RemoteThis = this as RemoteToolChain; bool bAllowUploading = RemoteThis != null && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac; // Don't use remote features when compiling from a Mac if (bAllowUploading) { RemoteThis.QueueFileForBatchUpload(SourceFile); } if (!BuildConfiguration.bUseExperimentalFastBuildIteration) // In fast build iteration mode, we'll gather includes later on { // @todo fastubt: What if one of the prerequisite files has become missing since it was updated in our cache? (usually, because a coder eliminated the source file) // -> Two CASES: // 1) NOT WORKING: Non-unity file went away (SourceFile in this context). That seems like an existing old use case. Compile params or Response file should have changed? // 2) WORKING: Indirect file went away (unity'd original source file or include). This would return a file that no longer exists and adds to the prerequiteitems list var IncludedFileList = CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CompileEnvironment.Config.CPPIncludeInfo, bOnlyCachedDependencies: BuildConfiguration.bUseExperimentalFastDependencyScan); foreach (FileItem IncludedFile in IncludedFileList) { PrerequisiteItems.Add(IncludedFile); if (bAllowUploading && !BuildConfiguration.bUseExperimentalFastDependencyScan) // With fast dependency scanning, we will not have an exhaustive list of dependencies here. We rely on PostCodeGeneration() to upload these files. { RemoteThis.QueueFileForBatchUpload(IncludedFile); } } } }
/// <summary> /// Setup the configuration environment for building /// </summary> /// <param name="InBuildTarget"> The target being built</param> public override void SetUpConfigurationEnvironment(TargetInfo Target, CPPEnvironment GlobalCompileEnvironment, LinkEnvironment GlobalLinkEnvironment) { // Determine the C++ compile/link configuration based on the Unreal configuration. CPPTargetConfiguration CompileConfiguration; //@todo SAS: Add a true Debug mode! UnrealTargetConfiguration CheckConfig = Target.Configuration; switch (CheckConfig) { default: case UnrealTargetConfiguration.Debug: CompileConfiguration = CPPTargetConfiguration.Debug; if (BuildConfiguration.bDebugBuildsActuallyUseDebugCRT) { GlobalCompileEnvironment.Config.Definitions.Add("_DEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does } else { GlobalCompileEnvironment.Config.Definitions.Add("NDEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does } GlobalCompileEnvironment.Config.Definitions.Add("UE_BUILD_DEBUG=1"); break; case UnrealTargetConfiguration.DebugGame: // Default to Development; can be overridden by individual modules. case UnrealTargetConfiguration.Development: CompileConfiguration = CPPTargetConfiguration.Development; GlobalCompileEnvironment.Config.Definitions.Add("NDEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does GlobalCompileEnvironment.Config.Definitions.Add("UE_BUILD_DEVELOPMENT=1"); break; case UnrealTargetConfiguration.Shipping: CompileConfiguration = CPPTargetConfiguration.Shipping; GlobalCompileEnvironment.Config.Definitions.Add("NDEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does GlobalCompileEnvironment.Config.Definitions.Add("UE_BUILD_SHIPPING=1"); break; case UnrealTargetConfiguration.Test: CompileConfiguration = CPPTargetConfiguration.Shipping; GlobalCompileEnvironment.Config.Definitions.Add("NDEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does GlobalCompileEnvironment.Config.Definitions.Add("UE_BUILD_TEST=1"); break; } // Set up the global C++ compilation and link environment. GlobalCompileEnvironment.Config.Target.Configuration = CompileConfiguration; GlobalLinkEnvironment.Config.Target.Configuration = CompileConfiguration; // Create debug info based on the heuristics specified by the user. GlobalCompileEnvironment.Config.bCreateDebugInfo = !BuildConfiguration.bDisableDebugInfo && ShouldCreateDebugInfo(CheckConfig); // NOTE: Even when debug info is turned off, we currently force the linker to generate debug info // anyway on Visual C++ platforms. This will cause a PDB file to be generated with symbols // for most of the classes and function/method names, so that crashes still yield somewhat // useful call stacks, even though compiler-generate debug info may be disabled. This gives // us much of the build-time savings of fully-disabled debug info, without giving up call // data completely. GlobalLinkEnvironment.Config.bCreateDebugInfo = true; }
static void AppendCLArguments_CPP(CPPEnvironment CompileEnvironment, StringBuilder Arguments) { // Explicitly compile the file as C++. Arguments.Append(" /TP"); if (!CompileEnvironment.Config.bEnableBufferSecurityChecks) { // This will disable buffer security checks (which are enabled by default) that the MS compiler adds around arrays on the stack, // Which can add some performance overhead, especially in performance intensive code // Only disable this if you know what you are doing, because it will be disabled for the entire module! Arguments.Append(" /GS-"); } // C++/CLI requires that RTTI is left enabled if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLRDisabled) { if (CompileEnvironment.Config.bUseRTTI) { // Enable C++ RTTI. Arguments.Append(" /GR"); } else { // Disable C++ RTTI. Arguments.Append(" /GR-"); } } // Level 4 warnings. Arguments.Append(" /W3"); }
/// <summary> /// Copy constructor. /// </summary> protected CPPEnvironment(CPPEnvironment InCopyEnvironment) { PrecompiledHeaderFile = InCopyEnvironment.PrecompiledHeaderFile; Headers = InCopyEnvironment.Headers; bHackHeaderGenerator = InCopyEnvironment.bHackHeaderGenerator; Config = new CPPEnvironmentConfiguration(InCopyEnvironment.Config); }
public static List <FileItem> FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem SourceFile, UEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, bool bOnlyCachedDependencies) { List <FileItem> Result = null; if (CPPIncludeInfo.IncludeFileSearchDictionary == null) { CPPIncludeInfo.IncludeFileSearchDictionary = new Dictionary <string, FileItem>(); } bool bUseFlatCPPIncludeDependencyCache = BuildConfiguration.bUseUBTMakefiles && UnrealBuildTool.IsAssemblingBuild; if (bOnlyCachedDependencies && bUseFlatCPPIncludeDependencyCache) { Result = FlatCPPIncludeDependencyCache[Target].GetDependenciesForFile(SourceFile.Reference); if (Result == null) { // Nothing cached for this file! It is new to us. This is the expected flow when our CPPIncludeDepencencyCache is missing. } } else { // @todo ubtmake: HeaderParser.h is missing from the include set for Module.UnrealHeaderTool.cpp (failed to find include using: FileItem DirectIncludeResolvedFile = CPPEnvironment.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, IncludePathsToSearch, IncludeFileSearchDictionary );) // If we're doing an exhaustive include scan, make sure that we have our include dependency cache loaded and ready if (!bOnlyCachedDependencies) { if (!IncludeDependencyCache.ContainsKey(Target)) { IncludeDependencyCache.Add(Target, DependencyCache.Create(DependencyCache.GetDependencyCachePathForTarget(Target))); } } Result = new List <FileItem>(); IncludedFilesSet IncludedFileList = new IncludedFilesSet(); CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies: bOnlyCachedDependencies); foreach (FileItem IncludedFile in IncludedFileList) { Result.Add(IncludedFile); } // Update cache if (bUseFlatCPPIncludeDependencyCache && !bOnlyCachedDependencies) { List <FileReference> Dependencies = new List <FileReference>(); foreach (FileItem IncludedFile in Result) { Dependencies.Add(IncludedFile.Reference); } FileReference PCHName = SourceFile.PrecompiledHeaderIncludeFilename; FlatCPPIncludeDependencyCache[Target].SetDependenciesForFile(SourceFile.Reference, PCHName, Dependencies); } } return(Result); }
/** Get the desired OnlineSubsystem. */ public string GetDesiredOnlineSubsystem( CPPEnvironment CPPEnv, UnrealTargetPlatform Platform ) { string ForcedOSS = UE3BuildTarget.ForceOnlineSubsystem( Platform ); if( ForcedOSS != null ) { return ( ForcedOSS ); } return ( "PC" ); }
/** Copy constructor. */ protected CPPEnvironment(CPPEnvironment InCopyEnvironment) { PrecompiledHeaderFile = InCopyEnvironment.PrecompiledHeaderFile; PrivateAssemblyDependencies.AddRange(InCopyEnvironment.PrivateAssemblyDependencies); SharedPCHHeaderFiles.AddRange(InCopyEnvironment.SharedPCHHeaderFiles); SharedPCHEnvironments.AddRange(InCopyEnvironment.SharedPCHEnvironments); bHackHeaderGenerator = InCopyEnvironment.bHackHeaderGenerator; Config = new CPPEnvironmentConfiguration(InCopyEnvironment.Config); }
static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment) { string Result = ""; if (CompileEnvironment.Config.Architecture != "-win32") // ! simulator { Result = " -std=c++14"; } return(Result); }
public static List <FileItem> FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem SourceFile, IUEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, bool bOnlyCachedDependencies) { var Result = new List <FileItem>(); if (CPPIncludeInfo.IncludeFileSearchDictionary == null) { CPPIncludeInfo.IncludeFileSearchDictionary = new Dictionary <string, FileItem>(); } bool bUseFlatCPPIncludeDependencyCache = (BuildConfiguration.bUseExperimentalFastDependencyScan && (!BuildConfiguration.bUseExperimentalFastBuildIteration || UnrealBuildTool.IsAssemblingBuild)); if (bUseFlatCPPIncludeDependencyCache && bOnlyCachedDependencies) { var Dependencies = FlatCPPIncludeDependencyCache[Target].GetDependenciesForFile(SourceFile.AbsolutePath); if (Dependencies != null) { foreach (string Dependency in Dependencies) { Result.Add(FileItem.GetItemByFullPath(Dependency)); // @todo fastubt: Make sure this is as fast as possible (convert to FileItem) } } else { // Nothing cached for this file! It is new to us. This is the expected flow when our CPPIncludeDepencencyCache is missing. } } else { // @todo fastubt: HeaderParser.h is missing from the include set for Module.UnrealHeaderTool.cpp (failed to find include using: FileItem DirectIncludeResolvedFile = CPPEnvironment.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, IncludePathsToSearch, IncludeFileSearchDictionary );) var IncludedFileList = new IncludedFilesSet(); CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies: bOnlyCachedDependencies); foreach (FileItem IncludedFile in IncludedFileList) { Result.Add(IncludedFile); } // Update cache if (bUseFlatCPPIncludeDependencyCache && !bOnlyCachedDependencies) { var Dependencies = new List <string>(); foreach (var IncludedFile in Result) { Dependencies.Add(IncludedFile.AbsolutePath); } string PCHName = SourceFile.PrecompiledHeaderIncludeFilename; FlatCPPIncludeDependencyCache[Target].SetDependenciesForFile(SourceFile.AbsolutePath, PCHName, Dependencies); } } return(Result); }
public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List <FileItem> RCFiles) { CPPOutput Result = new CPPOutput(); if (Environment.Config.Target.Architecture == "-win32") { return(base.CompileRCFiles(Target, Environment, RCFiles)); } return(Result); }
static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment) { string Result = ""; if (CompileEnvironment.Config.Target.Architecture != "-win32") { Result = " -std=c++11"; } return(Result); }
public override CPPOutput CompileRCFiles(CPPEnvironment Environment, List <FileItem> RCFiles, ActionGraph ActionGraph) { CPPOutput Result = new CPPOutput(); if (Environment.Config.Architecture == "-win32") // simulator { return(base.CompileRCFiles(Environment, RCFiles, ActionGraph)); } return(Result); }
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment) { string Result = GetSharedArguments_Global(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture, CompileEnvironment.Config.bEnableShadowVariableWarning); if (CompileEnvironment.Config.Target.Architecture != "-win32") // ! simulator { // do we want debug info? // if (CompileEnvironment.Config.bCreateDebugInfo) // { // Result += " -g"; // // // dump headers: http://stackoverflow.com/questions/42308/tool-to-track-include-dependencies // Result += " -H"; // } // Result += " -Wno-warn-absolute-paths "; // as of emscripten 1.35.0 complains that this is unknown Result += " -Wno-reorder"; // we disable constructor order warnings. if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { Result += " -s GL_ASSERTIONS=1"; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -O0"; } else // development & shipiing { Result += " -s ASM_JS=1"; if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz -s OUTLINING_LIMIT=40000"; } else { Result += " -s OUTLINING_LIMIT=110000"; if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { Result += " -O2"; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { Result += " -O3"; } } } } return(Result); }
/// <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) { // UnrealCodeAnalyzer produces output files only for a specific module. if (BuildConfiguration.bRunUnrealCodeAnalyzer && !(ModuleNames.Contains(BuildConfiguration.UCAModuleToAnalyze))) { return(new List <FileItem>()); } // Setup linking environment. var BinaryLinkEnvironment = SetupBinaryLinkEnvironment(LinkEnvironment, CompileEnvironment); // Return linked files. return(SetupOutputFiles(TargetToolChain, ref BinaryLinkEnvironment)); }
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment) { string Result = GetSharedArguments_Global(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture, CompileEnvironment.Config.bEnableShadowVariableWarning); if (CompileEnvironment.Config.Target.Architecture != "-win32") { // do we want debug info? /* if (CompileEnvironment.Config.bCreateDebugInfo) * { * Result += " -g"; * }*/ Result += " -Wno-warn-absolute-paths "; Result += " -Wno-reorder"; // we disable constructor order warnings. if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -O0"; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { Result += " -s GL_ASSERTIONS=1 "; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000"; } else { Result += " -O2 -s ASM_JS=1 -s OUTLINING_LIMIT=110000"; } } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000"; } else { Result += " -O3 -s ASM_JS=1 -s OUTLINING_LIMIT=110000"; } } } return(Result); }
/// <summary> /// Generates a UHTModuleInfo for a particular named module under a directory. /// </summary> /// <returns> public static UHTModuleInfo CreateUHTModuleInfo(IEnumerable <string> HeaderFilenames, UEBuildTarget Target, string ModuleName, DirectoryReference ModuleDirectory, UEBuildModuleType ModuleType) { var ClassesFolder = DirectoryReference.Combine(ModuleDirectory, "Classes"); var PublicFolder = DirectoryReference.Combine(ModuleDirectory, "Public"); var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform); var AllClassesHeaders = new List <FileItem>(); var PublicUObjectHeaders = new List <FileItem>(); var PrivateUObjectHeaders = new List <FileItem>(); foreach (var Header in HeaderFilenames) { // Check to see if we know anything about this file. If we have up-to-date cached information about whether it has // UObjects or not, we can skip doing a test here. var UObjectHeaderFileItem = FileItem.GetExistingItemByPath(Header); if (CPPEnvironment.DoesFileContainUObjects(UObjectHeaderFileItem.AbsolutePath)) { if (new FileReference(UObjectHeaderFileItem.AbsolutePath).IsUnderDirectory(ClassesFolder)) { AllClassesHeaders.Add(UObjectHeaderFileItem); } else if (new FileReference(UObjectHeaderFileItem.AbsolutePath).IsUnderDirectory(PublicFolder)) { PublicUObjectHeaders.Add(UObjectHeaderFileItem); } else { PrivateUObjectHeaders.Add(UObjectHeaderFileItem); } } } var Result = new UHTModuleInfo { ModuleName = ModuleName, ModuleDirectory = ModuleDirectory.FullName, ModuleType = ModuleType.ToString(), PublicUObjectClassesHeaders = AllClassesHeaders, PublicUObjectHeaders = PublicUObjectHeaders, PrivateUObjectHeaders = PrivateUObjectHeaders, GeneratedCodeVersion = Target.Rules.GetGeneratedCodeVersion() }; return(Result); }
/// <summary> /// Builds the binary. /// </summary> /// <param name="ToolChain">The toolchain to use for building</param> /// <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(UEToolChain ToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment) { var ProjectCSharpEnviroment = new CSharpEnvironment(); if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { ProjectCSharpEnviroment.TargetConfiguration = CSharpTargetConfiguration.Debug; } else { ProjectCSharpEnviroment.TargetConfiguration = CSharpTargetConfiguration.Development; } ProjectCSharpEnviroment.EnvironmentTargetPlatform = LinkEnvironment.Config.Target.Platform; ToolChain.CompileCSharpProject(ProjectCSharpEnviroment, Config.ProjectFilePath, Config.OutputFilePath); return(new FileItem[] { FileItem.GetItemByFileReference(Config.OutputFilePath) }); }
/** Allows the game to add any additional environment settings before building */ public void SetUpGameEnvironment(CPPEnvironment GameCPPEnvironment, LinkEnvironment FinalLinkEnvironment, List<UE3ProjectDesc> GameProjects) { GameCPPEnvironment.IncludePaths.Add("ExampleGame/Inc"); GameProjects.Add( new UE3ProjectDesc( "ExampleGame/ExampleGame.vcproj") ); if (UE3BuildConfiguration.bBuildEditor && (GameCPPEnvironment.TargetPlatform == CPPTargetPlatform.Win32 || GameCPPEnvironment.TargetPlatform == CPPTargetPlatform.Win64)) { GameProjects.Add( new UE3ProjectDesc( "ExampleEditor/ExampleEditor.vcproj") ); GameCPPEnvironment.IncludePaths.Add("ExampleEditor/Inc"); } GameCPPEnvironment.Definitions.Add("GAMENAME=EXAMPLEGAME"); GameCPPEnvironment.Definitions.Add("IS_EXAMPLEGAME=1"); FinalLinkEnvironment.AdditionalLibraries.Add("ws2_32.lib"); FinalLinkEnvironment.AdditionalLibraries.Add("../../Binaries/win32/Network.lib"); }
/// <summary> /// Builds the binary. /// </summary> /// <param name="ToolChain">The toolchain to use for building</param> /// <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 ToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment) { var ProjectCSharpEnviroment = new CSharpEnvironment(); if (LinkEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { ProjectCSharpEnviroment.TargetConfiguration = CSharpTargetConfiguration.Debug; } else { ProjectCSharpEnviroment.TargetConfiguration = CSharpTargetConfiguration.Development; } ProjectCSharpEnviroment.EnvironmentTargetPlatform = LinkEnvironment.Config.Target.Platform; // Currently only supported by windows... UEToolChain.GetPlatformToolChain(CPPTargetPlatform.Win64).CompileCSharpProject( ProjectCSharpEnviroment, Config.ProjectFilePath, Config.OutputFilePath); return(new FileItem[] { FileItem.GetItemByPath(Config.OutputFilePath) }); }
static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment) { string Result = ""; // Explicitly compile the file as C++. Result += " /TP"; // C++/CLI requires that RTTI is left enabled if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLRDisabled) { if (CompileEnvironment.Config.bUseRTTI) { // Enable C++ RTTI. Result += " /GR"; } else { // Disable C++ RTTI. Result += " /GR-"; } } if (WinRTPlatform.ShouldCompileWinRT() == true) { // WinRT headers generate too many warnings for /W4 Result += " /W1"; } else { // Level 3 warnings. // Result += " /W3"; Result += " /W1"; } return(Result); }
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment) { string Result = GetSharedArguments_Global(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture, CompileEnvironment.Config.bEnableShadowVariableWarning); if (CompileEnvironment.Config.Target.Architecture != "-win32") // ! simulator { // do we want debug info? /* if (CompileEnvironment.Config.bCreateDebugInfo) { Result += " -g"; }*/ // Result += " -Wno-warn-absolute-paths "; // as of emscripten 1.35.0 complains that this is unknown Result += " -Wno-reorder"; // we disable constructor order warnings. if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { Result += " -s GL_ASSERTIONS=1"; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -O0"; } else // development & shipiing { Result += " -s ASM_JS=1"; if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz -s OUTLINING_LIMIT=40000"; } else { Result += " -s OUTLINING_LIMIT=110000"; if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { Result += " -O2"; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { Result += " -O3"; } } } } return Result; }
public abstract CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName);
/// <summary> /// Builds the binary. /// </summary> /// <param name="ToolChain">The toolchain which to use for building</param> /// <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 abstract IEnumerable <FileItem> Build(IUEToolChain ToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment);
/// <summary> /// Builds and runs the header tool and touches the header directories. /// Performs any early outs if headers need no changes, given the UObject modules, tool path, game name, and configuration /// </summary> public static bool ExecuteHeaderToolIfNecessary(UEToolChain ToolChain, UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List <UHTModuleInfo> UObjectModules, FileReference ModuleInfoFileName, ref ECompilationResult UHTResult) { if (ProgressWriter.bWriteMarkup) { Log.WriteLine(LogEventType.Console, "@progress push 5%"); } using (ProgressWriter Progress = new ProgressWriter("Generating code...", false)) { // We never want to try to execute the header tool when we're already trying to build it! var bIsBuildingUHT = Target.GetTargetName().Equals("UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase); var RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath); // check if UHT is out of date DateTime HeaderToolTimestamp = DateTime.MaxValue; bool bHaveHeaderTool = !bIsBuildingUHT && GetHeaderToolTimestamp(out HeaderToolTimestamp); // ensure the headers are up to date bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || !bHaveHeaderTool || AreGeneratedCodeFilesOutOfDate(UObjectModules, HeaderToolTimestamp)); if (bUHTNeedsToRun || UnrealBuildTool.IsGatheringBuild) { // Since code files are definitely out of date, we'll now finish computing information about the UObject modules for UHT. We // want to save this work until we know that UHT actually needs to be run to speed up best-case iteration times. if (UnrealBuildTool.IsGatheringBuild) // In assembler-only mode, PCH info is loaded from our UBTMakefile! { foreach (var UHTModuleInfo in UObjectModules) { // Only cache the PCH name if we don't already have one. When running in 'gather only' mode, this will have already been cached if (string.IsNullOrEmpty(UHTModuleInfo.PCH)) { UHTModuleInfo.PCH = ""; // We need to figure out which PCH header this module is including, so that UHT can inject an include statement for it into any .cpp files it is synthesizing var DependencyModuleCPP = (UEBuildModuleCPP)Target.GetModuleByName(UHTModuleInfo.ModuleName); var ModuleCompileEnvironment = DependencyModuleCPP.CreateModuleCompileEnvironment(GlobalCompileEnvironment); DependencyModuleCPP.CachePCHUsageForModuleSourceFiles(ModuleCompileEnvironment); if (DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile != null) { UHTModuleInfo.PCH = DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath; } } } } } // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run! Can't we use the existing copy? (see below use of Manifest) UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules); if (!bIsBuildingUHT && bUHTNeedsToRun) { // Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem or hot-reloading if (UnrealBuildTool.RunningRocket() == false && UEBuildConfiguration.bDoNotBuildUHT == false && UEBuildConfiguration.bHotReloadFromIDE == false && !(bHaveHeaderTool && !UnrealBuildTool.IsGatheringBuild && UnrealBuildTool.IsAssemblingBuild)) // If running in "assembler only" mode, we assume UHT is already up to date for much faster iteration! { // If it is out of date or not there it will be built. // If it is there and up to date, it will add 0.8 seconds to the build time. Log.TraceInformation("Building UnrealHeaderTool..."); var UBTArguments = new StringBuilder(); UBTArguments.Append("UnrealHeaderTool"); // Which desktop platform do we need to compile UHT for? UBTArguments.Append(" " + BuildHostPlatform.Current.Platform.ToString()); // NOTE: We force Development configuration for UHT so that it runs quickly, even when compiling debug UBTArguments.Append(" " + UnrealTargetConfiguration.Development.ToString()); // NOTE: We disable mutex when launching UBT from within UBT to compile UHT UBTArguments.Append(" -NoMutex"); if (UnrealBuildTool.CommandLineContains("-noxge")) { UBTArguments.Append(" -noxge"); } // Propagate command-line option if (UnrealBuildTool.CommandLineContains("-2015")) { UBTArguments.Append(" -2015"); } if (UnrealBuildTool.CommandLineContains("-2013")) { UBTArguments.Append(" -2013"); } // Add UHT plugins to UBT command line as external plugins if (Target.UnrealHeaderToolPlugins != null && Target.UnrealHeaderToolPlugins.Count > 0) { foreach (PluginInfo Plugin in Target.UnrealHeaderToolPlugins) { UBTArguments.Append(" -PLUGIN \"" + Plugin.File + "\""); } } if (RunExternalExecutable(UnrealBuildTool.GetUBTPath(), UBTArguments.ToString()) != 0) { return(false); } } Progress.Write(1, 3); var ActualTargetName = String.IsNullOrEmpty(Target.GetTargetName()) ? "UE4" : Target.GetTargetName(); Log.TraceInformation("Parsing headers for {0}", ActualTargetName); string HeaderToolPath = GetHeaderToolPath(); if (!File.Exists(HeaderToolPath)) { throw new BuildException("Unable to generate headers because UnrealHeaderTool binary was not found ({0}).", Path.GetFullPath(HeaderToolPath)); } // Disable extensions when serializing to remove the $type fields Directory.CreateDirectory(ModuleInfoFileName.Directory.FullName); System.IO.File.WriteAllText(ModuleInfoFileName.FullName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters { UseExtensions = false })); string CmdLine = (Target.ProjectFile != null) ? "\"" + Target.ProjectFile.FullName + "\"" : Target.GetTargetName(); CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\" -Unattended -WarningsAsErrors"; if (UnrealBuildTool.IsEngineInstalled()) { CmdLine += " -installed"; } if (UEBuildConfiguration.bFailIfGeneratedCodeChanges) { CmdLine += " -FailIfGeneratedCodeChanges"; } if (!bInvalidateUHTMakefile && BuildConfiguration.bUseUHTMakefiles) { CmdLine += " -UseMakefiles"; } if (!UEBuildConfiguration.bCompileAgainstEngine) { CmdLine += " -NoEnginePlugins"; } Log.TraceInformation(" Running UnrealHeaderTool {0}", CmdLine); Stopwatch s = new Stopwatch(); s.Start(); UHTResult = (ECompilationResult)RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine); s.Stop(); if (UHTResult != ECompilationResult.Succeeded) { // On Linux and Mac, the shell will return 128+signal number exit codes if UHT gets a signal (e.g. crashes or is interrupted) if ((BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) && (int)(UHTResult) >= 128 ) { // SIGINT is 2, so 128 + SIGINT is 130 UHTResult = ((int)(UHTResult) == 130) ? ECompilationResult.Canceled : ECompilationResult.CrashOrAssert; } Log.TraceInformation("Error: Failed to generate code for {0} - error code: {2} ({1})", ActualTargetName, (int)UHTResult, UHTResult.ToString()); return(false); } Log.TraceInformation("Reflection code generated for {0} in {1} seconds", ActualTargetName, s.Elapsed.TotalSeconds); if (BuildConfiguration.bPrintPerformanceInfo) { Log.TraceInformation("UnrealHeaderTool took {1}", ActualTargetName, (double)s.ElapsedMilliseconds / 1000.0); } // Now that UHT has successfully finished generating code, we need to update all cached FileItems in case their last write time has changed. // Otherwise UBT might not detect changes UHT made. DateTime StartTime = DateTime.UtcNow; FileItem.ResetInfos(); double ResetDuration = (DateTime.UtcNow - StartTime).TotalSeconds; Log.TraceVerbose("FileItem.ResetInfos() duration: {0}s", ResetDuration); } else { Log.TraceVerbose("Generated code is up to date."); } Progress.Write(2, 3); // There will never be generated code if we're building UHT, so this should never be called. if (!bIsBuildingUHT) { // Allow generated code to be sync'd to remote machines if needed. This needs to be done even if UHT did not run because // generated headers include other generated headers using absolute paths which in case of building remotely are already // the remote machine absolute paths. Because of that parsing headers will not result in finding all includes properly. // @todo ubtmake: Need to figure out what this does in the assembler case, and whether we need to run it ToolChain.PostCodeGeneration(Manifest); } // touch the directories UpdateDirectoryTimestamps(UObjectModules); Progress.Write(3, 3); } if (ProgressWriter.bWriteMarkup) { Log.WriteLine(LogEventType.Console, "@progress pop"); } return(true); }
/** * Builds and runs the header tool and touches the header directories. * Performs any early outs if headers need no changes, given the UObject modules, tool path, game name, and configuration */ public static bool ExecuteHeaderToolIfNecessary( UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List<UHTModuleInfo> UObjectModules, string ModuleInfoFileName, ref ECompilationResult UHTResult ) { if(ProgressWriter.bWriteMarkup) { Log.WriteLine(TraceEventType.Information, "@progress push 5%"); } using (ProgressWriter Progress = new ProgressWriter("Generating code...", false)) { // We never want to try to execute the header tool when we're already trying to build it! var bIsBuildingUHT = Target.GetTargetName().Equals( "UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase ); var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform); var CppPlatform = BuildPlatform.GetCPPTargetPlatform(Target.Platform); var ToolChain = UEToolChain.GetPlatformToolChain(CppPlatform); var RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath); // check if UHT is out of date DateTime HeaderToolTimestamp = DateTime.MaxValue; bool bHaveHeaderTool = !bIsBuildingUHT && GetHeaderToolTimestamp(out HeaderToolTimestamp); // ensure the headers are up to date bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || !bHaveHeaderTool || AreGeneratedCodeFilesOutOfDate(UObjectModules, HeaderToolTimestamp)); if( bUHTNeedsToRun || UnrealBuildTool.IsGatheringBuild ) { // Since code files are definitely out of date, we'll now finish computing information about the UObject modules for UHT. We // want to save this work until we know that UHT actually needs to be run to speed up best-case iteration times. if( UnrealBuildTool.IsGatheringBuild ) // In assembler-only mode, PCH info is loaded from our UBTMakefile! { foreach( var UHTModuleInfo in UObjectModules ) { // Only cache the PCH name if we don't already have one. When running in 'gather only' mode, this will have already been cached if( string.IsNullOrEmpty( UHTModuleInfo.PCH ) ) { UHTModuleInfo.PCH = ""; // We need to figure out which PCH header this module is including, so that UHT can inject an include statement for it into any .cpp files it is synthesizing var DependencyModuleCPP = (UEBuildModuleCPP)Target.GetModuleByName( UHTModuleInfo.ModuleName ); var ModuleCompileEnvironment = DependencyModuleCPP.CreateModuleCompileEnvironment(GlobalCompileEnvironment); DependencyModuleCPP.CachePCHUsageForModuleSourceFiles(ModuleCompileEnvironment); if (DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile != null) { UHTModuleInfo.PCH = DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath; } } } } } // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run! Can't we use the existing copy? (see below use of Manifest) UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules); if( !bIsBuildingUHT && bUHTNeedsToRun ) { // Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem or hot-reloading if (UnrealBuildTool.RunningRocket() == false && UEBuildConfiguration.bDoNotBuildUHT == false && UEBuildConfiguration.bHotReloadFromIDE == false && !( bHaveHeaderTool && !UnrealBuildTool.IsGatheringBuild && UnrealBuildTool.IsAssemblingBuild ) ) // If running in "assembler only" mode, we assume UHT is already up to date for much faster iteration! { // If it is out of date or not there it will be built. // If it is there and up to date, it will add 0.8 seconds to the build time. Log.TraceInformation("Building UnrealHeaderTool..."); var UBTArguments = new StringBuilder(); UBTArguments.Append( "UnrealHeaderTool" ); // Which desktop platform do we need to compile UHT for? UBTArguments.Append(" " + BuildHostPlatform.Current.Platform.ToString()); // NOTE: We force Development configuration for UHT so that it runs quickly, even when compiling debug UBTArguments.Append( " " + UnrealTargetConfiguration.Development.ToString() ); // NOTE: We disable mutex when launching UBT from within UBT to compile UHT UBTArguments.Append( " -NoMutex" ); if (UnrealBuildTool.CommandLineContains("-noxge")) { UBTArguments.Append(" -noxge"); } if ( RunExternalExecutable( UnrealBuildTool.GetUBTPath(), UBTArguments.ToString() ) != 0 ) { return false; } } Progress.Write(1, 3); var ActualTargetName = String.IsNullOrEmpty( Target.GetTargetName() ) ? "UE4" : Target.GetTargetName(); Log.TraceInformation( "Parsing headers for {0}", ActualTargetName ); string HeaderToolPath = GetHeaderToolPath(); if (!File.Exists(HeaderToolPath)) { throw new BuildException( "Unable to generate headers because UnrealHeaderTool binary was not found ({0}).", Path.GetFullPath( HeaderToolPath ) ); } // Disable extensions when serializing to remove the $type fields Directory.CreateDirectory(Path.GetDirectoryName(ModuleInfoFileName)); System.IO.File.WriteAllText(ModuleInfoFileName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters{ UseExtensions = false })); string CmdLine = (UnrealBuildTool.HasUProjectFile()) ? "\"" + UnrealBuildTool.GetUProjectFile() + "\"" : Target.GetTargetName(); CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\""; if (UnrealBuildTool.RunningRocket()) { CmdLine += " -rocket -installed"; } if (UEBuildConfiguration.bFailIfGeneratedCodeChanges) { CmdLine += " -FailIfGeneratedCodeChanges"; } Log.TraceInformation(" Running UnrealHeaderTool {0}", CmdLine); Stopwatch s = new Stopwatch(); s.Start(); UHTResult = (ECompilationResult) RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine); s.Stop(); if (UHTResult != ECompilationResult.Succeeded) { // On Linux and Mac, the shell will return 128+signal number exit codes if UHT gets a signal (e.g. crashes or is interrupted) if ((BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) && (int)(UHTResult) >= 128 ) { // SIGINT is 2, so 128 + SIGINT is 130 UHTResult = ((int)(UHTResult) == 130) ? ECompilationResult.Canceled : ECompilationResult.CrashOrAssert; } Log.TraceInformation("Error: Failed to generate code for {0} - error code: {2} ({1})", ActualTargetName, (int) UHTResult, UHTResult.ToString()); return false; } Log.TraceInformation("Reflection code generated for {0} in {1} seconds", ActualTargetName, s.Elapsed.TotalSeconds); if( BuildConfiguration.bPrintPerformanceInfo ) { Log.TraceInformation( "UnrealHeaderTool took {1}", ActualTargetName, (double)s.ElapsedMilliseconds/1000.0 ); } // Now that UHT has successfully finished generating code, we need to update all cached FileItems in case their last write time has changed. // Otherwise UBT might not detect changes UHT made. DateTime StartTime = DateTime.UtcNow; FileItem.ResetInfos(); double ResetDuration = (DateTime.UtcNow - StartTime).TotalSeconds; Log.TraceVerbose("FileItem.ResetInfos() duration: {0}s", ResetDuration); } else { Log.TraceVerbose( "Generated code is up to date." ); } Progress.Write(2, 3); // There will never be generated code if we're building UHT, so this should never be called. if (!bIsBuildingUHT) { // Allow generated code to be sync'd to remote machines if needed. This needs to be done even if UHT did not run because // generated headers include other generated headers using absolute paths which in case of building remotely are already // the remote machine absolute paths. Because of that parsing headers will not result in finding all includes properly. // @todo ubtmake: Need to figure out what this does in the assembler case, and whether we need to run it ToolChain.PostCodeGeneration(Manifest); } // touch the directories UpdateDirectoryTimestamps(UObjectModules); Progress.Write(3, 3); } if(ProgressWriter.bWriteMarkup) { Log.WriteLine(TraceEventType.Information, "@progress pop"); } return true; }
/// <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 ); }
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment) { string Result = ""; //Result += " /showIncludes"; // Prevents the compiler from displaying its logo for each invocation. Result += " /nologo"; // Enable intrinsic functions. Result += " /Oi"; // Enable for static code analysis (where supported). Not treating analysis warnings as errors. // Result += " /analyze:WX-"; // Pack struct members on 8-byte boundaries. Result += " /Zp8"; // Calling convention - _cdecl Result += " /Gd"; // Disable minimal rebuild Result += " /Gm-"; // Security checks enabled Result += " /GS"; // Separate functions for linker. Result += " /Gy"; // Relaxes floating point precision semantics to allow more optimization. Result += " /fp:fast"; // Compile into an .obj file, and skip linking. Result += " /c"; // Allow 400% of the default memory allocation limit. Result += " /Zm400"; // Allow large object files to avoid hitting the 2^16 section limit when running with -StressTestUnity. Result += " /bigobj"; Result += " /Zc:wchar_t"; Result += " /Zc:forScope"; // Disable "The file contains a character that cannot be represented in the current code page" warning for non-US windows. Result += " /wd4819"; if( BuildConfiguration.bUseSharedPCHs ) { // @todo SharedPCH: Disable warning about PCH defines not matching .cpp defines. We "cheat" these defines a little // bit to make shared PCHs work. But it's totally safe. Trust us. Result += " /wd4651"; // @todo SharedPCH: Disable warning about redefining *API macros. The PCH header is compiled with various DLLIMPORTs, but // when a module that uses that PCH header *IS* one of those imports, that module is compiled with EXPORTS, so the macro // is redefined on the command-line. We need to clobber those defines to make shared PCHs work properly! Result += " /wd4005"; } // If compiling as a DLL, set the relevant defines if (CompileEnvironment.Config.bIsBuildingDLL) { Result += " /D _WINDLL"; Result += " /D _USRDLLundefined_EXPORTS"; } // // Debug // if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { // Disable compiler optimization. Result += " /Od"; // Favor code size (especially useful for embedded platforms). Result += " /Os"; // Allow inline method expansion unless E&C support is requested if (!BuildConfiguration.bSupportEditAndContinue) { // Allow inline method expansion of any suitable. Result += " /Ob2"; } // Perform runtime checks for (s) stack frames and (u) unintialized variables // RTC1 == RTCsu Result += " /RTC1"; } // // Release and LTCG // else { // Maximum optimizations. Result += " /Ox"; // Enable intrinsics Result += " /Oi"; // Allow inline method expansion Result += " /Ob2"; // // LTCG // if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { if (BuildConfiguration.bAllowLTCG) { // Enable link-time code generation. Result += " /GL"; } } } // // WinRT // if (CompileEnvironment.Config.bIsBuildingLibrary == false) { Result += " /ZW"; } if (WinRTPlatform.ShouldCompileWinRT() == true) { // Prompt the user before reporting internal errors to Microsoft. Result += " /errorReport:prompt"; // Enable C++ exception handling, but not C exceptions. Result += " /EHsc"; // Disable "unreferenced formal parameter" warning since auto-included vccorlib.h triggers it Result += " /wd4100"; // Disable "unreachable code" warning since auto-included vccorlib.h triggers it Result += " /wd4702"; } else { Result += " /AI\"C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\vcpackages\""; Result += " /D USE_WINRT_MAIN=1"; // WinRT requires exceptions! // if (CompileEnvironment.Config.bEnableExceptions) { // Enable C++ exception handling, but not C exceptions. Result += " /EHsc"; } // Disable "unreferenced formal parameter" warning since auto-included vccorlib.h triggers it Result += " /wd4100"; // Disable "unreachable code" warning since auto-included vccorlib.h triggers it Result += " /wd4702"; // Disable "alignment of a member was sensitive to packing" warning since auto-included vccorlib.h triggers it Result += " /wd4121"; // reinterpret_cast used between related classes: 'Platform::Object' and ... Result += " /wd4946"; // macro redefinition Result += " /wd4005"; //Result += " /showIncludes"; } // If enabled, create debug information. if (CompileEnvironment.Config.bCreateDebugInfo) { // Store debug info in .pdb files. if (BuildConfiguration.bUsePDBFiles) { // Create debug info suitable for E&C if wanted. if (BuildConfiguration.bSupportEditAndContinue // We only need to do this in debug as that's the only configuration that supports E&C. && CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " /ZI"; } // Regular PDB debug information. else { Result += " /Zi"; } } // Store C7-format debug info in the .obj files, which is faster. else { Result += " /Z7"; } } // Specify the appropriate runtime library based on the platform and config. if( CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug && BuildConfiguration.bDebugBuildsActuallyUseDebugCRT ) { Result += " /MDd"; } else { Result += " /MD"; } return Result; }
static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment) { string Result = ""; // Explicitly compile the file as C++. Result += " /TP"; // C++/CLI requires that RTTI is left enabled if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLRDisabled) { if (CompileEnvironment.Config.bUseRTTI) { // Enable C++ RTTI. Result += " /GR"; } else { // Disable C++ RTTI. Result += " /GR-"; } } if (WinRTPlatform.ShouldCompileWinRT() == true) { // WinRT headers generate too many warnings for /W4 Result += " /W1"; } else { // Level 3 warnings. // Result += " /W3"; Result += " /W1"; } return Result; }
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." + ModuleName + "." + Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename) + ".cpp"; string PCHCPPPath = Path.Combine(CompileEnvironment.Config.OutputDirectory, PCHCPPFilename); FileItem PCHCPPFile = FileItem.CreateIntermediateTextFile( PCHCPPPath, string.Format("#include \"{0}\"\r\n", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename) ); // Make sure the original source directory the PCH header file existed in is added as an include // path -- it might be a private PCH header and we need to make sure that its found! string OriginalPCHHeaderDirectory = Path.GetDirectoryName(SourceFile.AbsolutePath); FileArguments += string.Format(" /I \"{0}\"", OriginalPCHHeaderDirectory); 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.bIsVCCompiler = true; 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; }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName) { if (Arches.Count == 0) { throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build"); } if (!bHasPrintedApiLevel) { Console.WriteLine("Compiling Native code with NDK API '{0}'", GetNdkApiLevel()); bHasPrintedApiLevel = true; } string BaseArguments = ""; if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create) { BaseArguments += " -Werror"; } // Directly added NDK files for NDK extensions ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName); // Deal with dynamic modules removed by architecture GenerateEmptyLinkFunctionsForRemovedModules(SourceFiles, ModuleName, CompileEnvironment.Config.OutputDirectory); // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { BaseArguments += string.Format(" -D \"{0}\"", Definition); } var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); var NDKRoot = Environment.GetEnvironmentVariable("NDKROOT").Replace("\\", "/"); string BasePCHName = ""; var PCHExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { BasePCHName = RemoveArchName(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath).Replace(PCHExtension, ""); } // Create a compile action for each source file. CPPOutput Result = new CPPOutput(); foreach (string Arch in Arches) { if (ShouldSkipModule(ModuleName, Arch)) { continue; } foreach (string GPUArchitecture in GPUArchitectures) { // which toolchain to use string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments; switch (Arch) { case "-armv7": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break; case "-arm64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_ARM64=1"; break; case "-x86": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_X86=1"; break; case "-x64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_X64=1"; break; default: Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break; } if (GPUArchitecture == "-esdeferred") { Arguments += " -DPLATFORM_ANDROIDESDEFERRED=1"; } // which PCH file to include string PCHArguments = ""; if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { // Add the precompiled header file's path to the include path so Clang can find it. // This needs to be before the other include paths to ensure Clang uses it instead of the source header file. PCHArguments += string.Format(" -include \"{0}\"", InlineArchName(BasePCHName, Arch, GPUArchitecture)); } // Add include paths to the argument list (filtered by architecture) foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths) { if (IsDirectoryForArch(IncludePath, Arch)) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } } foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths) { if (IsDirectoryForArch(IncludePath, Arch)) { Arguments += string.Format(" -I\"{0}\"", IncludePath); } } foreach (FileItem SourceFile in SourceFiles) { Action CompileAction = new Action(ActionType.Compile); string FileArguments = ""; bool bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C"; bool bDisableShadowWarning = false; // should we disable optimizations on this file? // @todo android - We wouldn't need this if we could disable optimizations per function (via pragma) bool bDisableOptimizations = false;// SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1; if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath); } bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug; // Add C or C++ specific compiler arguments. if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { FileArguments += GetCompileArguments_PCH(bDisableOptimizations); } else if (bIsPlainCFile) { FileArguments += GetCompileArguments_C(bDisableOptimizations); // remove shadow variable warnings for NDK files if (SourceFile.AbsolutePath.Replace("\\", "/").StartsWith(NDKRoot)) { bDisableShadowWarning = true; } } else { FileArguments += GetCompileArguments_CPP(bDisableOptimizations); // only use PCH for .cpp files FileArguments += PCHArguments; } // Add the C++ source file and its included files to the prerequisite item list. AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { // Add the precompiled header file to the produced item list. FileItem PrecompiledHeaderFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, Path.GetFileName(InlineArchName(SourceFile.AbsolutePath, Arch, GPUArchitecture) + PCHExtension) ) ); CompileAction.ProducedItems.Add(PrecompiledHeaderFile); Result.PrecompiledHeaderFile = PrecompiledHeaderFile; // Add the parameters needed to compile the precompiled header file to the command-line. FileArguments += string.Format(" -o \"{0}\"", PrecompiledHeaderFile.AbsolutePath, false); } else { if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { CompileAction.bIsUsingPCH = true; FileItem ArchPrecompiledHeaderFile = FileItem.GetItemByPath(InlineArchName(BasePCHName, Arch, GPUArchitecture) + PCHExtension); CompileAction.PrerequisiteItems.Add(ArchPrecompiledHeaderFile); } var ObjectFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Android).GetBinaryExtension(UEBuildBinaryType.Object); // Add the object file to the produced item list. FileItem ObjectFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, InlineArchName(Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension, Arch, GPUArchitecture) ) ); CompileAction.ProducedItems.Add(ObjectFile); Result.ObjectFiles.Add(ObjectFile); FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath, false); } // Add the source file path to the command-line. FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath); // Build a full argument list string AllArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments; AllArguments = ActionThread.ExpandEnvironmentVariables(AllArguments); AllArguments = AllArguments.Replace("\\", "/"); // Remove shadow warning for this file if requested if (bDisableShadowWarning) { int WarningIndex = AllArguments.IndexOf(" -Wshadow"); if (WarningIndex > 0) { AllArguments = AllArguments.Remove(WarningIndex, 9); } } // Create the response file FileReference ResponseFileName = CompileAction.ProducedItems[0].Reference + "_" + AllArguments.GetHashCode().ToString("X") + ".response"; string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List<string> { AllArguments }).FullName); CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; CompileAction.CommandPath = ClangPath; CompileAction.CommandArguments = ResponseArgument; CompileAction.StatusDescription = string.Format("{0} [{1}-{2}]", Path.GetFileName(SourceFile.AbsolutePath), Arch.Replace("-", ""), GPUArchitecture.Replace("-", "")); // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves CompileAction.bShouldOutputStatusDescription = true; // Don't farm out creation of pre-compiled headers as it is the critical path task. CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create || BuildConfiguration.bAllowRemotelyCompiledPCHs; } } } return Result; }
string GetCLArguments_Global(CPPEnvironment CompileEnvironment, string Architecture) { string Result = ""; switch (Architecture) { case "-armv7": Result += ToolchainParamsArm; break; case "-arm64": Result += ToolchainParamsArm64; break; case "-x86": Result += ToolchainParamsx86; break; case "-x64": Result += ToolchainParamsx64; break; default: Result += ToolchainParamsArm; break; } // build up the commandline common to C and C++ Result += " -c"; Result += " -fdiagnostics-format=msvc"; Result += " -Wall"; Result += " -Wno-unused-variable"; // this will hide the warnings about static functions in headers that aren't used in every single .cpp file Result += " -Wno-unused-function"; // this hides the "enumeration value 'XXXXX' not handled in switch [-Wswitch]" warnings - we should maybe remove this at some point and add UE_LOG(, Fatal, ) to default cases Result += " -Wno-switch"; // this hides the "warning : comparison of unsigned expression < 0 is always false" type warnings due to constant comparisons, which are possible with template arguments Result += " -Wno-tautological-compare"; //This will prevent the issue of warnings for unused private variables. Result += " -Wno-unused-private-field"; Result += " -Wno-local-type-template-args"; // engine triggers this Result += " -Wno-return-type-c-linkage"; // needed for PhysX Result += " -Wno-reorder"; // member initialization order Result += " -Wno-unknown-pragmas"; // probably should kill this one, sign of another issue in PhysX? Result += " -Wno-invalid-offsetof"; // needed to suppress warnings about using offsetof on non-POD types. Result += " -Wno-logical-op-parentheses"; // needed for external headers we can't change if (CompileEnvironment.Config.bEnableShadowVariableWarning) { Result += " -Wshadow -Wno-error=shadow"; } // new for clang4.5 warnings: if (ClangVersionFloat >= 3.5f) { Result += " -Wno-undefined-bool-conversion"; // 'this' pointer cannot be null in well-defined C++ code; pointer may be assumed to always convert to true (if (this)) // we use this feature to allow static FNames. Result += " -Wno-gnu-string-literal-operator-template"; } if (ClangVersionFloat >= 3.6f) { Result += " -Wno-unused-local-typedef"; // clang is being overly strict here? PhysX headers trigger this. Result += " -Wno-inconsistent-missing-override"; // these have to be suppressed for UE 4.8, should be fixed later. } // shipping builds will cause this warning with "ensure", so disable only in those case if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { Result += " -Wno-unused-value"; } // debug info if (CompileEnvironment.Config.bCreateDebugInfo) { Result += " -g2 -gdwarf-4"; } // optimization level if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -O0"; } else { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz"; } else { Result += " -O3"; } } //@todo android: these are copied verbatim from UE3 and probably need adjustment if (Architecture == "-armv7") { // Result += " -mthumb-interwork"; // Generates code which supports calling between ARM and Thumb instructions, w/o it you can't reliability use both together Result += " -funwind-tables"; // Just generates any needed static data, affects no code Result += " -fstack-protector"; // Emits extra code to check for buffer overflows // Result += " -mlong-calls"; // Perform function calls by first loading the address of the function into a reg and then performing the subroutine call Result += " -fno-strict-aliasing"; // Prevents unwanted or invalid optimizations that could produce incorrect code Result += " -fpic"; // Generates position-independent code (PIC) suitable for use in a shared library Result += " -fno-exceptions"; // Do not enable exception handling, generates extra code needed to propagate exceptions Result += " -fno-rtti"; // Result += " -fno-short-enums"; // Do not allocate to an enum type only as many bytes as it needs for the declared range of possible values // Result += " -finline-limit=64"; // GCC limits the size of functions that can be inlined, this flag allows coarse control of this limit // Result += " -Wno-psabi"; // Warn when G++ generates code that is probably not compatible with the vendor-neutral C++ ABI Result += " -march=armv7-a"; Result += " -mfloat-abi=softfp"; Result += " -mfpu=vfpv3-d16"; //@todo android: UE3 was just vfp. arm7a should all support v3 with 16 registers // Add flags for on-device debugging if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -fno-omit-frame-pointer"; // Disable removing the save/restore frame pointer for better debugging if (ClangVersionFloat >= 3.6f) { Result += " -fno-function-sections"; // Improve breakpoint location } } // Some switches interfere with on-device debugging if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Result += " -ffunction-sections"; // Places each function in its own section of the output file, linker may be able to perform opts to improve locality of reference } Result += " -fsigned-char"; // Treat chars as signed //@todo android: any concerns about ABI compatibility with libs here? } else if (Architecture == "-arm64") { Result += " -funwind-tables"; // Just generates any needed static data, affects no code Result += " -fstack-protector"; // Emits extra code to check for buffer overflows Result += " -fno-strict-aliasing"; // Prevents unwanted or invalid optimizations that could produce incorrect code Result += " -fpic"; // Generates position-independent code (PIC) suitable for use in a shared library Result += " -fno-exceptions"; // Do not enable exception handling, generates extra code needed to propagate exceptions Result += " -fno-rtti"; // Result += " -fno-short-enums"; // Do not allocate to an enum type only as many bytes as it needs for the declared range of possible values Result += " -D__arm64__"; // for some reason this isn't defined and needed for PhysX Result += " -march=armv8-a"; //Result += " -mfloat-abi=softfp"; //Result += " -mfpu=vfpv3-d16"; //@todo android: UE3 was just vfp. arm7a should all support v3 with 16 registers // Some switches interfere with on-device debugging if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Result += " -ffunction-sections"; // Places each function in its own section of the output file, linker may be able to perform opts to improve locality of reference } Result += " -fsigned-char"; // Treat chars as signed //@todo android: any concerns about ABI compatibility with libs here? } else if (Architecture == "-x86") { Result += " -fstrict-aliasing"; Result += " -fno-omit-frame-pointer"; Result += " -fno-strict-aliasing"; Result += " -fno-short-enums"; Result += " -fno-exceptions"; Result += " -fno-rtti"; Result += " -march=atom"; } else if (Architecture == "-x64") { Result += " -fstrict-aliasing"; Result += " -fno-omit-frame-pointer"; Result += " -fno-strict-aliasing"; Result += " -fno-short-enums"; Result += " -fno-exceptions"; Result += " -fno-rtti"; Result += " -march=atom"; } return Result; }
/** Copy constructor. */ protected CPPEnvironment(CPPEnvironment InCopyEnvironment) { PrecompiledHeaderFile = InCopyEnvironment.PrecompiledHeaderFile; PrivateAssemblyDependencies.AddRange(InCopyEnvironment.PrivateAssemblyDependencies); SharedPCHHeaderFiles.AddRange( InCopyEnvironment.SharedPCHHeaderFiles ); SharedPCHEnvironments.AddRange( InCopyEnvironment.SharedPCHEnvironments ); bHackHeaderGenerator = InCopyEnvironment.bHackHeaderGenerator; Config = new CPPEnvironmentConfiguration(InCopyEnvironment.Config); }
string GetCompileArguments_Global(CPPEnvironment CompileEnvironment) { IOSPlatform BuildPlat = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS) as IOSPlatform; BuildPlat.SetUpProjectEnvironment(UnrealTargetPlatform.IOS); string Result = ""; Result += " -fmessage-length=0"; Result += " -pipe"; Result += " -fpascal-strings"; Result += " -fno-exceptions"; Result += " -fno-rtti"; Result += " -fvisibility=hidden"; // hides the linker warnings with PhysX // if (CompileEnvironment.Config.TargetConfiguration == CPPTargetConfiguration.Shipping) // { // Result += " -flto"; // } Result += " -Wall -Werror"; if (CompileEnvironment.Config.bEnableShadowVariableWarning) { Result += " -Wshadow" + (BuildConfiguration.bShadowVariableErrors? "" : " -Wno-error=shadow"); } Result += " -Wno-unused-variable"; Result += " -Wno-unused-value"; // this will hide the warnings about static functions in headers that aren't used in every single .cpp file Result += " -Wno-unused-function"; // this hides the "enumeration value 'XXXXX' not handled in switch [-Wswitch]" warnings - we should maybe remove this at some point and add UE_LOG(, Fatal, ) to default cases Result += " -Wno-switch"; // this hides the "warning : comparison of unsigned expression < 0 is always false" type warnings due to constant comparisons, which are possible with template arguments Result += " -Wno-tautological-compare"; //This will prevent the issue of warnings for unused private variables. Result += " -Wno-unused-private-field"; Result += " -Wno-invalid-offsetof"; // needed to suppress warnings about using offsetof on non-POD types. Result += " -c"; // What architecture(s) to build for Result += GetArchitectureArgument(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture); if (CompileEnvironment.Config.Target.Architecture == "-simulator") { Result += " -isysroot " + BaseSDKDirSim + "/iPhoneSimulator" + IOSSDKVersion + ".sdk"; } else { Result += " -isysroot " + BaseSDKDir + "/iPhoneOS" + IOSSDKVersion + ".sdk"; } Result += " -miphoneos-version-min=" + BuildPlat.GetRunTimeVersion(); // Optimize non- debug builds. if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz"; } else { Result += " -O3"; } } else { Result += " -O0"; } // Create DWARF format debug info if wanted, if (CompileEnvironment.Config.bCreateDebugInfo) { Result += " -gdwarf-2"; } // Add additional frameworks so that their headers can be found foreach (UEBuildFramework Framework in CompileEnvironment.Config.AdditionalFrameworks) { if (Framework.OwningModule != null && Framework.FrameworkZipPath != null && Framework.FrameworkZipPath != "") { Result += " -F \"" + GetRemoteIntermediateFrameworkZipPath(Framework) + "\""; } } return Result; }
public static FileItem CachePCHUsageForModuleSourceFile(UEBuildTarget Target, CPPEnvironment ModuleCompileEnvironment, FileItem CPPFile) { if( !CPPFile.bExists ) { throw new BuildException( "Required source file not found: " + CPPFile.AbsolutePath ); } var PCHCacheTimerStart = DateTime.UtcNow; var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform( ModuleCompileEnvironment.Config.Target.Platform ); var IncludePathsToSearch = ModuleCompileEnvironment.Config.CPPIncludeInfo.GetIncludesPathsToSearch( CPPFile ); // Store the module compile environment along with the .cpp file. This is so that we can use it later on when looking // for header dependencies CPPFile.CachedCPPIncludeInfo = ModuleCompileEnvironment.Config.CPPIncludeInfo; var PCHFile = CachePCHUsageForCPPFile( Target, CPPFile, BuildPlatform, IncludePathsToSearch, ModuleCompileEnvironment.Config.CPPIncludeInfo.IncludeFileSearchDictionary ); if( BuildConfiguration.bPrintPerformanceInfo ) { var PCHCacheTime = ( DateTime.UtcNow - PCHCacheTimerStart ).TotalSeconds; TotalPCHCacheTime += PCHCacheTime; } return PCHFile; }
/// <summary> /// Given a set of C++ files, generates another set of C++ files that #include all the original /// files, the goal being to compile the same code in fewer translation units. /// The "unity" files are written to the CompileEnvironment's OutputDirectory. /// </summary> /// <param name="Target">The target we're building</param> /// <param name="CPPFiles">The C++ files to #include.</param> /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param> /// <param name="BaseName">Base name to use for the Unity files</param> /// <returns>The "unity" C++ files.</returns> public static List<FileItem> GenerateUnityCPPs( UEBuildTarget Target, List<FileItem> CPPFiles, CPPEnvironment CompileEnvironment, string BaseName ) { var ToolChain = UEToolChain.GetPlatformToolChain(CompileEnvironment.Config.Target.Platform); var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not. long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Info.Length); // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file. // // Optimization only makes sense if PCH files are enabled. bool bForceIntoSingleUnityFile = BuildConfiguration.bStressTestUnity || (TotalBytesInCPPFiles < BuildConfiguration.NumIncludedBytesPerUnityCPP * 2 && CompileEnvironment.ShouldUsePCHs()); // Build the list of unity files. List<FileCollection> AllUnityFiles; { var CPPUnityFileBuilder = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : BuildConfiguration.NumIncludedBytesPerUnityCPP); foreach( var CPPFile in CPPFiles ) { if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.Contains(".GeneratedWrapper.")) { CPPUnityFileBuilder.EndCurrentUnityFile(); CPPUnityFileBuilder.AddFile(CPPFile); CPPUnityFileBuilder.EndCurrentUnityFile(); } else { CPPUnityFileBuilder.AddFile(CPPFile); } // Now that the CPPFile is part of this unity file, we will no longer need to treat it like a root level prerequisite for our // dependency cache, as it is now an "indirect include" from the unity file. We'll clear out the compile environment // attached to this file. This prevents us from having to cache all of the indirect includes from these files inside our // dependency cache, which speeds up iterative builds a lot! CPPFile.CachedCPPIncludeInfo = null; } AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles(); } //THIS CHANGE WAS MADE TO FIX THE BUILD IN OUR BRANCH //DO NOT MERGE THIS BACK TO MAIN string PCHHeaderNameInCode = CPPFiles.Count > 0 ? CPPFiles[0].PCHHeaderNameInCode : ""; if( CompileEnvironment.Config.PrecompiledHeaderIncludeFilename != null ) { PCHHeaderNameInCode = ToolChain.ConvertPath( CompileEnvironment.Config.PrecompiledHeaderIncludeFilename ); // Generated unity .cpp files always include the PCH using an absolute path, so we need to update // our compile environment's PCH header name to use this instead of the text it pulled from the original // C++ source files CompileEnvironment.Config.PCHHeaderNameInCode = PCHHeaderNameInCode; } // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding // actions to compile them. int CurrentUnityFileCount = 0; var UnityCPPFiles = new List<FileItem>(); foreach( var UnityFile in AllUnityFiles ) { ++CurrentUnityFileCount; StringWriter OutputUnityCPPWriter = new StringWriter(); StringWriter OutputUnityCPPWriterExtra = null; // add an extra file for UBT to get the #include dependencies from if (BuildPlatform.RequiresExtraUnityCPPWriter() == true) { OutputUnityCPPWriterExtra = new StringWriter(); } OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files."); // Explicitly include the precompiled header first, since Visual C++ expects the first top-level #include to be the header file // that was used to create the PCH. if (CompileEnvironment.Config.PrecompiledHeaderIncludeFilename != null) { OutputUnityCPPWriter.WriteLine("#include \"{0}\"", PCHHeaderNameInCode); if (OutputUnityCPPWriterExtra != null) { OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", PCHHeaderNameInCode); } } // Add source files to the unity file foreach( var CPPFile in UnityFile.Files ) { OutputUnityCPPWriter.WriteLine("#include \"{0}\"", ToolChain.ConvertPath(CPPFile.AbsolutePath)); if (OutputUnityCPPWriterExtra != null) { OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath); } } // Determine unity file path name string UnityCPPFilePath; if (AllUnityFiles.Count > 1) { UnityCPPFilePath = string.Format("Module.{0}.{1}_of_{2}.cpp", BaseName, CurrentUnityFileCount, AllUnityFiles.Count); } else { UnityCPPFilePath = string.Format("Module.{0}.cpp", BaseName); } UnityCPPFilePath = Path.Combine(CompileEnvironment.Config.OutputDirectory, UnityCPPFilePath); // Write the unity file to the intermediate folder. FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString()); if (OutputUnityCPPWriterExtra != null) { FileItem.CreateIntermediateTextFile(UnityCPPFilePath + ".ex", OutputUnityCPPWriterExtra.ToString()); } UnityCPPFile.RelativeCost = UnityFile.TotalLength; UnityCPPFile.PCHHeaderNameInCode = PCHHeaderNameInCode; UnityCPPFiles.Add(UnityCPPFile); // Cache information about the unity .cpp dependencies // @todo ubtmake urgent: Fails when building remotely for Mac because unity .cpp has an include for a PCH on the REMOTE machine UEBuildModuleCPP.CachePCHUsageForModuleSourceFile( Target, CompileEnvironment, UnityCPPFile ); } return UnityCPPFiles; }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName) { var EnvVars = VCEnvironment.SetEnvironment(CompileEnvironment.Config.Target.Platform, false); StringBuilder Arguments = new StringBuilder(); AppendCLArguments_Global(CompileEnvironment, EnvVars, Arguments); // Add include paths to the argument list. foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths) { string IncludePathRelative = Utils.CleanDirectorySeparators(Utils.MakePathRelativeTo(IncludePath, Path.Combine(ProjectFileGenerator.RootRelativePath, "Engine/Source")), '/'); Arguments.AppendFormat(" /I \"{0}\"", IncludePathRelative); } foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths) { string IncludePathRelative = Utils.CleanDirectorySeparators(Utils.MakePathRelativeTo(IncludePath, Path.Combine(ProjectFileGenerator.RootRelativePath, "Engine/Source")), '/'); Arguments.AppendFormat(" /I \"{0}\"", IncludePathRelative); } if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled) { // Add .NET framework assembly paths. This is needed so that C++/CLI projects // can reference assemblies with #using, without having to hard code a path in the // .cpp file to the assembly's location. foreach (string AssemblyPath in CompileEnvironment.Config.SystemDotNetAssemblyPaths) { Arguments.AppendFormat(" /AI \"{0}\"", AssemblyPath); } // Add explicit .NET framework assembly references foreach (string AssemblyName in CompileEnvironment.Config.FrameworkAssemblyDependencies) { Arguments.AppendFormat(" /FU \"{0}\"", AssemblyName); } // Add private assembly references foreach (PrivateAssemblyInfo CurAssemblyInfo in CompileEnvironment.PrivateAssemblyDependencies) { Arguments.AppendFormat(" /FU \"{0}\"", CurAssemblyInfo.FileItem.AbsolutePath); } } // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { // Escape all quotation marks so that they get properly passed with the command line. var DefinitionArgument = Definition.Contains("\"") ? Definition.Replace("\"", "\\\"") : Definition; Arguments.AppendFormat(" /D\"{0}\"", DefinitionArgument); } var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); // Create a compile action for each source file. CPPOutput Result = new CPPOutput(); foreach (FileItem SourceFile in SourceFiles) { Action CompileAction = new Action(ActionType.Compile); CompileAction.CommandDescription = "Compile"; StringBuilder FileArguments = new StringBuilder(); bool bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C"; // Add the C++ source file and its included files to the prerequisite item list. AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems); // If this is a CLR file then make sure our dependent assemblies are added as prerequisites if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled) { foreach (PrivateAssemblyInfo CurPrivateAssemblyDependency in CompileEnvironment.PrivateAssemblyDependencies) { CompileAction.PrerequisiteItems.Add(CurPrivateAssemblyDependency.FileItem); } } bool bEmitsObjectFile = true; if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { // Generate a CPP File that just includes the precompiled header. string PCHCPPFilename = "PCH." + ModuleName + "." + CompileEnvironment.Config.PrecompiledHeaderIncludeFilename.GetFileName() + ".cpp"; FileReference PCHCPPPath = FileReference.Combine(CompileEnvironment.Config.OutputDirectory, PCHCPPFilename); FileItem PCHCPPFile = FileItem.CreateIntermediateTextFile( PCHCPPPath, string.Format("#include \"{0}\"\r\n", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename) ); // Make sure the original source directory the PCH header file existed in is added as an include // path -- it might be a private PCH header and we need to make sure that its found! string OriginalPCHHeaderDirectory = Path.GetDirectoryName(SourceFile.AbsolutePath); FileArguments.AppendFormat(" /I \"{0}\"", OriginalPCHHeaderDirectory); var PrecompiledFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.UWP).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader); // Add the precompiled header file to the produced items list. FileItem PrecompiledHeaderFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, Path.GetFileName(SourceFile.AbsolutePath) + PrecompiledFileExtension ) ); CompileAction.ProducedItems.Add(PrecompiledHeaderFile); Result.PrecompiledHeaderFile = PrecompiledHeaderFile; // Add the parameters needed to compile the precompiled header file to the command-line. FileArguments.AppendFormat(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename); FileArguments.AppendFormat(" /Fp\"{0}\"", PrecompiledHeaderFile.AbsolutePath); // If we're creating a PCH that will be used to compile source files for a library, we need // the compiled modules to retain a reference to PCH's module, so that debugging information // will be included in the library. This is also required to avoid linker warning "LNK4206" // when linking an application that uses this library. if (CompileEnvironment.Config.bIsBuildingLibrary) { // NOTE: The symbol name we use here is arbitrary, and all that matters is that it is // unique per PCH module used in our library string FakeUniquePCHSymbolName = CompileEnvironment.Config.PrecompiledHeaderIncludeFilename.GetFileNameWithoutExtension(); FileArguments.AppendFormat(" /Yl{0}", FakeUniquePCHSymbolName); } FileArguments.AppendFormat(" \"{0}\"", PCHCPPFile.AbsolutePath); CompileAction.StatusDescription = PCHCPPFilename; } else { if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { CompileAction.bIsUsingPCH = true; CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile); FileArguments.AppendFormat(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode); FileArguments.AppendFormat(" /Fp\"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath); // Is it unsafe to always force inclusion? Clang is doing it, and .generated.cpp files // won't work otherwise, because they're not located in the context of the module, // so they can't access the module's PCH without an absolute path. //if( CompileEnvironment.Config.bForceIncludePrecompiledHeader ) { // Force include the precompiled header file. This is needed because we may have selected a // precompiled header that is different than the first direct include in the C++ source file, but // we still need to make sure that our precompiled header is the first thing included! FileArguments.AppendFormat(" /FI\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode); } } // Add the source file path to the command-line. FileArguments.AppendFormat(" \"{0}\"", SourceFile.AbsolutePath); CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath); } if (bEmitsObjectFile) { var ObjectFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.UWP).GetBinaryExtension(UEBuildBinaryType.Object); // Add the object file to the produced item list. FileItem ObjectFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension ) ); CompileAction.ProducedItems.Add(ObjectFile); Result.ObjectFiles.Add(ObjectFile); FileArguments.AppendFormat(" /Fo\"{0}\"", ObjectFile.AbsolutePath); } // Create PDB files if we were configured to do that. // // Also, when debug info is off and XGE is enabled, force PDBs, otherwise it will try to share // a PDB file, which causes PCH creation to be serial rather than parallel (when debug info is disabled) // --> See https://udn.epicgames.com/lists/showpost.php?id=50619&list=unprog3 if (BuildConfiguration.bUsePDBFiles || (BuildConfiguration.bAllowXGE && !CompileEnvironment.Config.bCreateDebugInfo)) { string PDBFileName; bool bActionProducesPDB = false; // All files using the same PCH are required to share the same PDB that was used when compiling the PCH if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { PDBFileName = "PCH." + ModuleName + "." + CompileEnvironment.Config.PrecompiledHeaderIncludeFilename.GetFileName(); } // Files creating a PCH use a PDB per file. else if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { PDBFileName = "PCH." + ModuleName + "." + CompileEnvironment.Config.PrecompiledHeaderIncludeFilename.GetFileName(); bActionProducesPDB = true; } // Ungrouped C++ files use a PDB per file. else if (!bIsPlainCFile) { PDBFileName = Path.GetFileName(SourceFile.AbsolutePath); bActionProducesPDB = true; } // Group all plain C files that doesn't use PCH into the same PDB else { PDBFileName = "MiscPlainC"; } // Specify the PDB file that the compiler should write to. FileItem PDBFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, PDBFileName + ".pdb" ) ); FileArguments.AppendFormat(" /Fd\"{0}\"", PDBFile.AbsolutePath); // Only use the PDB as an output file if we want PDBs and this particular action is // the one that produces the PDB (as opposed to no debug info, where the above code // is needed, but not the output PDB, or when multiple files share a single PDB, so // only the action that generates it should count it as output directly) if (BuildConfiguration.bUsePDBFiles && bActionProducesPDB) { CompileAction.ProducedItems.Add(PDBFile); Result.DebugDataFiles.Add(PDBFile); } } // Add C or C++ specific compiler arguments. if (bIsPlainCFile) { AppendCLArguments_C(FileArguments); } else { AppendCLArguments_CPP(CompileEnvironment, FileArguments); } CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; CompileAction.CommandPath = EnvVars.CompilerPath; CompileAction.CommandArguments = Arguments.ToString() + FileArguments.ToString() + CompileEnvironment.Config.AdditionalArguments; if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { Log.TraceVerbose("Creating PCH: " + CompileEnvironment.Config.PrecompiledHeaderIncludeFilename); Log.TraceVerbose(" Command: " + CompileAction.CommandArguments); } else { Log.TraceVerbose(" Compiling: " + CompileAction.StatusDescription); Log.TraceVerbose(" Command: " + CompileAction.CommandArguments); } // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves CompileAction.bShouldOutputStatusDescription = false; // Don't farm out creation of precompiled headers as it is the critical path task. CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create || BuildConfiguration.bAllowRemotelyCompiledPCHs ; // @todo: XGE has problems remote compiling C++/CLI files that use .NET Framework 4.0 if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled) { CompileAction.bCanExecuteRemotely = false; } } return(Result); }
/// <summary> /// Given a set of C++ files, generates another set of C++ files that #include all the original /// files, the goal being to compile the same code in fewer translation units. /// The "unity" files are written to the CompileEnvironment's OutputDirectory. /// </summary> /// <param name="Target">The target we're building</param> /// <param name="CPPFiles">The C++ files to #include.</param> /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param> /// <param name="BaseName">Base name to use for the Unity files</param> /// <returns>The "unity" C++ files.</returns> public static List <FileItem> GenerateUnityCPPs( UEBuildTarget Target, List <FileItem> CPPFiles, CPPEnvironment CompileEnvironment, string BaseName ) { var ToolChain = UEToolChain.GetPlatformToolChain(CompileEnvironment.Config.Target.Platform); var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not. long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Info.Length); // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file. // // Optimization only makes sense if PCH files are enabled. bool bForceIntoSingleUnityFile = BuildConfiguration.bStressTestUnity || (TotalBytesInCPPFiles < BuildConfiguration.NumIncludedBytesPerUnityCPP * 2 && CompileEnvironment.ShouldUsePCHs()); // Build the list of unity files. List <FileCollection> AllUnityFiles; { var CPPUnityFileBuilder = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : BuildConfiguration.NumIncludedBytesPerUnityCPP); foreach (var CPPFile in CPPFiles) { if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.Contains(".GeneratedWrapper.")) { CPPUnityFileBuilder.EndCurrentUnityFile(); CPPUnityFileBuilder.AddFile(CPPFile); CPPUnityFileBuilder.EndCurrentUnityFile(); } else { CPPUnityFileBuilder.AddFile(CPPFile); } // Now that the CPPFile is part of this unity file, we will no longer need to treat it like a root level prerequisite for our // dependency cache, as it is now an "indirect include" from the unity file. We'll clear out the compile environment // attached to this file. This prevents us from having to cache all of the indirect includes from these files inside our // dependency cache, which speeds up iterative builds a lot! CPPFile.CachedCPPIncludeInfo = null; } AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles(); } //THIS CHANGE WAS MADE TO FIX THE BUILD IN OUR BRANCH //DO NOT MERGE THIS BACK TO MAIN string PCHHeaderNameInCode = CPPFiles.Count > 0 ? CPPFiles[0].PCHHeaderNameInCode : ""; if (CompileEnvironment.Config.PrecompiledHeaderIncludeFilename != null) { PCHHeaderNameInCode = ToolChain.ConvertPath(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename); // Generated unity .cpp files always include the PCH using an absolute path, so we need to update // our compile environment's PCH header name to use this instead of the text it pulled from the original // C++ source files CompileEnvironment.Config.PCHHeaderNameInCode = PCHHeaderNameInCode; } // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding // actions to compile them. int CurrentUnityFileCount = 0; var UnityCPPFiles = new List <FileItem>(); foreach (var UnityFile in AllUnityFiles) { ++CurrentUnityFileCount; StringWriter OutputUnityCPPWriter = new StringWriter(); StringWriter OutputUnityCPPWriterExtra = null; // add an extra file for UBT to get the #include dependencies from if (BuildPlatform.RequiresExtraUnityCPPWriter() == true) { OutputUnityCPPWriterExtra = new StringWriter(); } OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files."); // Explicitly include the precompiled header first, since Visual C++ expects the first top-level #include to be the header file // that was used to create the PCH. if (CompileEnvironment.Config.PrecompiledHeaderIncludeFilename != null) { OutputUnityCPPWriter.WriteLine("#include \"{0}\"", PCHHeaderNameInCode); if (OutputUnityCPPWriterExtra != null) { OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", PCHHeaderNameInCode); } } // Add source files to the unity file foreach (var CPPFile in UnityFile.Files) { OutputUnityCPPWriter.WriteLine("#include \"{0}\"", ToolChain.ConvertPath(CPPFile.AbsolutePath)); if (OutputUnityCPPWriterExtra != null) { OutputUnityCPPWriterExtra.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath); } } // Determine unity file path name string UnityCPPFilePath; if (AllUnityFiles.Count > 1) { UnityCPPFilePath = string.Format("Module.{0}.{1}_of_{2}.cpp", BaseName, CurrentUnityFileCount, AllUnityFiles.Count); } else { UnityCPPFilePath = string.Format("Module.{0}.cpp", BaseName); } UnityCPPFilePath = Path.Combine(CompileEnvironment.Config.OutputDirectory, UnityCPPFilePath); // Write the unity file to the intermediate folder. FileItem UnityCPPFile = FileItem.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString()); if (OutputUnityCPPWriterExtra != null) { FileItem.CreateIntermediateTextFile(UnityCPPFilePath + ".ex", OutputUnityCPPWriterExtra.ToString()); } UnityCPPFile.RelativeCost = UnityFile.TotalLength; UnityCPPFile.PCHHeaderNameInCode = PCHHeaderNameInCode; UnityCPPFiles.Add(UnityCPPFile); // Cache information about the unity .cpp dependencies // @todo ubtmake urgent: Fails when building remotely for Mac because unity .cpp has an include for a PCH on the REMOTE machine UEBuildModuleCPP.CachePCHUsageForModuleSourceFile(Target, CompileEnvironment, UnityCPPFile); } return(UnityCPPFiles); }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName) { if (CompileEnvironment.Config.Target.Architecture == "-win32") // simulator { 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); } if (bEnableTracing) { Arguments += string.Format(" -D__EMSCRIPTEN_TRACING__"); } 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.GetBuildPlatform(UnrealTargetPlatform.HTML5).GetBinaryExtension(UEBuildBinaryType.Object); // Add the object file to the produced item list. FileItem ObjectFile = FileItem.GetItemByFileReference( FileReference.Combine( CompileEnvironment.Config.OutputDirectory, Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension ) ); CompileAction.ProducedItems.Add(ObjectFile); 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 = UnrealBuildTool.EngineSourceDirectory.FullName; CompileAction.CommandPath = HTML5SDKInfo.Python(); CompileAction.CommandArguments = HTML5SDKInfo.EmscriptenCompiler() + " " + 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; }
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); }
static void AppendCLArguments_Global(CPPEnvironment CompileEnvironment, VCEnvironment EnvVars, StringBuilder Arguments) { //Arguments.Append(" /showIncludes"); if (BuildConfiguration.bEnableCodeAnalysis) { Arguments.Append(" /analyze"); // Don't cause analyze warnings to be errors Arguments.Append(" /analyze:WX-"); // Report functions that use a LOT of stack space. You can lower this value if you // want more aggressive checking for functions that use a lot of stack memory. Arguments.Append(" /analyze:stacksize81940"); // Don't bother generating code, only analyze code (may report fewer warnings though.) //Arguments.Append(" /analyze:only"); } // Prevents the compiler from displaying its logo for each invocation. Arguments.Append(" /nologo"); // Enable intrinsic functions. Arguments.Append(" /Oi"); // Pack struct members on 8-byte boundaries. Arguments.Append(" /Zp8"); // Separate functions for linker. Arguments.Append(" /Gy"); // Relaxes floating point precision semantics to allow more optimization. Arguments.Append(" /fp:fast"); // Compile into an .obj file, and skip linking. Arguments.Append(" /c"); // Allow 800% of the default memory allocation limit. Arguments.Append(" /Zm800"); // Allow large object files to avoid hitting the 2^16 section limit when running with -StressTestUnity. Arguments.Append(" /bigobj"); // Disable "The file contains a character that cannot be represented in the current code page" warning for non-US windows. Arguments.Append(" /wd4819"); // @todo UWP: Disable "unreachable code" warning since auto-included vccorlib.h triggers it Arguments.Append(" /wd4702"); // @todo UWP: Silence the hash_map deprecation errors for now. This should be replaced with unordered_map for the real fix. if (WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2015) { Arguments.Append(" /D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS"); } if (BuildConfiguration.bUseSharedPCHs) { // @todo SharedPCH: Disable warning about PCH defines not matching .cpp defines. We "cheat" these defines a little // bit to make shared PCHs work. But it's totally safe. Trust us. Arguments.Append(" /wd4651"); // @todo SharedPCH: Disable warning about redefining *API macros. The PCH header is compiled with various DLLIMPORTs, but // when a module that uses that PCH header *IS* one of those imports, that module is compiled with EXPORTS, so the macro // is redefined on the command-line. We need to clobber those defines to make shared PCHs work properly! Arguments.Append(" /wd4005"); } // If compiling as a DLL, set the relevant defines if (CompileEnvironment.Config.bIsBuildingDLL) { Arguments.Append(" /D_WINDLL"); } // Handle Common Language Runtime support (C++/CLI) if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled) { Arguments.Append(" /clr"); // Don't use default lib path, we override it explicitly to use the 4.0 reference assemblies. Arguments.Append(" /clr:nostdlib"); } // // Debug // if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { // Disable compiler optimization. Arguments.Append(" /Od"); // Favor code size (especially useful for embedded platforms). Arguments.Append(" /Os"); // Allow inline method expansion unless E&C support is requested if (!BuildConfiguration.bSupportEditAndContinue) { // @todo UWP: No inlining in Debug builds except in the editor where DLL exports/imports aren't handled properly in module _API macros. if (UEBuildConfiguration.bBuildEditor) { Arguments.Append(" /Ob2"); } } // Runtime stack checks are not allowed when compiling for CLR if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLRDisabled) { Arguments.Append(" /RTCs"); } } // // Development and LTCG // else { // Maximum optimizations if desired. if (CompileEnvironment.Config.OptimizeCode >= ModuleRules.CodeOptimization.InNonDebugBuilds) { Arguments.Append(" /Ox"); // Allow optimized code to be debugged more easily. This makes PDBs a bit larger, but doesn't noticeably affect // compile times. The executable code is not affected at all by this switch, only the debugging information. Arguments.Append(" /Zo"); } // Favor code speed. Arguments.Append(" /Ot"); // Only omit frame pointers on the PC (which is implied by /Ox) if wanted. if (BuildConfiguration.bOmitFramePointers == false && (CompileEnvironment.Config.Target.Platform == CPPTargetPlatform.UWP)) { Arguments.Append(" /Oy-"); } // Allow inline method expansion Arguments.Append(" /Ob2"); // // LTCG // if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { if (BuildConfiguration.bAllowLTCG) { // Enable link-time code generation. Arguments.Append(" /GL"); } } } // // PC // // Prompt the user before reporting internal errors to Microsoft. Arguments.Append(" /errorReport:prompt"); // Enable C++ exception handling, but not C exceptions. Arguments.Append(" /EHsc"); // If enabled, create debug information. if (CompileEnvironment.Config.bCreateDebugInfo) { // Store debug info in .pdb files. if (BuildConfiguration.bUsePDBFiles) { // Create debug info suitable for E&C if wanted. if (BuildConfiguration.bSupportEditAndContinue && // We only need to do this in debug as that's the only configuration that supports E&C. CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Arguments.Append(" /ZI"); } // Regular PDB debug information. else { Arguments.Append(" /Zi"); } // We need to add this so VS won't lock the PDB file and prevent synchronous updates. This forces serialization through MSPDBSRV.exe. // See http://msdn.microsoft.com/en-us/library/dn502518.aspx for deeper discussion of /FS switch. if (BuildConfiguration.bUseIncrementalLinking && WindowsPlatform.Compiler >= WindowsCompiler.VisualStudio2013) { Arguments.Append(" /FS"); } } // Store C7-format debug info in the .obj files, which is faster. else { Arguments.Append(" /Z7"); } } // Specify the appropriate runtime library based on the platform and config. if (CompileEnvironment.Config.bUseStaticCRT) { if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug && BuildConfiguration.bDebugBuildsActuallyUseDebugCRT) { Arguments.Append(" /MTd"); } else { Arguments.Append(" /MT"); } } else { if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug && BuildConfiguration.bDebugBuildsActuallyUseDebugCRT) { Arguments.Append(" /MDd"); } else { Arguments.Append(" /MD"); } } if (UWPPlatform.bBuildForStore) { Arguments.Append(" /D_BUILD_FOR_STORE=1"); } if (WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2015) { // @todo UWP: These must be appended to the end of the system include list, lest they override some of the third party sources includes if (Directory.Exists(EnvVars.WindowsSDKExtensionDir)) { CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add(string.Format(@"{0}\Include\{1}\ucrt", EnvVars.WindowsSDKExtensionDir, EnvVars.WindowsSDKExtensionHeaderLibVersion)); CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add(string.Format(@"{0}\Include\{1}\um", EnvVars.WindowsSDKExtensionDir, EnvVars.WindowsSDKExtensionHeaderLibVersion)); CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add(string.Format(@"{0}\Include\{1}\shared", EnvVars.WindowsSDKExtensionDir, EnvVars.WindowsSDKExtensionHeaderLibVersion)); CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add(string.Format(@"{0}\Include\{1}\winrt", EnvVars.WindowsSDKExtensionDir, EnvVars.WindowsSDKExtensionHeaderLibVersion)); } } if (CompileEnvironment.Config.bIsBuildingLibrary == false) // will put in a config option, but for now... { // Enable Windows Runtime extensions Arguments.Append(" /ZW"); Arguments.Append(" /DUSE_WINRT_MAIN=1"); // TODO - richiem - this will have to be updated when final layout SDKs are available if (WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2015 && Directory.Exists(Path.Combine(EnvVars.WindowsSDKExtensionDir, "UnionMetadata"))) { Arguments.AppendFormat(@" /AI""{0}\UnionMetadata""", EnvVars.WindowsSDKExtensionDir); Arguments.AppendFormat(@" /FU""{0}\UnionMetadata\windows.winmd""", EnvVars.WindowsSDKExtensionDir); } Arguments.AppendFormat(@" /AI""{0}\..\..\VC\vcpackages""", EnvVars.BaseVSToolPath); Arguments.AppendFormat(@" /FU""{0}\..\..\VC\vcpackages\platform.winmd""", EnvVars.BaseVSToolPath); } }
/// <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); }
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment) { string Result = GetSharedArguments_Global(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture); if (CompileEnvironment.Config.Target.Architecture != "-win32") { // do we want debug info? /* if (CompileEnvironment.Config.bCreateDebugInfo) { Result += " -g"; }*/ Result += " -Wno-warn-absolute-paths "; if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -O0"; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { Result += " -s GL_ASSERTIONS=1 "; } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Development) { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000"; } else { Result += " -O2 -s ASM_JS=1 -s OUTLINING_LIMIT=110000"; } } if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz -s ASM_JS=1 -s OUTLINING_LIMIT=40000"; } else { Result += " -O3 -s ASM_JS=1 -s OUTLINING_LIMIT=110000"; } } } return Result; }
protected void AddPrerequisiteSourceFile(UEBuildTarget Target, UEBuildPlatform BuildPlatform, CPPEnvironment CompileEnvironment, FileItem SourceFile, List<FileItem> PrerequisiteItems) { PrerequisiteItems.Add(SourceFile); RemoteToolChain RemoteThis = this as RemoteToolChain; bool bAllowUploading = RemoteThis != null && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac; // Don't use remote features when compiling from a Mac if (bAllowUploading) { RemoteThis.QueueFileForBatchUpload(SourceFile); } if (!BuildConfiguration.bUseUBTMakefiles) // In fast build iteration mode, we'll gather includes later on { // @todo ubtmake: What if one of the prerequisite files has become missing since it was updated in our cache? (usually, because a coder eliminated the source file) // -> Two CASES: // 1) NOT WORKING: Non-unity file went away (SourceFile in this context). That seems like an existing old use case. Compile params or Response file should have changed? // 2) WORKING: Indirect file went away (unity'd original source file or include). This would return a file that no longer exists and adds to the prerequiteitems list List<FileItem> IncludedFileList = CPPEnvironment.FindAndCacheAllIncludedFiles(Target, SourceFile, BuildPlatform, CompileEnvironment.Config.CPPIncludeInfo, bOnlyCachedDependencies: BuildConfiguration.bUseUBTMakefiles); if (IncludedFileList != null) { foreach (FileItem IncludedFile in IncludedFileList) { PrerequisiteItems.Add(IncludedFile); if (bAllowUploading && !BuildConfiguration.bUseUBTMakefiles) // With fast dependency scanning, we will not have an exhaustive list of dependencies here. We rely on PostCodeGeneration() to upload these files. { RemoteThis.QueueFileForBatchUpload(IncludedFile); } } } } }
// 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 ); }
public virtual CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List<FileItem> RCFiles) { CPPOutput Result = new CPPOutput(); return Result; }
/** Compiles the module, and returns a list of files output by the compiler. */ public abstract List<FileItem> Compile( CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment );
static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment) { string Result = ""; if (CompileEnvironment.Config.Target.Architecture != "-win32") // ! simulator { Result = " -std=c++11"; } return Result; }
public virtual CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List <FileItem> RCFiles) { CPPOutput Result = new CPPOutput(); return(Result); }
public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List<FileItem> RCFiles) { CPPOutput Result = new CPPOutput(); if (Environment.Config.Target.Architecture == "-win32") // simulator { return base.CompileRCFiles(Target, Environment, RCFiles); } return Result; }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName) { var Arguments = new StringBuilder(); var PCHArguments = new StringBuilder(); Arguments.Append(GetCompileArguments_Global(CompileEnvironment)); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { // Add the precompiled header file's path to the include path so GCC can find it. // This needs to be before the other include paths to ensure GCC uses it instead of the source header file. var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Mac].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader); PCHArguments.Append(" -include \""); PCHArguments.Append(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(PrecompiledFileExtension, "")); PCHArguments.Append("\""); } // Add include paths to the argument list. HashSet<string> AllIncludes = new HashSet<string>(CompileEnvironment.Config.CPPIncludeInfo.IncludePaths); AllIncludes.UnionWith(CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths); foreach (string IncludePath in AllIncludes) { Arguments.Append(" -I\""); if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) { Arguments.Append(ConvertPath(Path.GetFullPath(IncludePath))); // sync any third party headers we may need if (IncludePath.Contains("ThirdParty")) { string[] FileList = Directory.GetFiles(IncludePath, "*.h", SearchOption.AllDirectories); foreach (string File in FileList) { FileItem ExternalDependency = FileItem.GetItemByPath(File); LocalToRemoteFileItem(ExternalDependency, true); } FileList = Directory.GetFiles(IncludePath, "*.cpp", SearchOption.AllDirectories); foreach (string File in FileList) { FileItem ExternalDependency = FileItem.GetItemByPath(File); LocalToRemoteFileItem(ExternalDependency, true); } } } else { Arguments.Append(IncludePath); } Arguments.Append("\""); } foreach (string Definition in CompileEnvironment.Config.Definitions) { Arguments.Append(" -D\""); Arguments.Append(Definition); Arguments.Append("\""); } var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); CPPOutput Result = new CPPOutput(); // Create a compile action for each source file. foreach (FileItem SourceFile in SourceFiles) { Action CompileAction = new Action(ActionType.Compile); string FileArguments = ""; string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant(); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { // Compile the file as a C++ PCH. FileArguments += GetCompileArguments_PCH(); } else if (Extension == ".C") { // Compile the file as C code. FileArguments += GetCompileArguments_C(); } else if (Extension == ".CC") { // Compile the file as C++ code. FileArguments += GetCompileArguments_CPP(); } else if (Extension == ".MM") { // Compile the file as Objective-C++ code. FileArguments += GetCompileArguments_MM(); } else if (Extension == ".M") { // Compile the file as Objective-C++ code. FileArguments += GetCompileArguments_M(); } else { // Compile the file as C++ code. FileArguments += GetCompileArguments_CPP(); // only use PCH for .cpp files FileArguments += PCHArguments.ToString(); } // 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 PrecompiledHeaderExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Mac].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) + PrecompiledHeaderExtension ) ); FileItem RemotePrecompiledHeaderFile = LocalToRemoteFileItem(PrecompiledHeaderFile, false); CompileAction.ProducedItems.Add(RemotePrecompiledHeaderFile); Result.PrecompiledHeaderFile = RemotePrecompiledHeaderFile; // Add the parameters needed to compile the precompiled header file to the command-line. FileArguments += string.Format(" -o \"{0}\"", RemotePrecompiledHeaderFile.AbsolutePath, false); } else { if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include) { CompileAction.bIsUsingPCH = true; CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile); } var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.Mac].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 ) ); FileItem RemoteObjectFile = LocalToRemoteFileItem(ObjectFile, false); CompileAction.ProducedItems.Add(RemoteObjectFile); Result.ObjectFiles.Add(RemoteObjectFile); FileArguments += string.Format(" -o \"{0}\"", RemoteObjectFile.AbsolutePath, false); } // Add the source file path to the command-line. FileArguments += string.Format(" \"{0}\"", ConvertPath(SourceFile.AbsolutePath), false); if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) { CompileAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler); } CompileAction.WorkingDirectory = GetMacDevSrcRoot(); CompileAction.CommandPath = ToolchainDir + MacCompiler; CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments; CompileAction.CommandDescription = "Compile"; CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath); CompileAction.bIsGCCCompiler = true; // We're already distributing the command by execution on Mac. CompileAction.bCanExecuteRemotely = false; CompileAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler); } return Result; }
public void CachePCHUsageForModuleSourceFiles(CPPEnvironment ModuleCompileEnvironment) { if( ProcessedDependencies == null ) { var PCHCacheTimerStart = DateTime.UtcNow; var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform( ModuleCompileEnvironment.Config.Target.Platform ); bool bFoundAProblemWithPCHs = false; FileItem UniquePCH = null; foreach( var CPPFile in SourceFilesFound.CPPFiles ) // @todo ubtmake: We're not caching CPPEnvironments for .c/.mm files, etc. Even though they don't use PCHs, they still have #includes! This can break dependency checking! { // Build a single list of include paths to search. var IncludePathsToSearch = ModuleCompileEnvironment.Config.CPPIncludeInfo.GetIncludesPathsToSearch( CPPFile ); // Store the module compile environment along with the .cpp file. This is so that we can use it later on when looking // for header dependencies CPPFile.CachedCPPIncludeInfo = ModuleCompileEnvironment.Config.CPPIncludeInfo; // Find headers used by the source file. var PCH = UEBuildModuleCPP.CachePCHUsageForCPPFile(Target, CPPFile, BuildPlatform, IncludePathsToSearch, ModuleCompileEnvironment.Config.CPPIncludeInfo.IncludeFileSearchDictionary); if( PCH == null ) { throw new BuildException( "Source file \"{0}\" is not including any headers. We expect all modules to include a header file for precompiled header generation. Please add an #include statement.", CPPFile.AbsolutePath ); } if( UniquePCH == null ) { UniquePCH = PCH; } else if( !UniquePCH.Info.Name.Equals( PCH.Info.Name, StringComparison.InvariantCultureIgnoreCase ) ) // @todo ubtmake: We do a string compare on the file name (not path) here, because sometimes the include resolver will pick an Intermediate copy of a PCH header file and throw off our comparisons { // OK, looks like we have multiple source files including a different header file first. We'll keep track of this and print out // helpful information afterwards. bFoundAProblemWithPCHs = true; } } ProcessedDependencies = new ProcessedDependenciesClass{ UniquePCHHeaderFile = UniquePCH }; if( bFoundAProblemWithPCHs ) { // Map from pch header string to the source files that use that PCH var UsageMapPCH = new Dictionary<string, List<FileItem>>( StringComparer.InvariantCultureIgnoreCase ); foreach( var CPPFile in SourceFilesToBuild.CPPFiles ) { // Create a new entry if not in the pch usage map UsageMapPCH.GetOrAddNew( CPPFile.PrecompiledHeaderIncludeFilename ).Add( CPPFile ); } if( BuildConfiguration.bPrintDebugInfo ) { Log.TraceVerbose( "{0} PCH files for module {1}:", UsageMapPCH.Count, Name ); int MostFilesIncluded = 0; foreach( var CurPCH in UsageMapPCH ) { if( CurPCH.Value.Count > MostFilesIncluded ) { MostFilesIncluded = CurPCH.Value.Count; } Log.TraceVerbose(" {0} ({1} files including it: {2}, ...)", CurPCH.Key, CurPCH.Value.Count, CurPCH.Value[0].AbsolutePath); } } if( UsageMapPCH.Count > 1 ) { // Keep track of the PCH file that is most used within this module string MostFilesAreIncludingPCH = string.Empty; int MostFilesIncluded = 0; foreach( var CurPCH in UsageMapPCH.Where( PCH => PCH.Value.Count > MostFilesIncluded ) ) { MostFilesAreIncludingPCH = CurPCH.Key; MostFilesIncluded = CurPCH.Value.Count; } // Find all of the files that are not including our "best" PCH header var FilesNotIncludingBestPCH = new StringBuilder(); foreach( var CurPCH in UsageMapPCH.Where( PCH => PCH.Key != MostFilesAreIncludingPCH ) ) { foreach( var SourceFile in CurPCH.Value ) { FilesNotIncludingBestPCH.AppendFormat( "{0} (including {1})\n", SourceFile.AbsolutePath, CurPCH.Key ); } } // Bail out and let the user know which source files may need to be fixed up throw new BuildException( "All source files in module \"{0}\" must include the same precompiled header first. Currently \"{1}\" is included by most of the source files. The following source files are not including \"{1}\" as their first include:\n\n{2}", Name, MostFilesAreIncludingPCH, FilesNotIncludingBestPCH ); } } if( BuildConfiguration.bPrintPerformanceInfo ) { var PCHCacheTime = ( DateTime.UtcNow - PCHCacheTimerStart ).TotalSeconds; TotalPCHCacheTime += PCHCacheTime; } } }
static string GetCLArguments_Global(CPPEnvironment CompileEnvironment, string Architecture) { string Result = ""; switch (Architecture) { case "-armv7": Result += ToolchainParamsArm; break; case "-arm64": Result += ToolchainParamsArm64; break; case "-x86": Result += ToolchainParamsx86; break; case "-x64": Result += ToolchainParamsx64; break; default: Result += ToolchainParamsArm; break; } // build up the commandline common to C and C++ Result += " -c"; Result += " -fdiagnostics-format=msvc"; Result += " -Wall"; Result += " -Wno-unused-variable"; // this will hide the warnings about static functions in headers that aren't used in every single .cpp file Result += " -Wno-unused-function"; // this hides the "enumeration value 'XXXXX' not handled in switch [-Wswitch]" warnings - we should maybe remove this at some point and add UE_LOG(, Fatal, ) to default cases Result += " -Wno-switch"; // this hides the "warning : comparison of unsigned expression < 0 is always false" type warnings due to constant comparisons, which are possible with template arguments Result += " -Wno-tautological-compare"; //This will prevent the issue of warnings for unused private variables. Result += " -Wno-unused-private-field"; Result += " -Wno-local-type-template-args"; // engine triggers this Result += " -Wno-return-type-c-linkage"; // needed for PhysX Result += " -Wno-reorder"; // member initialization order Result += " -Wno-unknown-pragmas"; // probably should kill this one, sign of another issue in PhysX? Result += " -Wno-invalid-offsetof"; // needed to suppress warnings about using offsetof on non-POD types. Result += " -Wno-logical-op-parentheses"; // needed for external headers we can't change if (CompileEnvironment.Config.bEnableShadowVariableWarning) { Result += " -Wshadow -Wno-error=shadow"; } // new for clang4.5 warnings: if (ClangVersionFloat >= 3.5f) { Result += " -Wno-undefined-bool-conversion"; // 'this' pointer cannot be null in well-defined C++ code; pointer may be assumed to always convert to true (if (this)) } if (ClangVersionFloat >= 3.6f) { Result += " -Wno-unused-local-typedef"; // clang is being overly strict here? PhysX headers trigger this. Result += " -Wno-inconsistent-missing-override"; // these have to be suppressed for UE 4.8, should be fixed later. } // shipping builds will cause this warning with "ensure", so disable only in those case if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping) { Result += " -Wno-unused-value"; } // debug info if (CompileEnvironment.Config.bCreateDebugInfo) { Result += " -g2 -gdwarf-2"; } // optimization level if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -O0"; } else { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz"; } else { Result += " -O3"; } } //@todo android: these are copied verbatim from UE3 and probably need adjustment if (Architecture == "-armv7") { // Result += " -mthumb-interwork"; // Generates code which supports calling between ARM and Thumb instructions, w/o it you can't reliability use both together Result += " -funwind-tables"; // Just generates any needed static data, affects no code Result += " -fstack-protector"; // Emits extra code to check for buffer overflows // Result += " -mlong-calls"; // Perform function calls by first loading the address of the function into a reg and then performing the subroutine call Result += " -fno-strict-aliasing"; // Prevents unwanted or invalid optimizations that could produce incorrect code Result += " -fpic"; // Generates position-independent code (PIC) suitable for use in a shared library Result += " -fno-exceptions"; // Do not enable exception handling, generates extra code needed to propagate exceptions Result += " -fno-rtti"; // Result += " -fno-short-enums"; // Do not allocate to an enum type only as many bytes as it needs for the declared range of possible values // Result += " -finline-limit=64"; // GCC limits the size of functions that can be inlined, this flag allows coarse control of this limit // Result += " -Wno-psabi"; // Warn when G++ generates code that is probably not compatible with the vendor-neutral C++ ABI Result += " -march=armv7-a"; Result += " -mfloat-abi=softfp"; Result += " -mfpu=vfpv3-d16"; //@todo android: UE3 was just vfp. arm7a should all support v3 with 16 registers // Add flags for on-device debugging if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug) { Result += " -fno-omit-frame-pointer"; // Disable removing the save/restore frame pointer for better debugging if (ClangVersionFloat >= 3.6f) { Result += " -fno-function-sections"; // Improve breakpoint location } } // Some switches interfere with on-device debugging if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Result += " -ffunction-sections"; // Places each function in its own section of the output file, linker may be able to perform opts to improve locality of reference } Result += " -fsigned-char"; // Treat chars as signed //@todo android: any concerns about ABI compatibility with libs here? } else if (Architecture == "-arm64") { Result += " -funwind-tables"; // Just generates any needed static data, affects no code Result += " -fstack-protector"; // Emits extra code to check for buffer overflows Result += " -fno-strict-aliasing"; // Prevents unwanted or invalid optimizations that could produce incorrect code Result += " -fpic"; // Generates position-independent code (PIC) suitable for use in a shared library Result += " -fno-exceptions"; // Do not enable exception handling, generates extra code needed to propagate exceptions Result += " -fno-rtti"; // Result += " -fno-short-enums"; // Do not allocate to an enum type only as many bytes as it needs for the declared range of possible values Result += " -march=armv8-a"; //Result += " -mfloat-abi=softfp"; //Result += " -mfpu=vfpv3-d16"; //@todo android: UE3 was just vfp. arm7a should all support v3 with 16 registers // Some switches interfere with on-device debugging if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Result += " -ffunction-sections"; // Places each function in its own section of the output file, linker may be able to perform opts to improve locality of reference } Result += " -fsigned-char"; // Treat chars as signed //@todo android: any concerns about ABI compatibility with libs here? } else if (Architecture == "-x86") { Result += " -fstrict-aliasing"; Result += " -fno-omit-frame-pointer"; Result += " -fno-strict-aliasing"; Result += " -fno-short-enums"; Result += " -fno-exceptions"; Result += " -fno-rtti"; Result += " -march=atom"; } else if (Architecture == "-x64") { Result += " -fstrict-aliasing"; Result += " -fno-omit-frame-pointer"; Result += " -fno-strict-aliasing"; Result += " -fno-short-enums"; Result += " -fno-exceptions"; Result += " -fno-rtti"; Result += " -march=atom"; } return Result; }
public override CPPOutput CompileRCFiles(UEBuildTarget Target, CPPEnvironment Environment, List <FileItem> RCFiles) { var EnvVars = VCEnvironment.SetEnvironment(Environment.Config.Target.Platform, false); CPPOutput Result = new CPPOutput(); var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(Environment.Config.Target.Platform); foreach (FileItem RCFile in RCFiles) { Action CompileAction = new Action(ActionType.Compile); CompileAction.CommandDescription = "Resource"; CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; CompileAction.CommandPath = EnvVars.ResourceCompilerPath; CompileAction.StatusDescription = Path.GetFileName(RCFile.AbsolutePath); // Suppress header spew CompileAction.CommandArguments += " /nologo"; // If we're compiling for 64-bit Windows, also add the _WIN64 definition to the resource // compiler so that we can switch on that in the .rc file using #ifdef. CompileAction.CommandArguments += " /D_WIN64"; // Language CompileAction.CommandArguments += " /l 0x409"; // Include paths. foreach (string IncludePath in Environment.Config.CPPIncludeInfo.IncludePaths) { CompileAction.CommandArguments += string.Format(" /i \"{0}\"", IncludePath); } // System include paths. foreach (var SystemIncludePath in Environment.Config.CPPIncludeInfo.SystemIncludePaths) { CompileAction.CommandArguments += string.Format(" /i \"{0}\"", SystemIncludePath); } // Preprocessor definitions. foreach (string Definition in Environment.Config.Definitions) { CompileAction.CommandArguments += string.Format(" /d \"{0}\"", Definition); } // Add the RES file to the produced item list. FileItem CompiledResourceFile = FileItem.GetItemByFileReference( FileReference.Combine( Environment.Config.OutputDirectory, Path.GetFileName(RCFile.AbsolutePath) + ".res" ) ); CompileAction.ProducedItems.Add(CompiledResourceFile); CompileAction.CommandArguments += string.Format(" /fo \"{0}\"", CompiledResourceFile.AbsolutePath); Result.ObjectFiles.Add(CompiledResourceFile); // Add the RC file as a prerequisite of the action. CompileAction.CommandArguments += string.Format(" \"{0}\"", RCFile.AbsolutePath); // Add the C++ source file and its included files to the prerequisite item list. AddPrerequisiteSourceFile(Target, BuildPlatform, Environment, RCFile, CompileAction.PrerequisiteItems); } return(Result); }
// 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; }
/// <summary> /// Finds the files directly or indirectly included by the given C++ file. /// </summary> /// <param name="CPPFile">C++ file to get the dependencies for.</param> /// <param name="Result">List of CPPFile dependencies.</param> /// <returns>false if CPPFile is still being processed further down the callstack, true otherwise.</returns> public static bool FindAndCacheAllIncludedFiles(UEBuildTarget Target, FileItem CPPFile, UEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, ref IncludedFilesSet Result, bool bOnlyCachedDependencies) { IncludedFilesSet IncludedFileList; Dictionary <FileItem, IncludedFilesSet> IncludedFilesMap = bOnlyCachedDependencies ? OnlyCachedIncludedFilesMap : ExhaustiveIncludedFilesMap; if (!IncludedFilesMap.TryGetValue(CPPFile, out IncludedFileList)) { DateTime TimerStartTime = DateTime.UtcNow; IncludedFileList = new IncludedFilesSet(); // Add an uninitialized entry for the include file to avoid infinitely recursing on include file loops. IncludedFilesMap.Add(CPPFile, IncludedFileList); // Gather a list of names of files directly included by this C++ file. List <DependencyInclude> DirectIncludes = GetDirectIncludeDependencies(Target, CPPFile, BuildPlatform, bOnlyCachedDependencies: bOnlyCachedDependencies); // Build a list of the unique set of files that are included by this file. HashSet <FileItem> DirectlyIncludedFiles = new HashSet <FileItem>(); // require a for loop here because we need to keep track of the index in the list. for (int DirectlyIncludedFileNameIndex = 0; DirectlyIncludedFileNameIndex < DirectIncludes.Count; ++DirectlyIncludedFileNameIndex) { // Resolve the included file name to an actual file. DependencyInclude DirectInclude = DirectIncludes[DirectlyIncludedFileNameIndex]; if (!DirectInclude.HasAttemptedResolve || // ignore any preexisting resolve cache if we are not configured to use it. !BuildConfiguration.bUseIncludeDependencyResolveCache || // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts BuildConfiguration.bTestIncludeDependencyResolveCache ) { ++TotalDirectIncludeResolveCacheMisses; // search the include paths to resolve the file FileItem DirectIncludeResolvedFile = CPPEnvironment.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, CPPIncludeInfo.GetIncludesPathsToSearch(CPPFile), CPPIncludeInfo.IncludeFileSearchDictionary); if (DirectIncludeResolvedFile != null) { DirectlyIncludedFiles.Add(DirectIncludeResolvedFile); } IncludeDependencyCache[Target].CacheResolvedIncludeFullPath(CPPFile, DirectlyIncludedFileNameIndex, DirectIncludeResolvedFile != null ? DirectIncludeResolvedFile.Reference : null); } else { // we might have cached an attempt to resolve the file, but couldn't actually find the file (system headers, etc). if (DirectInclude.IncludeResolvedNameIfSuccessful != null) { DirectlyIncludedFiles.Add(FileItem.GetItemByFileReference(DirectInclude.IncludeResolvedNameIfSuccessful)); } } } TotalDirectIncludeResolves += DirectIncludes.Count; // Convert the dictionary of files included by this file into a list. foreach (FileItem DirectlyIncludedFile in DirectlyIncludedFiles) { // Add the file we're directly including IncludedFileList.Add(DirectlyIncludedFile); // Also add all of the indirectly included files! if (FindAndCacheAllIncludedFiles(Target, DirectlyIncludedFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies: bOnlyCachedDependencies) == false) { // DirectlyIncludedFile is a circular dependency which is still being processed // further down the callstack. Add this file to its circular dependencies list // so that it can update its dependencies later. IncludedFilesSet DirectlyIncludedFileIncludedFileList; if (IncludedFilesMap.TryGetValue(DirectlyIncludedFile, out DirectlyIncludedFileIncludedFileList)) { DirectlyIncludedFileIncludedFileList.CircularDependencies.Add(CPPFile); } } } // All dependencies have been processed by now so update all circular dependencies // with the full list. foreach (FileItem CircularDependency in IncludedFileList.CircularDependencies) { IncludedFilesSet CircularDependencyIncludedFiles = IncludedFilesMap[CircularDependency]; foreach (FileItem IncludedFile in IncludedFileList) { CircularDependencyIncludedFiles.Add(IncludedFile); } } // No need to keep this around anymore. IncludedFileList.CircularDependencies.Clear(); // Done collecting files. IncludedFileList.bIsInitialized = true; TimeSpan TimerDuration = DateTime.UtcNow - TimerStartTime; TotalTimeSpentGettingIncludes += TimerDuration.TotalSeconds; } if (IncludedFileList.bIsInitialized) { // Copy the list of files included by this file into the result list. foreach (FileItem IncludedFile in IncludedFileList) { // If the result list doesn't contain this file yet, add the file and the files it includes. // NOTE: For some reason in .NET 4, Add() is over twice as fast as calling UnionWith() on the set Result.Add(IncludedFile); } return(true); } else { // The IncludedFileList.bIsInitialized was false because we added a dummy entry further down the call stack. We're already processing // the include list for this header elsewhere in the stack frame, so we don't need to add anything here. return(false); } }
/// <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; }
static string GetCompileArguments_Global(CPPEnvironment CompileEnvironment) { string Result = ""; Result += " -fmessage-length=0"; Result += " -pipe"; Result += " -fpascal-strings"; Result += " -fexceptions"; Result += " -fasm-blocks"; Result += " -Wall -Werror"; Result += " -Wno-unused-variable"; Result += " -Wno-unused-value"; // This will hide the warnings about static functions in headers that aren't used in every single .cpp file Result += " -Wno-unused-function"; // This hides the "enumeration value 'XXXXX' not handled in switch [-Wswitch]" warnings - we should maybe remove this at some point and add UE_LOG(, Fatal, ) to default cases Result += " -Wno-switch"; // This hides the "warning : comparison of unsigned expression < 0 is always false" type warnings due to constant comparisons, which are possible with template arguments Result += " -Wno-tautological-compare"; // This will prevent the issue of warnings for unused private variables. Result += " -Wno-unused-private-field"; Result += " -Wno-invalid-offsetof"; // needed to suppress warnings about using offsetof on non-POD types. if (MacOSSDKVersionFloat < 10.9f && MacOSSDKVersionFloat >= 10.11f) { Result += " -Wno-inconsistent-missing-override"; // too many missing overrides... Result += " -Wno-unused-local-typedef"; // PhysX has some, hard to remove } if (CompileEnvironment.Config.bEnableShadowVariableWarning) { Result += " -Wshadow" + (BuildConfiguration.bShadowVariableErrors? "" : " -Wno-error=shadow"); } // @todo: Remove these two when the code is fixed and they're no longer needed Result += " -Wno-logical-op-parentheses"; Result += " -Wno-unknown-pragmas"; Result += " -c"; Result += " -arch x86_64"; Result += " -isysroot " + BaseSDKDir + "/MacOSX" + MacOSSDKVersion + ".sdk"; Result += " -mmacosx-version-min=" + MacOSVersion; // Optimize non- debug builds. if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { if (UEBuildConfiguration.bCompileForSize) { Result += " -Oz"; } else { Result += " -O3"; } } else { Result += " -O0"; } // Create DWARF format debug info if wanted, if (CompileEnvironment.Config.bCreateDebugInfo) { Result += " -gdwarf-2"; } return Result; }
private PrecompileHeaderEnvironment ApplySharedPCH(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment, CPPEnvironment ModuleCompileEnvironment, List<FileItem> CPPFiles, ref FileItem SharedPCHHeaderFile) { // Check to see if we have a PCH header already setup that we can use var SharedPCHHeaderFileCopy = SharedPCHHeaderFile; var SharedPCHEnvironment = GlobalCompileEnvironment.SharedPCHEnvironments.Find(Env => Env.PrecompiledHeaderIncludeFilename == SharedPCHHeaderFileCopy); if (SharedPCHEnvironment == null) { return null; } // Don't mix CLR modes if (SharedPCHEnvironment.CLRMode != ModuleCompileEnvironment.Config.CLRMode) { Log.TraceVerbose("Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because CLR modes don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName); SharedPCHHeaderFile = null; return null; } // Don't mix RTTI modes if (bUseRTTI) { Log.TraceVerbose("Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because RTTI modes don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName); SharedPCHHeaderFile = null; return null; } // Don't mix non-optimized code with optimized code (PCHs won't be compatible) var SharedPCHCodeOptimization = SharedPCHEnvironment.OptimizeCode; var ModuleCodeOptimization = ModuleCompileEnvironment.Config.OptimizeCode; if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { if (SharedPCHCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds) { SharedPCHCodeOptimization = ModuleRules.CodeOptimization.Always; } if (ModuleCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds) { ModuleCodeOptimization = ModuleRules.CodeOptimization.Always; } } if (SharedPCHCodeOptimization != ModuleCodeOptimization) { Log.TraceVerbose("Module {0} cannot use existing Shared PCH '{1}' (from module '{2}') because optimization levels don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName); SharedPCHHeaderFile = null; return null; } return SharedPCHEnvironment; }
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName) { if (Arches.Count == 0) { throw new BuildException("At least one architecture (armv7, x86, etc) needs to be selected in the project settings to build"); } if (!bHasPrintedApiLevel) { Console.WriteLine("Compiling Native code with NDK API '{0}'", GetNdkApiLevel()); bHasPrintedApiLevel = true; } string BaseArguments = ""; if (CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create) { BaseArguments += " -Werror"; } // Directly added NDK files for NDK extensions ConditionallyAddNDKSourceFiles(SourceFiles, ModuleName); // Deal with dynamic modules removed by architecture GenerateEmptyLinkFunctionsForRemovedModules(SourceFiles, ModuleName, CompileEnvironment.Config.OutputDirectory); // Add preprocessor definitions to the argument list. foreach (string Definition in CompileEnvironment.Config.Definitions) { BaseArguments += string.Format(" -D \"{0}\"", Definition); } var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); var NDKRoot = Environment.GetEnvironmentVariable("NDKROOT").Replace("\\", "/"); string BasePCHName = ""; var PCHExtension = UEBuildPlatform.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) { if (ShouldSkipModule(ModuleName, Arch)) { continue; } foreach (string GPUArchitecture in GPUArchitectures) { // which toolchain to use string Arguments = GetCLArguments_Global(CompileEnvironment, Arch) + BaseArguments; switch (Arch) { case "-armv7": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break; case "-arm64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_ARM64=1"; break; case "-x86": Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_X86=1"; break; case "-x64": Arguments += " -DPLATFORM_64BITS=1 -DPLATFORM_ANDROID_X64=1"; break; default: Arguments += " -DPLATFORM_64BITS=0 -DPLATFORM_ANDROID_ARM=1"; break; } if (GPUArchitecture == "-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"; bool bDisableShadowWarning = false; // should we disable optimizations on this file? // @todo android - We wouldn't need this if we could disable optimizations per function (via pragma) bool bDisableOptimizations = false;// SourceFile.AbsolutePath.ToUpperInvariant().IndexOf("\\SLATE\\") != -1; if (bDisableOptimizations && CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug) { Log.TraceWarning("Disabling optimizations on {0}", SourceFile.AbsolutePath); } bDisableOptimizations = bDisableOptimizations || CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug; // Add C or C++ specific compiler arguments. if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { FileArguments += GetCompileArguments_PCH(bDisableOptimizations); } else if (bIsPlainCFile) { FileArguments += GetCompileArguments_C(bDisableOptimizations); // remove shadow variable warnings for NDK files if (SourceFile.AbsolutePath.Replace("\\", "/").StartsWith(NDKRoot)) { bDisableShadowWarning = true; } } else { FileArguments += GetCompileArguments_CPP(bDisableOptimizations); // only use PCH for .cpp files FileArguments += PCHArguments; } // Add the C++ source file and its included files to the prerequisite item list. AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems); if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create) { // Add the precompiled header file to the produced item list. FileItem PrecompiledHeaderFile = FileItem.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("\\", "/"); // Remove shadow warning for this file if requested if (bDisableShadowWarning) { int WarningIndex = AllArguments.IndexOf(" -Wshadow"); if (WarningIndex > 0) { AllArguments = AllArguments.Remove(WarningIndex, 9); } } // Create the response file 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; }
// UEBuildModule interface. public override List<FileItem> Compile(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment) { return new List<FileItem>(); }