【UE5】Jenkinsを用いたビルド自動化

# 初めに

この記事では、Unreal Engine 5(UE5)で作成したプロジェクトファイルからWindowsやLinux、iOS、Androidなど様々なプラットフォーム向けにJenkinsを用いたビルド自動化について書きます。
実際のプロジェクトでは、定期的にビルドを出してその内容を確認しながら、実装を進めることが非常に重要です。しかし、手動でビルドを出したり、チームに共有することは、作業を中断する要因になったり、同じ操作を繰り返すことになるため、自動化が求められます。
ビルドを自動化することによって、精神的に余裕を持って開発、確認ができるようになるはずです!

# 概要
今回は、GitHubなどgit関連のサービスをチームで利用して、チーム開発をしていくことを想定しています。
新しい実装がMainブランチ(一部、ツールなどのUpdateができておらずMasterブランチと記載されているものもあります。適切な言葉遣いになっておらずすみません。)にプッシュあるいは、マージされたことをJenkinsが確認したら、各プラットフォーム向けにビルドを実行し、その実行結果をSlackに通知するというフローを作りたいと思います。

## 開発環境
- Windows  10/11
- Visual Studio IDE / 2022
- Unreal Engine / 5.1

:::note alert
現在、UE5はWindows 10及び、Visual Studio 2019を推奨していますが、ここでは、違うバージョンを使っています。
:::


## 事前準備

初めに、JenkinsをWindowsにインストールします。
インストール方法は、たとえば以下の記事などを参考にしてください。

https://www.jenkins.io/doc/book/installing/windows/

https://itsakura.com/tool-jenkins-install

## Jenkinsの設定

まずJenkinsをビルドを実行したいプロジェクトのRemoteのレポジトリーに接続します。
この情報をもとに、Remoteレポジトリーの更新を監視します。
![スクリーンショット 2022-12-11 0.47.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/70df1de3-bd3d-f1b1-4a76-c935cffb27b0.png)
ビルド トリガータブでは、Jenkinsがゲームの新しいバージョンをビルドするトリガーについて設定できます。SCMをポーリングで設定を行います。これは、jenkins設定された一定期間にポーリングを行い、変更があった場合にのみビルドすることを表しています。

今回は、5分ごとに新しい更新があるかどうかを確認して行きたいので、H/5を設定しました。
![image (141).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/a2c20fc5-e0c9-bda2-2d9d-64e4bf9a041c.png)

Build Stepでは、上記のポーリングで、Mainブランチに新しい更新があった際にどのようなことを実行するかを記述します。
![image (144).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/4268450c-f97c-1fce-9232-65a7361ee1a5.png)

今回は、以下に記載するような処理を実行しました。
## ①
```powershell
rd /s /q temp
```
まず、上記では一時的に生成されているファイルなどを削除し、該当のディレクトリーををクリーンするために行います。ビルドが途中で失敗したりキャンセルされたりする場合があるため、これを最初に行っておくが大切です。rdは、windowsではファイルの削除を表し、`/s`フラグは、サブディレクトリやサブファイルも削除することを指定します。`/q`フラグは、確認なしに削除を実行することを指定します。

## ②
```powershell
"C:\Program Files\Epic Games\UE_5.0\Engine\Binaries\DotNet\UnrealBuildTool\UnrealBuildTool.exe" -projectfiles -project="%WORKSPACE%\Sample.uproject" -game -rocket -progress
```

このプログラムは、UnrealBuildToolを使用して、指定されたUnreal Engine　プロジェクトからVisul Studioのプロジェクトファイル .slnを構築します。(.uproject ファイルを右クリックして [ Visual Studio プロジェクト ファイルの生成]を選択するのと同じです。)
前半部分の C:/Program Files/Epic Games/<version> は利用される環境によって異なります。UEがインストールされているディレクトリーになります。%WORKSPACE%変数は Jenkins プロジェクトのワークスペースの絶対パスを適切に変換します。このコマンドは、Unreal Build Tool を使用してVSのプロジェクトファイルを生成します。

**`-projectfiles`**
フラグは、プロジェクトファイルを構築するために使用されます。

**`-project`**
フラグは、構築されるプロジェクトのパスを指定します。

**`-game`**
フラグは、ゲームプロジェクトとして構築されることを示します。

