本文主要介绍UE4如何通过UnrealBuildTool.exe去生成工程文件“visual studio 中就是生成UE4.sln”文件

关于UnrealBuildTool.exe是如何生成的请查看上一篇文章UnrealBuildTool.exe的生成

一、UnrealBuildTool.exe 生成工程文件的全流程

为什么点一下 “GenerateProjectFiles.bat” (UnrealEngine/GenerateProjectFiles.bat)就能生成工程文件?初入Unreal4的坑根据教程一步步操作然后 “UE4.sln” 就生成出来了!!!!太神奇了吧!!

我要搞懂他!!我不要不明不白!

搭配下面这张图一起食用可以有一个更清晰的思路!
在这里插入图片描述

二、下面将把主流程抓出来梳理一遍整个生成过程

1、主入口 UnrealBuildTool中的Main()——一切的开端

当我们运行 GenerateProjectFiles.bat 的时候,默认会传入 “-ProjectFiles” 该参数,如下如所示(下图为GenerateProjectFiles.bat中的截屏)
在这里插入图片描述

/// <summary>
/// UnrealBuildTool.cs
/// </summary>
class GlobalOptions
{
	...
	[CommandLine]
	[CommandLine("-Clean", Value="Clean")]
	[CommandLine("-ProjectFiles", Value="GenerateProjectFiles")]
	[CommandLine("-ProjectFileFormat=", Value="GenerateProjectFiles")]
	[CommandLine("-Makefile", Value="GenerateProjectFiles")]
	[CommandLine("-CMakefile", Value="GenerateProjectFiles")]
	[CommandLine("-QMakefile", Value="GenerateProjectFiles")]
	[CommandLine("-KDevelopfile", Value="GenerateProjectFiles")]
	[CommandLine("-CodeliteFiles", Value="GenerateProjectFiles")]
	[CommandLine("-XCodeProjectFiles", Value="GenerateProjectFiles")]
	[CommandLine("-EdditProjectFiles", Value="GenerateProjectFiles")]
	[CommandLine("-VSCode", Value="GenerateProjectFiles")]
	[CommandLine("-VSMac", Value="GenerateProjectFiles")]
	[CommandLine("-CLion", Value="GenerateProjectFiles")]
	[CommandLine("-Rider", Value="GenerateProjectFiles")]
	public string Mode = null;
	...
}


private static int Main(string[] ArgumentsArray)
{
	...
	// 传入的数据进行数据类型的转化
	CommandLineArguments Arguments = new CommandLineArguments(ArgumentsArray);

	// 将上述数据转化成我们需要的对应参数 由于传入的是 -ProjectFiles 因此得到的Mode就是GenerateProjectFiles
	GlobalOptions Options = new GlobalOptions(Arguments);
	...
	// 创建一个Mode
	Type ModeType = typeof(BuildMode);
	...
	// 找到 GenerateProjectFiles 对应的Mode 此处得到的是 GenerateProjectFilesMode
	if(!ModeNameToType.TryGetValue(Options.Mode, out ModeType))
	{
		Log.TraceError("No mode named '{0}'. Available modes are:\n  {1}", Options.Mode, String.Join("\n  ", ModeNameToType.Keys));
		return 1;
	}
	...
	// 创建对应的实例
	ToolMode Mode = (ToolMode)Activator.CreateInstance(ModeType);
	...
	// 运行上述得到的Mode 即 GenerateProjectFilesMode
	int Result = Mode.Execute(Arguments);
	...
}

1、可以看到在Main中,将传入的参数进行编译,并创建了一个对应的Mode,最后运行该Mode,即Mode.Execute(Arguments)

2、由于传入的参数是“-ProjectFiles”,因此Options.Mode的值是GenerateProjectFiles,对应的ModeType便是GenerateProjectFilesMode

2、ToolMode不同的运行模式——Mode.Execute的运行

