// Anonymous function that writes project configuration data private void WriteConfiguration(string ProjectName, UnrealTargetConfiguration Configuration, UnrealTargetPlatform Platform, string TargetFilePath, TargetRules TargetRulesObject, StringBuilder VCProjectFileContent, StringBuilder VCUserFileContent) { UEPlatformProjectGenerator ProjGenerator = UEPlatformProjectGenerator.GetPlatformProjectGenerator(Platform, true); if (((ProjGenerator == null) && (Platform != UnrealTargetPlatform.Unknown))) { return; } string UProjectPath = ""; bool bIsProjectTarget = UnrealBuildTool.HasUProjectFile() && Utils.IsFileUnderDirectory(TargetFilePath, UnrealBuildTool.GetUProjectPath()); // @todo Rocket: HACK: Only use long project names on the UBT command-line for out-of-root projects for now. We need to revisit all uses of HasUProjectFile and short names in general to fix this. if (bIsProjectTarget && !UnrealBuildTool.RunningRocket() && Utils.IsFileUnderDirectory(UnrealBuildTool.GetUProjectFile(), ProjectFileGenerator.RootRelativePath)) { bIsProjectTarget = false; } if (bIsProjectTarget) { UProjectPath = "\"$(SolutionDir)$(SolutionName).uproject\""; } string ProjectConfigName = StubProjectConfigurationName; string ProjectPlatformName = StubProjectPlatformName; MakeProjectPlatformAndConfigurationNames(Platform, Configuration, TargetRulesObject.ConfigurationName, out ProjectPlatformName, out ProjectConfigName); var ConfigAndPlatformName = ProjectConfigName + "|" + ProjectPlatformName; string ConditionString = "Condition=\"'$(Configuration)|$(Platform)'=='" + ConfigAndPlatformName + "'\""; { VCProjectFileContent.Append( " <ImportGroup " + ConditionString + " Label=\"PropertySheets\">" + ProjectFileGenerator.NewLine + " <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />" + ProjectFileGenerator.NewLine + " </ImportGroup>" + ProjectFileGenerator.NewLine); VCProjectFileContent.Append( " <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator.NewLine); if (IsStubProject) { string ProjectRelativeUnusedDirectory = NormalizeProjectPath(Path.Combine(ProjectFileGenerator.EngineRelativePath, BuildConfiguration.BaseIntermediateFolder, "Unused")); VCProjectFileContent.Append( " <OutDir></OutDir>" + ProjectFileGenerator.NewLine + " <IntDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator.NewLine + " <NMakeBuildCommandLine/>" + ProjectFileGenerator.NewLine + " <NMakeReBuildCommandLine/>" + ProjectFileGenerator.NewLine + " <NMakeCleanCommandLine/>" + ProjectFileGenerator.NewLine + " <NMakeOutput/>" + ProjectFileGenerator.NewLine); } else { string TargetName = Utils.GetFilenameWithoutAnyExtensions(TargetFilePath); var UBTPlatformName = IsStubProject ? StubProjectPlatformName : Platform.ToString(); var UBTConfigurationName = IsStubProject ? StubProjectConfigurationName : Configuration.ToString(); // Setup output path UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform); // Figure out if this is a monolithic build bool bShouldCompileMonolithic = BuildPlatform.ShouldCompileMonolithicBinary(Platform); bShouldCompileMonolithic |= TargetRulesObject.ShouldCompileMonolithic(Platform, Configuration); // Get the output directory string RootDirectory = Path.GetFullPath(ProjectFileGenerator.EngineRelativePath); if ((TargetRules.IsAGame(TargetRulesObject.Type) || TargetRulesObject.Type == TargetRules.TargetType.Server) && bShouldCompileMonolithic && !TargetRulesObject.bOutputToEngineBinaries) { if (UnrealBuildTool.HasUProjectFile() && Utils.IsFileUnderDirectory(TargetFilePath, UnrealBuildTool.GetUProjectPath())) { RootDirectory = Path.GetFullPath(UnrealBuildTool.GetUProjectPath()); } else { string UnrealProjectPath = UProjectInfo.GetProjectFilePath(ProjectName); if (!String.IsNullOrEmpty(UnrealProjectPath)) { RootDirectory = Path.GetDirectoryName(Path.GetFullPath(UnrealProjectPath)); } } } // Get the output directory string OutputDirectory = Path.Combine(RootDirectory, "Binaries", UBTPlatformName); // Get the executable name (minus any platform or config suffixes) string BaseExeName = TargetName; if (!bShouldCompileMonolithic && TargetRulesObject.Type != TargetRules.TargetType.Program) { // Figure out what the compiled binary will be called so that we can point the IDE to the correct file string TargetConfigurationName = TargetRulesObject.ConfigurationName; if (TargetConfigurationName != TargetRules.TargetType.Game.ToString() && TargetConfigurationName != TargetRules.TargetType.RocketGame.ToString() && TargetConfigurationName != TargetRules.TargetType.Program.ToString()) { BaseExeName = "UE4" + TargetConfigurationName; } } // Make the output file path string NMakePath = Path.Combine(OutputDirectory, BaseExeName); if (Configuration != UnrealTargetConfiguration.Development && (Configuration != UnrealTargetConfiguration.DebugGame || bShouldCompileMonolithic)) { NMakePath += "-" + UBTPlatformName + "-" + UBTConfigurationName; } NMakePath += BuildPlatform.GetActiveArchitecture(); NMakePath += BuildPlatform.GetBinaryExtension(UEBuildBinaryType.Executable); NMakePath = BuildPlatform.ModifyNMakeOutput(NMakePath); string PathStrings = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioPathsEntries(Platform, Configuration, TargetRulesObject.Type, TargetFilePath, ProjectFilePath, NMakePath) : ""; if (string.IsNullOrEmpty(PathStrings) || (PathStrings.Contains("<IntDir>") == false)) { string ProjectRelativeUnusedDirectory = "$(ProjectDir)..\\Build\\Unused"; VCProjectFileContent.Append( PathStrings + " <OutDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</OutDir>" + ProjectFileGenerator.NewLine + " <IntDir>" + ProjectRelativeUnusedDirectory + Path.DirectorySeparatorChar + "</IntDir>" + ProjectFileGenerator.NewLine); } else { VCProjectFileContent.Append(PathStrings); } // Force specification of TargetName on XboxOne so that the manifest can identify the correct executable to the debugger. if (Platform == UnrealTargetPlatform.XboxOne) { VCProjectFileContent.Append(" <TargetName>$(ProjectName)"); if (Configuration != UnrealTargetConfiguration.Development) { VCProjectFileContent.Append(UBTConfigurationName); } VCProjectFileContent.Append("</TargetName>" + ProjectFileGenerator.NewLine); } // This is the standard UE4 based project NMake build line: // ..\..\Build\BatchFiles\Build.bat <TARGETNAME> <PLATFORM> <CONFIGURATION> // ie ..\..\Build\BatchFiles\Build.bat BlankProgram Win64 Debug string ProjectPlatformConfiguration = " " + TargetName + " " + UBTPlatformName + " " + UBTConfigurationName; string BatchFilesDirectoryName = Path.Combine(ProjectFileGenerator.EngineRelativePath, "Build", "BatchFiles"); // NMake Build command line VCProjectFileContent.Append(" <NMakeBuildCommandLine>"); VCProjectFileContent.Append(EscapePath(NormalizeProjectPath(Path.Combine(BatchFilesDirectoryName, "Build.bat"))) + ProjectPlatformConfiguration.ToString()); if (bIsProjectTarget) { VCProjectFileContent.Append(" " + UProjectPath + (UnrealBuildTool.RunningRocket() ? " -rocket" : "")); } VCProjectFileContent.Append("</NMakeBuildCommandLine>" + ProjectFileGenerator.NewLine); // NMake ReBuild command line VCProjectFileContent.Append(" <NMakeReBuildCommandLine>"); VCProjectFileContent.Append(EscapePath(NormalizeProjectPath(Path.Combine(BatchFilesDirectoryName, "Rebuild.bat"))) + ProjectPlatformConfiguration.ToString()); if (bIsProjectTarget) { VCProjectFileContent.Append(" " + UProjectPath + (UnrealBuildTool.RunningRocket() ? " -rocket" : "")); } VCProjectFileContent.Append("</NMakeReBuildCommandLine>" + ProjectFileGenerator.NewLine); // NMake Clean command line VCProjectFileContent.Append(" <NMakeCleanCommandLine>"); VCProjectFileContent.Append(EscapePath(NormalizeProjectPath(Path.Combine(BatchFilesDirectoryName, "Clean.bat"))) + ProjectPlatformConfiguration.ToString()); if (bIsProjectTarget) { VCProjectFileContent.Append(" " + UProjectPath + (UnrealBuildTool.RunningRocket() ? " -rocket" : "")); } VCProjectFileContent.Append("</NMakeCleanCommandLine>" + ProjectFileGenerator.NewLine); VCProjectFileContent.Append(" <NMakeOutput>"); VCProjectFileContent.Append(NormalizeProjectPath(NMakePath)); VCProjectFileContent.Append("</NMakeOutput>" + ProjectFileGenerator.NewLine); } VCProjectFileContent.Append(" </PropertyGroup>" + ProjectFileGenerator.NewLine); if (VCUserFileContent != null) { if (UnrealBuildTool.HasUProjectFile()) { if ((Platform == UnrealTargetPlatform.Win32) || (Platform == UnrealTargetPlatform.Win64)) { VCUserFileContent.Append( " <PropertyGroup " + ConditionString + ">" + ProjectFileGenerator.NewLine); if ((TargetRulesObject.Type != TargetRules.TargetType.RocketGame) && (TargetRulesObject.Type != TargetRules.TargetType.Game)) { string DebugOptions = UProjectPath; if(DebugOptions.Length == 0 && TargetRulesObject.Type == TargetRules.TargetType.Editor && ProjectName != "UE4") { DebugOptions += ProjectName; } if (Configuration == UnrealTargetConfiguration.Debug || Configuration == UnrealTargetConfiguration.DebugGame) { DebugOptions += " -debug"; } else if (Configuration == UnrealTargetConfiguration.Shipping) { DebugOptions += " -shipping"; } VCUserFileContent.Append( " <LocalDebuggerCommandArguments>" + DebugOptions + "</LocalDebuggerCommandArguments>" + ProjectFileGenerator.NewLine ); } VCUserFileContent.Append( " <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>" + ProjectFileGenerator.NewLine ); VCUserFileContent.Append( " </PropertyGroup>" + ProjectFileGenerator.NewLine ); } } string PlatformUserFileStrings = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioUserFileStrings(Platform, Configuration, ConditionString, TargetRulesObject, TargetFilePath, ProjectFilePath) : ""; VCUserFileContent.Append(PlatformUserFileStrings); } } string LayoutDirString = (ProjGenerator != null) ? ProjGenerator.GetVisualStudioLayoutDirSection(Platform, Configuration, ConditionString, TargetRulesObject.Type, TargetFilePath, ProjectFilePath) : ""; VCProjectFileContent.Append(LayoutDirString); }
/// <summary> /// /// </summary> /// <param name="InGameName"></param> /// <param name="InRulesObject"></param> /// <param name="InPlatform"></param> /// <param name="InConfiguration"></param> /// <returns></returns> public static string GetBinaryBaseName(string InGameName, TargetRules InRulesObject, UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, string InNameAppend) { //@todo. Allow failure to get build platform here? bool bPlatformRequiresMonolithic = false; var BuildPlatform = UEBuildPlatform.GetBuildPlatform(InPlatform, true); if (BuildPlatform != null) { bPlatformRequiresMonolithic = BuildPlatform.ShouldCompileMonolithicBinary(InPlatform); } if (InRulesObject.ShouldCompileMonolithic(InPlatform, InConfiguration) || bPlatformRequiresMonolithic) { return InGameName; } else { return "UE4" + InNameAppend; } }
/// <summary> /// Constructor. /// </summary> /// <param name="InDesc">Target descriptor</param> /// <param name="InRules">The target rules, as created by RulesCompiler.</param> /// <param name="InPossibleAppName">The AppName for shared binaries of this target type, if used (null if there is none).</param> /// <param name="InTargetCsFilename">The name of the target </param> public UEBuildTarget(TargetDescriptor InDesc, TargetRules InRules, string InPossibleAppName, string InTargetCsFilename) { AppName = InDesc.TargetName; TargetName = InDesc.TargetName; Platform = InDesc.Platform; Configuration = InDesc.Configuration; Rules = InRules; TargetType = Rules.Type; bEditorRecompile = InDesc.bIsEditorRecompile; bPrecompile = InDesc.bPrecompile; bUsePrecompiled = InDesc.bUsePrecompiled; ForeignPlugins = InDesc.ForeignPlugins; ForceReceiptFileName = InDesc.ForceReceiptFileName; Debug.Assert(InTargetCsFilename == null || InTargetCsFilename.EndsWith(".Target.cs", StringComparison.InvariantCultureIgnoreCase)); TargetCsFilenameField = InTargetCsFilename; { bCompileMonolithic = Rules.ShouldCompileMonolithic(InDesc.Platform, InDesc.Configuration); // Platforms may *require* monolithic compilation... bCompileMonolithic |= UEBuildPlatform.PlatformRequiresMonolithicBuilds(InDesc.Platform, InDesc.Configuration); // Force monolithic or modular mode if we were asked to if( UnrealBuildTool.CommandLineContains("-Monolithic") || UnrealBuildTool.CommandLineContains("MONOLITHIC_BUILD=1") ) { bCompileMonolithic = true; } else if( UnrealBuildTool.CommandLineContains( "-Modular" ) ) { bCompileMonolithic = false; } } TargetInfo = new TargetInfo(Platform, Configuration, Rules.Type, bCompileMonolithic); if(InPossibleAppName != null && InRules.ShouldUseSharedBuildEnvironment(TargetInfo)) { AppName = InPossibleAppName; bUseSharedBuildEnvironment = true; } // Figure out what the project directory is. If we have a uproject file, use that. Otherwise use the engine directory. if (UnrealBuildTool.HasUProjectFile()) { ProjectDirectory = Path.GetFullPath(UnrealBuildTool.GetUProjectPath()); } else { ProjectDirectory = Path.GetFullPath(BuildConfiguration.RelativeEnginePath); } // Build the project intermediate directory ProjectIntermediateDirectory = Path.GetFullPath(Path.Combine(ProjectDirectory, BuildConfiguration.PlatformIntermediateFolder, GetTargetName(), Configuration.ToString())); // Build the engine intermediate directory. If we're building agnostic engine binaries, we can use the engine intermediates folder. Otherwise we need to use the project intermediates directory. if (!bUseSharedBuildEnvironment) { EngineIntermediateDirectory = ProjectIntermediateDirectory; } else if(Configuration == UnrealTargetConfiguration.DebugGame) { EngineIntermediateDirectory = Path.GetFullPath(Path.Combine(BuildConfiguration.RelativeEnginePath, BuildConfiguration.PlatformIntermediateFolder, AppName, UnrealTargetConfiguration.Development.ToString())); } else { EngineIntermediateDirectory = Path.GetFullPath(Path.Combine(BuildConfiguration.RelativeEnginePath, BuildConfiguration.PlatformIntermediateFolder, AppName, Configuration.ToString())); } RemoteRoot = InDesc.RemoteRoot; OnlyModules = InDesc.OnlyModules; // Construct the output paths for this target's executable string OutputDirectory; if((bCompileMonolithic || TargetType == TargetRules.TargetType.Program) && !Rules.bOutputToEngineBinaries) { OutputDirectory = ProjectDirectory; } else { OutputDirectory = Path.GetFullPath(BuildConfiguration.RelativeEnginePath); } OutputPaths = MakeExecutablePaths(OutputDirectory, bCompileMonolithic? TargetName : AppName, Platform, Configuration, Rules.UndecoratedConfiguration, bCompileMonolithic && UnrealBuildTool.HasUProjectFile(), Rules.ExeBinariesSubFolder); // handle some special case defines (so build system can pass -DEFINE as normal instead of needing // to know about special parameters) foreach (string Define in InDesc.AdditionalDefinitions) { switch (Define) { case "WITH_EDITOR=0": UEBuildConfiguration.bBuildEditor = false; break; case "WITH_EDITORONLY_DATA=0": UEBuildConfiguration.bBuildWithEditorOnlyData = false; break; // Memory profiler doesn't work if frame pointers are omitted case "USE_MALLOC_PROFILER=1": BuildConfiguration.bOmitFramePointers = false; break; case "WITH_LEAN_AND_MEAN_UE=1": UEBuildConfiguration.bCompileLeanAndMeanUE = true; break; } } // Add the definitions specified on the command-line. GlobalCompileEnvironment.Config.Definitions.AddRange(InDesc.AdditionalDefinitions); }
/** * @param InAppName - The name of the application being built, which is used to scope all intermediate and output file names. * @param InGameName - The name of the game being build - can be empty * @param InPlatform - The platform the target is being built for. * @param InConfiguration - The configuration the target is being built for. * @param InAdditionalDefinitions - Additional definitions provided on the UBT command-line for the target. * @param InRemoteRoot - The remote path that the build output is synced to. */ public UEBuildTarget( string InAppName, string InGameName, UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, TargetRules InRulesObject, List<string> InAdditionalDefinitions, string InRemoteRoot, List<OnlyModule> InOnlyModules, bool bInEditorRecompile) { AppName = InAppName; GameName = InGameName; Platform = InPlatform; Configuration = InConfiguration; Rules = InRulesObject; bEditorRecompile = bInEditorRecompile; { bCompileMonolithic = (Rules != null) ? Rules.ShouldCompileMonolithic(InPlatform, InConfiguration) : false; // Platforms may *require* monolithic compilation... bCompileMonolithic |= UEBuildPlatform.PlatformRequiresMonolithicBuilds(InPlatform, InConfiguration); // Force monolithic or modular mode if we were asked to if( UnrealBuildTool.CommandLineContains("-Monolithic") || UnrealBuildTool.CommandLineContains("MONOLITHIC_BUILD=1") ) { bCompileMonolithic = true; } else if( UnrealBuildTool.CommandLineContains( "-Modular" ) ) { bCompileMonolithic = false; } } // Figure out what the project directory is. If we have a uproject file, use that. Otherwise use the engine directory. if (UnrealBuildTool.HasUProjectFile()) { ProjectDirectory = Path.GetFullPath(UnrealBuildTool.GetUProjectPath()); } else { ProjectDirectory = Path.GetFullPath(BuildConfiguration.RelativeEnginePath); } // Build the project intermediate directory ProjectIntermediateDirectory = Path.GetFullPath(Path.Combine(ProjectDirectory, BuildConfiguration.PlatformIntermediateFolder, GetTargetName(), Configuration.ToString())); // Build the engine intermediate directory. If we're building agnostic engine binaries, we can use the engine intermediates folder. Otherwise we need to use the project intermediates directory. if (ShouldCompileMonolithic()) { EngineIntermediateDirectory = ProjectIntermediateDirectory; } else if(Configuration == UnrealTargetConfiguration.DebugGame) { EngineIntermediateDirectory = Path.GetFullPath(Path.Combine(BuildConfiguration.RelativeEnginePath, BuildConfiguration.PlatformIntermediateFolder, AppName, UnrealTargetConfiguration.Development.ToString())); } else { EngineIntermediateDirectory = Path.GetFullPath(Path.Combine(BuildConfiguration.RelativeEnginePath, BuildConfiguration.PlatformIntermediateFolder, AppName, Configuration.ToString())); } RemoteRoot = InRemoteRoot; OnlyModules = InOnlyModules; TargetTypeOrNull = (Rules != null) ? Rules.Type : (TargetRules.TargetType?)null; // Construct the output path based on configuration, platform, game if not specified. OutputPaths = MakeBinaryPaths("", AppName, UEBuildBinaryType.Executable, TargetType, null, InAppName, Configuration == UnrealTargetConfiguration.Shipping ? Rules.ForceNameAsForDevelopment() : false, Rules.ExeBinariesSubFolder); for (int Index = 0; Index < OutputPaths.Length; Index++) { OutputPaths[Index] = Path.GetFullPath(OutputPaths[Index]); } if (bCompileMonolithic && TargetRules.IsGameType(InRulesObject.Type)) { // For Rocket, UE4Game.exe and UE4Editor.exe still go into Engine/Binaries/<PLATFORM> if (!InRulesObject.bOutputToEngineBinaries) { // We are compiling a monolithic game... // We want the output to go into the <GAME>\Binaries folder if (UnrealBuildTool.HasUProjectFile() == false) { for (int Index = 0; Index < OutputPaths.Length; Index++) { OutputPaths[Index] = OutputPaths[Index].Replace(Path.Combine("Engine", "Binaries"), Path.Combine(InGameName, "Binaries")); } } else { string EnginePath = Path.GetFullPath(Path.Combine(ProjectFileGenerator.EngineRelativePath, "Binaries")); string UProjectPath = UnrealBuildTool.GetUProjectPath(); if (Path.IsPathRooted(UProjectPath) == false) { string FilePath = UProjectInfo.GetProjectForTarget(InGameName); string FullPath = Path.GetFullPath(FilePath); UProjectPath = Path.GetDirectoryName(FullPath); } string ProjectPath = Path.GetFullPath(Path.Combine(UProjectPath, "Binaries")); for (int Index = 0; Index < OutputPaths.Length; Index++) { OutputPaths[Index] = OutputPaths[Index].Replace(EnginePath, ProjectPath); } } } } // handle some special case defines (so build system can pass -DEFINE as normal instead of needing // to know about special parameters) foreach (string Define in InAdditionalDefinitions) { switch (Define) { case "WITH_EDITOR=0": UEBuildConfiguration.bBuildEditor = false; break; case "WITH_EDITORONLY_DATA=0": UEBuildConfiguration.bBuildWithEditorOnlyData = false; break; // Memory profiler doesn't work if frame pointers are omitted case "USE_MALLOC_PROFILER=1": BuildConfiguration.bOmitFramePointers = false; break; case "WITH_LEAN_AND_MEAN_UE=1": UEBuildConfiguration.bCompileLeanAndMeanUE = true; break; } } // Add the definitions specified on the command-line. GlobalCompileEnvironment.Config.Definitions.AddRange(InAdditionalDefinitions); }