**`-rocket`**
フラグは、ゲームプロジェクトをロケットモードで構築することを示します。ロケットモードとは、Unreal Engineのゲームプロジェクトを高速かつスケーラブルに構築するための特殊なモードのことのようですが、的確に説明がされているドキュメントが身つかなかったので、雰囲気で使っています。

**`-progress`**
フラグは、構築プロセスの進行状況を表示するよう指定します。

## ③

```powershell
"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/MSBuild/Current/Bin/MSBuild.exe" "%WORKSPACE%\Sample.sln" /t:build /p:Configuration="Development Editor";Platform=Win64;verbosity=diagnostic
```

このプログラムは、Microsoft Visual StudioのMSBuildツールを使用して、指定されたソリューションファイル（**`.sln`**）でプロジェクトをビルドするためのものです。

`C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools`部分は自身にVSのインストールを行っているパスに合わせてください。また今回は、VC2022を使っていますが、他のバージョンを使っているときは、他のバージョンの値を指定してください。また後半部分の

**`/t:build`**
フラグは、ビルドターゲットを指定するものです。

この場合、`build`ターゲットが指定されています。

**`/p:Configuration="Development Editor";Platform=Win64;verbosity=diagnostic`**
フラグは、ビルド時の詳細な設定を指定します。この場合、設定は`Development Editor`、プラットフォームは`Win64`、そしてlogの出力の詳細度は`diagnostic`に設定されています。

ここまで記載した①~③の処理はそれぞれのプラットフォームへのビルドを出すための処理ではありません。一方で、この処理を行わないとチーム開発では、ビルド生成時にエラーが発生しやすくなります。というのも、実開発においてPluginの修正やC++の実装などを頻繁に追加更新されるため、プロジェクトファイルが途中で開けなくなったり、BPの形が変わったりしてそのままビルドしようとすると、正しい結果を得られません。そのようなことを考慮して、ソリューションファイルの再生成とプロジェクトファイルのビルドを毎回行うことにしています。こうすることで、様々な修正を正しく反映したビルドを出すことが可能になります。

## ④
```powershell
"C:/Program Files/Epic Games/UE_5.0/Engine/Build/BatchFiles/RunUAT.bat" BuildCookRun -rocket -compile -compileeditor -installed -nop4 -project="%WORKSPACE%/Sample.uproject" -cook -stage -archive -archivedirectory="%WORKSPACE%/temp/Development/x64" -package -clientconfig=Shipping -ue4exe=UnrealEditor-Cmd.exe -clean -pak -prereqs -nodebuginfo -targetplatform=Win64 -build -utf8output
```

このコマンドでは、ビルドのためにUAT(Unreal Automation Tool)使用して、指定されたUnreal Engineプロジェクトをビルド、コンパイル、およびパッケージングするためのものです。