/// <summary>
/// GenerateProjectFilesMode.cs
/// </summary>
class GenerateProjectFilesMode : ToolMode
{
	[CommandLine("-ProjectFileFormat")]
	[CommandLine("-2012unsupported", Value = nameof(ProjectFileFormat.VisualStudio2012))]
	[CommandLine("-2013unsupported", Value = nameof(ProjectFileFormat.VisualStudio2013))]
	[CommandLine("-2015", Value = nameof(ProjectFileFormat.VisualStudio2015))]
	[CommandLine("-2017", Value = nameof(ProjectFileFormat.VisualStudio2017))]
	[CommandLine("-2019", Value = nameof(ProjectFileFormat.VisualStudio2019))]
	[CommandLine("-Makefile", Value = nameof(ProjectFileFormat.Make))]
	[CommandLine("-CMakefile", Value = nameof(ProjectFileFormat.CMake))]
	[CommandLine("-QMakefile", Value = nameof(ProjectFileFormat.QMake))]
	[CommandLine("-KDevelopfile", Value = nameof(ProjectFileFormat.KDevelop))]
	[CommandLine("-CodeLiteFiles", Value = nameof(ProjectFileFormat.CodeLite))]
	[CommandLine("-XCodeProjectFiles", Value = nameof(ProjectFileFormat.XCode))]
	[CommandLine("-EddieProjectFiles", Value = nameof(ProjectFileFormat.Eddie))]
	[CommandLine("-VSCode", Value = nameof(ProjectFileFormat.VisualStudioCode))]
	[CommandLine("-VSMac", Value = nameof(ProjectFileFormat.VisualStudioMac))]
	[CommandLine("-CLion", Value = nameof(ProjectFileFormat.CLion))]
	[CommandLine("-Rider", Value = nameof(ProjectFileFormat.Rider))]
	HashSet<ProjectFileFormat> ProjectFileFormats = new HashSet<ProjectFileFormat>();

	public override int Execute(CommandLineArguments Arguments)
	{
		...
		// 我们是没有设置任何参数的 所以Count是0
		if (ProjectFileFormats.Count == 0)
		{
			...
			// 我们是没有设置任何参数的 所以Count是0
			if (ProjectFileFormats.Count == 0)
			{		
				// 获取默认的ProjectFileFormats 也就是WindowsBuildHostPlatform
				ProjectFileFormats.UnionWith(BuildHostPlatform.Current.GetDefaultProjectFileFormats());
			}
		}
		...
		switch (ProjectFileFormat)
		{
			...
			case ProjectFileFormat.VisualStudio:
				Generator = new VCProjectFileGenerator(ProjectFile, VCProjectFileFormat.Default, Arguments);
				break;
			...
		}
		Generators.Add(Generator);
		}
		...
		foreach(ProjectFileGenerator Generator in Generators)
		{
			if (!Generator.GenerateProjectFiles(PlatformProjectGenerators, Arguments.GetRawArray()))
			{
				return (int)CompilationResult.OtherCompilationError;
			}
		}
		...
	}
}

1、我们是没有设置任何参数的 所以ProjectFileFormats.Count是0,我们获取默认的平台

2、如下面代码所示,获取默认平台的时候,查看当前的系统,发现是Win64,因此最后我们得到的平台就是WindowsBuildHostPlatform

3、我们根据当前的平台,在这里就是WindowsBuildHostPlatform,得到对应的"Generator",此处我们得到的是"VCProjectFileGenerator",并执行对应的"GenerateProjectFiles"方法

/// <summary>
/// BuildHostPlatform.cs
/// </summary>
public abstract class BuildHostPlatform
{
	...
	private static UnrealTargetPlatform GetRuntimePlatform()
	{
		PlatformID Platform = Environment.OSVersion.Platform;
		switch (Platform)
		{
			case PlatformID.Win32NT:
				return UnrealTargetPlatform.Win64;
			...
		}
	}

	static public BuildHostPlatform Current
	{
		get
		{
			if (CurrentPlatform == null)
			{
				UnrealTargetPlatform RuntimePlatform = GetRuntimePlatform();
				if (RuntimePlatform == UnrealTargetPlatform.Win64)
				{
					CurrentPlatform = new WindowsBuildHostPlatform();
				}
				...
			}
			return CurrentPlatform;
		}
	}
}


