[UE4] ビルドプロセスの流れ

対象Ver：UE4.25.0

#1. 概要
　UE4で作成したアプリケーションをビルドしたりパッケージするときは、以下のドキュメントからそのやり方を確認することができます。

[[公式ドキュメント] プロジェクトをリリースする](https://docs.unrealengine.com/ja/Engine/Deployment/Releasing/index.html)
[[公式ドキュメント] プロジェクトのパッケージ化](https://docs.unrealengine.com/ja/Engine/Basics/Projects/Packaging/index.html)
[[公式ドキュメント] プロジェクト ランチャーのリファレンス](https://docs.unrealengine.com/ja/Engine/Deployment/ProjectLauncher/index.html)

 本記事ではビルドやパッケージなどのフローに独自の処理を追加したり、各ステージでの問題点などを調査する事を目的としてブレークダウンしていきます、という建前ですが、正直なところは"Cook"や"Stage"といった単語に対する理解を深めるのと、後はソースコードのあたりをつけるためのメモのようなものです。

#2. ビルドオペレーション
　UE4でパッケージやデプロイを実行する方法は主に以下の3つの方法に分類されます。以下の3つの方法はそれぞれEditor, Project Launcher, .batファイルと実行する方法は異なりますが、最終的にはUATの中で処理されることになります。

![2020-06-02_15h57_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101019/4bb3c92b-ffdf-b824-0041-bb2bbbc82564.png)

　UATでビルドやクックといったオペレーションを実行する方法は以下の様に引数を渡すだけです。つまり、上記の3つの方法も結局は引数を収集して最終的に渡すだけのようなものになっています。

```:パッケージ実行のコマンド例
Build\BatchFiles\RunUAT.bat BuildCookRun -project=ElementalDemo -platform=Win64 -configuration=Development -build -cook -pak -stage
```
　例えば「EditorからPackage Projcet」を実行する際には、"Project Settings"からパッケージに必要なコマンドを生成してUATに渡すだけです。これは実行直後の`MainFrameActionCallbacks::PackageProject`で行われます。「Project LauncherからPackageを実行する」時も同様に`FLauncherWorker::CreateUATCommand`でUIで設定した内容を解析してコマンドを生成します。「.batファイルからPackageを実行」時はUATが読み込むコマンドを自分で追加するだけなので、予めどのようなコマンドがあるかを把握しておく必要があります。

#3. プロセス

##3.1. 全体
　ビルドオペレーションプロセスに関しては以下の通りです。プラットフォームによって若干動作や各ステートで実行する処理が異なることがありますが、おおむねはこのような流れとなります。

![2019-06-23_13h45_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/6264aa16-6af5-b375-fff6-bda5d5313bfe.png)

##3.2. コード上でのフロー
　ビルドオペレーション処理を行うプログラム部は以下の通りです。以下の箇所を追跡することで各フェーズの処理の詳細を確認することができます。UATで処理するコマンドをどう解釈するかは以下の実フェーズ内の処理を見ると確認することができます。

```cpp:

	// -------------------- BuildCookRun Command --------------------	
	ExecuteBuild();							// BuildCookRun.Automation.cs
	  DoBuildCookRun();						// BuildCookRun.Automation.cs
	    // -------------------- Build --------------------
	    Build();							// BuildProjectCommand.Automation.cs 
	      Build();							// UE4Build.cs
	        BuildWithUBT();					// UE4Build.cs
	          RunUBT();						// UBTUtils.cs
	            Run();						// ProcessUtils.cs
	    // -------------------- Cook --------------------
	    Cook();								// CookCommand.Automation.cs
	      CookCommandlet();					// CommandletUtils.cs
	        Main();							// CookCommandlet.cpp
	          CookByTheBook();				// CookCommandlet.cpp
	    // -------------------- Stage --------------------
	    CopyBuildToStagingDirectory();		// CopyBuildToStagingDirectory.Automation.cs
	      ApplyStagingManifest()			// CopyBuildToStagingDirectory.Automation.cs
	        CreatePakUsingStagingManifest()	// CopyBuildToStagingDirectory.Automation.cs
	        CreatePaksUsingChunkManifests()	// CopyBuildToStagingDirectory.Automation.cs
	          CreatePaks()					// CopyBuildToStagingDirectory.Automation.cs
	            RunUnrealPakInParallel()	// CopyBuildToStagingDirectory.Automation.cs
	              ExecuteUnrealPak()		// PakFileUtilities.cpp
	    // -------------------- Package --------------------
	    Package();							// PackageCommand.Automation.cs
	      Package();						// [PlatformName]Platform.Automation.cs
	    // -------------------- Archive --------------------
	    Archive();							// ArchiveCommand.Automation.cs
	      CreateDeploymentContext();		// CopyBuildToStagingDirectory.Automation.cs
	      ApplyArchiveManifest();			// ArchiveCommand.Automation.cs
	      ProcessArchivedProject();			// [PlatformName]Platform.Automation.cs
	    // -------------------- Deploy --------------------
	    Deploy();							// DeployCommand.Automation.cs
	      CreateDeploymentContext();		// CopyBuildToStagingDirectory.Automation.cs
	      PushDir();						// CopyBuildToStagingDirectory.Automation.cs
	      Run();							// ProcessUtils.cs
	    // -------------------- Run --------------------
	    Run();								// RunProjectCommand.Automation.cs
	      RunInternal();					// RunProjectCommand.Automation.cs

```

#4. プロセス詳細
 プロジェクトを作成してからパッケージを配布、またはアプリケーションを実機/端末上で起動するまでに幾つかの手順を踏む必要があります。この章ではその一連のプロセスにおける詳細な動作に関して説明します。

##4.1. Build
　プロジェクト、およびエンジンのソースコードを各プラットフォーム用にビルドするフェーズです。ビルドすることで各プラットフォームの実機上で動作するアプリケーションの実行ファイルを作成します。例えばWindowsプラットフォームのパッケージを行う場合には、まず最初にビルドを行い実行ファイル(.exe)を作成します。実行ファイルは構成によって以下のように生成先が異なります。

・C++
実行ファイルは`[Project]/Binaries/[Platform]`に作成される
・Blueprint
実行ファイルは`Engine/Binaries/[Platform]`に作成される　

<details><summary>**※Buildに失敗する時は**</summary><div>

**・EngineをDLした直後のビルドで失敗する場合**
　　→ Engineの完全なDLに失敗している可能性があるのでEngineを再DL
**・Engineのスイッチングが正しくない場合**
　　→ GenerateProjectFiles.bat, Setup.batを実行して構成を再構築する
**・古いファイル参照が残っている場合**
　　→ DDC/Intermediate/Saved を削除してGenerateProjectFiles.batを実行する

**・そもそもビルドターゲットに表示されない**
　　→ SDKが指定のEngineバージョンと一致していないので併せる
　　→ GenerateProjectFiles.batを実行して構成を再構築する
**・リンクエラーや存在しないファイルを参照している場合**
　　→ SDKバージョンを確認して再インストールする
**・複数のSDKが混在している場合**
　　→ 全てのSDKをアンインストール後に1つのSDKのみがある状態とする

</div></details>

##4.2. Cook
　ビルドが完了したら次にクックを行います。もちろんビルドをスキップしてクックを開始することも可能です。クックはプロジェクト、およびエンジンで使用するアセットを、各プラットフォームで利用可能な形式にコンバートするフェーズです。クックすることでアセットを各プラットフォームで利用できるようになります。クックしたアセットは`[Project]/Saved/Cooked`の配下に保存されています。

　[コンテンツのクック処理](https://docs.unrealengine.com/ja/Engine/Deployment/Cooking/index.html)にも記載されているようにプラットフォームによって利用可能なフォーマットがあるためクックしたファイルはプラットフォーム間で共有はできず、必ずプラットフォーム毎にクックする必要があります。クックする前の.uassetファイルはEditor上でも利用できるように様々なアセットの情報を持っていますが、クックをすると.uassetだけでなく.uexpや.ubulkといった複数のファイルで1つのアセットを構築するようになります。

　ネイティブ化を行う場合はBlueprintアセットを一旦ネイティブコードに変換する必要があるので、Cook→Buildの順番に逆転することがあります。

<details><summary>**※Cookに失敗する時は**</summary><div>

**・特定のアセットでエラーとなる**
　　→ アセットが破損している可能性があるので再保存やリダイレクタを修正を実行

</div></details>

##4.3. Stage
　ビルド時に作成した実行ファイルと、クック時に生成したアセットをStageディレクトリにコピーします。このコピーを行う目的は、実行ファイル群とクックしたアセット群を最終的に1つのファイル(アプリケーションパッケージ)とするためであり、一時的にコピーして一元管理するとパッケージを作成するにあたってファイル操作しやすいためです。

　Stageディレクトリは`[Project]/Saved/StagedBuilds`にあり、クック済みのアセット群を1つのファイルに纏める場合はStageのフェーズで.pakファイルを作成します。クックしたアセット群には大量のファイルが含まれますが.pakファイルとして1ファイルに纏めておく理由としては、ファイルアクセスが効率的に行えることや、アセットを圧縮して省サイズでパッケージに含めることができるためです。.pakに関連するChunkやPatchもここの処理を経由します。Project Launcherの場合はStageとPackageが必ずセットで実行されます。

##4.4. Package
　各プラットフォームで動作するアプリケーションパッケージ(Androidのケースであれば.apkファイル)を作成するフェーズです。

##4.5. Archive
　Stageフェーズで作成したアプリケーションパッケージ(パッケージを作成しない場合はStagedBuildsフォルダ内にあるアセット及び実行ファイル)を指定のフォルダにコピーするフェーズです。アプリケーションの実行に必要なファイル一式をコピーするため、特定のバージョンでのバックアップを作成する際などに利用します。プラットフォームによっては独自の処理を行ってアプリケーションの加工や、パッケージの起動に必要なインストーラを作成することもあります。

##4.6. Deploy
　作成したパッケージを実機に転送するフェーズです。パッケージを作成しない場合は、アセットを転送して実機上でアプリケーションを動作させるための準備を行います。

##4.7. Run
　転送したパッケージを実機で起動するフェーズです。