:::note info　
これ以外にもビルドを実行する方法はいくつかあり、以下のスライドなどで紹介されています。
[「Press Button, Drink Coffee」 UE4における ビルドパイプラインとメンテナンスの全体像【CEDEC 2019】](https://www.docswell.com/s/EpicGamesJapan/KLGQ75-UE4_CEDEC19_BuildPipeline#p29)
:::

またAutomation Toolを使ったビルドについては以下の記事などが参考になります。

https://zenn.dev/kihoku/articles/ad7be2c491cd34

、Unreal Automation Tool（UAT）を使用して、指定されたUnreal Engineプロジェクトをビルド、コンパイル、およびパッケージングするためのものです。

`BuildCookRun`スクリプトは、ゲームプロジェクトをビルド、コンパイル、実行するために使用されます。

**`-rocket`**
フラグは、プロジェクトをロケットモードで構築することを指定します。

**`-compile`**
フラグは、ゲームプロジェクトをコンパイルすることを指定します。

**`-compileeditor`**
フラグは、ゲームプロジェクトをエディターでコンパイルすることを指定します。

**`-installed`**
フラグは、UATがインストールされていることを示します。

**`-nop4`**
フラグは、Perforceとの連携を無効にすることを指定します。

**`-project`**
フラグは、ビルドされるプロジェクトのパスを指定します。

**`-cook`**
フラグは、ゲームプロジェクトをクックすることを指定します。

**`-stage`**
フラグは、ゲームプロジェクトをステージングすることを指定します。

**`-archive`**
フラグは、ステージされたゲームプロジェクトをアーカイブすることを指定します。

**`-archivedirectory`**
フラグは、アーカイブされたゲームプロジェクトを保存するディレクトリを指定します。

**`-package`**
フラグは、ゲームプロジェクトをパッケージングすることを指定します。

**`-clientconfig`**
フラグは、パッケージングするゲームプロジェクトの設定を指定します。この場合は、`Developmen`設定が指定されています。

**`-ue4exe`**
フラグは、UATが使用するUnreal Engineエディターのパスを指定します。

**`-clean`**
フラグは、ビルド後に一時ファイルをクリーンアップすることを指定します。より高速なビルドが必要な場合は、 -cleanパラメーターを削除できますが、これは安全ではなく、残り物がないことを確認するために定期的にクリーンビルドを実行する必要がある場合があります。

**`-pak`**
フラグは、ゲームプロジェクトをPAKファイルとして構築

**`-prereqs`**
フラグは、必要なプリリクエストをダウンロードすることを指定します。

**`-distribution`**
フラグは、ゲームプロジェクトを配布用に構築することを指定します。Developmentビルドの場合はつけないと思います。

**`-nodebuginfo`**
フラグは、デバッグ情報を含まないように構築することを指定します。

**`-targetplatform`**
フラグは、ビルドされるゲームプロジェクトのプラットフォームを指定します。この場合は`Win64`プラットフォームが指定されています。

**`-utf8output`**
フラグは、UATが出力するテキストをUTF-8形式で出力することを指定します。


①~③は、プロジェクトをきれいな状態にする処理なので、実際のビルドはこの処理になります。
また、今回載せたのは、Win64用のものなので、たとえば、Androidの場合は、`-targetplatform=Android`とすれば可能です。iOSの場合は、`-targetplatform=IOS`とします。

ここまでできたら、チームに配布するために、共有フォルダーなどにuploadなどします。僕の場合は、Firebaseを用いることが多いので、FirebaseのCLIを用いて、できたAPK(最近だとABB)とIPAをFireabase App Distributionにuploadします。ここまで、Jenkinsで実行することで、ビルドから、実機へのアプリインストールの手前までを全て自動化することができてハッピーになれます。

## Slack連携

最後にビルドが終わったことをSlackに通知することでチームに対してビルド結果を共有することができます。
Jenkinsには、SlackのPluginがあるので今回はそれを利用しました。![image (146).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/46708967-33b5-0895-67ff-928fcb8a5734.png)

こちらを設定して、Build Stepの最後に、Slackへの通知を設定ます。

![image (145).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/8f75429c-0254-be22-88eb-184ee52af706.png)

そうすると、バージョン管理ソフトに更新が入るタイミングでトリーがされ、ビルドを始めてくれます。
![スクリーンショット 2022-12-11 10.46.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/ec5ae586-a7c0-c6d3-7340-7e8216df7726.png)

またビルドを実行して何もなければ、成功を返してくれます。
一方で、実装に問題があれば、以下のように失敗した旨がSalckに通知されます! 便利。

![スクリーンショット 2022-12-11 10.46.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206272/f41d3dec-1b1e-7f6e-3fae-0d5b62b22eac.png)


# 終わりに
実装に集中したい時に、ビルドを個々のPCで行うのは、心理的なハードルや作業に集中できなかったりするので、ビルド用のPCを用意して、そこになるべく集中させることで、継続的にビルドの作成、テストができるようになります。プロジェクトの佳境のタイミングで、重い腰を上げてビルドをすると、実機で思いもよらないエラーや致命的な問題が起きてしまい対処方法を考える時間がなかったりします。そのため、なるべく早めにこまめにビルドをするために、今回紹介したような方法は小規模のチームでも大切だと思いました!

# 宣伝
最後に会社の紹介をさせてください。Alcheでは、Metaverse/VRの領域で体験やコンテンツを作っています。これまでの製作などは、以下のHPを見ていただけたら嬉しいです!!

https://alche.studio/

UEのプログラマーの方、ネットワークエンジニア、バックエンドエンジニア、インフラエンジニアの方をとっても募集しております。少しでも興味があれば以下の私のTwitter(@r_etx)もしくは、弊社のHPのお問い合わせよりご連絡いただけたら幸いです!!


# Reference

https://patricevignola.com/post/automation-jenkins-unreal

その他エンジンのコード
Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectParams.cs
Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherWorker.cpp
などが参考になります。