class WindowsBuildHostPlatform : BuildHostPlatform
{
	...
	internal override IEnumerable<ProjectFileFormat> GetDefaultProjectFileFormats()
	{
		yield return ProjectFileFormat.VisualStudio;
	}
}

4、继承自“ToolMode”的模式有如下这些,在调用UnrealBuildTool.exe的时候会根据不同的参数选择不同的Mode并执行"Execute"方法
在这里插入图片描述

3、ProjectFileGenerator生成器——生成对应的解决方案

/// <summary>
/// ProjectFileGenerator.cs
/// </summary>
abstract class ProjectFileGenerator
{
	// 为所有已知引擎和游戏目标生成VisualStudio解决方案文件和VisualC++项目文件
	public virtual bool GenerateProjectFiles( PlatformProjectGeneratorCollection PlatformProjectGenerators, String[] Arguments )
	{
		...
		// 根据命令行选项配置项目生成器
		ConfigureProjectFileGeneration( Arguments, ref IncludeAllPlatforms);
		...
		
		WriteProjectFiles(PlatformProjectGenerators);
		...
	}
	protected virtual bool WriteProjectFiles(PlatformProjectGeneratorCollection PlatformProjectGenerators)
	{
		...
		WriteMasterProjectFile( UBTProject, PlatformProjectGenerators );
		...
		return true;
	}

	protected abstract bool WriteMasterProjectFile( ProjectFile UBTProject, PlatformProjectGeneratorCollection PlatformProjectGenerators );
}

1、前面最后说到,调用Generator的"GenerateProjectFiles"方法,如上面代码所示

2、生成解决方案的时候首先会 进行生成方案的配置,即"ConfigureProjectFileGeneration"

3、接着开始将解决方案写入文件中,即"WriteProjectFiles(PlatformProjectGenerators)",该方法在子类中是有重写的,看下面的子类

/// <summary>
/// VCProjectFileGenerator.cs
/// </summary>
class VCProjectFileGenerator : ProjectFileGenerator
{
	protected override bool WriteProjectFiles(PlatformProjectGeneratorCollection PlatformProjectGenerators)
	{
		if(!base.WriteProjectFiles(PlatformProjectGenerators))
		{
			return false;
		}
		// 写入自动引用文件
		if (AutomationProjectFiles.Any())
		{
			...
		}
		...
	}
	protected override bool WriteMasterProjectFile(ProjectFile UBTProject, PlatformProjectGeneratorCollection PlatformProjectGenerators)
	{
		...
		// 保存的文件名 UE4.sln
		string SolutionFileName = MasterProjectName + ".sln";
		...
		// 保存解决方案文件
		if (bSuccess)
		{
			string SolutionFilePath = FileReference.Combine(MasterProjectPath, SolutionFileName).FullName;
			bSuccess = WriteFileIfChanged(SolutionFilePath, VCSolutionFileContent.ToString());
		}
		// 保存默认情况下选择开发编辑器配置的解决方案配置文件
		if (bSuccess && Settings.bWriteSolutionOptionFile)
		{
		...
		}
	}
}

4、子类中"WriteProjectFiles"方法会先调用父类的"WriteProjectFiles",然后再写入自动引用文件并且保存

5、父类的"WriteProjectFiles"方法会调用"WriteMasterProjectFile",也就是我们此次的终点,生成"UE4.sln!!!"

7、继承自“ProjectFileGenerator”的生成器有如下这些,在对应Mode的Execute方法中会根据不同的平台选择不同的生成器,并进行解决方案的生成
在这里插入图片描述

三、这绝对是全网写的最最详细的UE4项目生成解释了!希望读者们能给我点个赞,多多增加阅读量!!

四、后面还会写第三篇,关于运行时调用UnrealBuildTool.exe的一些东西,多多支持!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