tech.guitarrapc.cóm

Technical updates

Azure DevOpsの Microsoft-hosted Agent で HoloLens ビルドを行う(MRTK/MRTKv2)

前回、Azure DevOpsでHoloLensのビルド環境を行うこと、Microsoft-hosted Agentが今ならいいということを書きました。

tech.guitarrapc.com

今回は、MRTKとMRTKv2をMicrosoft-hosted Agentで現実的にビルドすることを考えてみましょう。 内容としては、次の記事が近いです。

withmr.nextscape.net

この記事では、MRTKv1とMRTKv2それぞれについてリポジトリとAzure Devops PipelineのYAMLを示しつつ、現実にビルドしていくことに必要なことをカバーします。

Unity のビルドエラーがわからない

Windows上でUnityのバッチビルドをしたときに困るのが、Unityビルドの経過、ログが標準出力に出ないことです。*1

結果Unity内部でどのようなエラーが起こってもエラーの詳細がわからないので、記事にあるUnityBuildTask@2を使う方法は現実的じゃありません。*2

コンパイルエラー時に、どこでコンパイルエラー出たかわからないのは絶望です。

そのため、Unity Tools for Azure DevOpsでUnityビルドを行うのは厳しいものがあります。

- task: UnityBuildTask@2
  displayName: 'Unity Build WindowsStoreApps'
  name: 'unityBuild'
  inputs:
    buildTarget: 'WindowsStoreApps'
    unityEditorsPathMode: 'unityHub'
    unityProjectPath: '$(unityProjectPath)'
    commandLineArgumentsMode: 'default'

Unity Tools for Azure DevOps

代わりに「Unityビルド呼び出しつつlogファイルに吐いたログを読み込んで標準出力に吐く」ラッパーアプリケーションを用意する方法をよく採用されています。

https://chiepomme.gitbook.io/chienote/ci-cd/unity-build-log-to-stdoutchiepomme.gitbook.io

お手伝い先で必要にな使っていただいているのがUnityBuildRunnerです。*3

github.com

dotnet global toolとして公開してあるので、dotnet tool install -g UnityBuildRunnerでWindows/Mac問わずサクッとインストールできます。

使い方は単純です。Unityのバッチビルドは次のフォーマットです。

Unity.exe [args]

この引数をUnityBuildRunnerにそのまま渡せばokです。 加えてタイムアウトにも対応してあります。

UnityBuildRunner [-UnityPath|-unityPath|-u] [-timeout|-t 00:60:00] [-version] [-help] [args]

たとえば、MRTKv2でビルドするならこのように書けます。

UnityBuildRunner -UnityPath "C:\Program Files\Unity\Hub\Editor\2018.3.13f1\Editor\Unity.exe" -quit -batchmode -projectPath パス -buildTarget WSAPlayer -logfile Editor.log -executeMethod Microsoft.MixedReality.Toolkit.Build.Editor.UnityPlayerBuildTools.StartCommandLineBuild

Unityパスは環境変数から読むこともできるので次のようにも書けます。

set unityPath=C:\Program Files\Unity\Hub\Editor\2018.3.13f1\Editor\Unity.exe
UnityBuildRunner -quit -batchmode -projectPath パス -buildTarget WSAPlayer -logfile Editor.log -executeMethod Microsoft.MixedReality.Toolkit.Build.Editor.UnityPlayerBuildTools.StartCommandLineBuild

https://github.com/guitarrapc/UnityBuildRunner を使ったWindowsでのUnityビルド

MRTKv1 のビルドを行う

MRTKのビルドは、HoloToolkit.Unity.BuildDeployTools.BuildSLNメソッドを使います。*4

MRTKv2を使ったビルドとYAML定義を含んだリポジトリです。

github.com

ビルドのYAML定義を見てみましょう。

gist.github.com

途中のコメントを外すとsln一式がartifactsから取得できます。

# if you want to build locally
# - task: PublishPipelineArtifact@0
#   displayName: 'Publish Pipeline Artifact'
#   inputs:
#     artifactName: 'UWP_Sln'
#     targetPath: 'UWP'

ちなみにMRTKv1のシンプルなシーンをビルドしてみると、ビルドに30min、長い。

MRTKv1 の Azure DevOps Microsoft-host Agent でのビルド

プロジェクト固有の情報を知らずビルドするコツとして、VSビルド時にslnファイルを指定するのではなくslnのあるフォルダを指定 + /と書くことでslnビルドできます。/ がないとslnが見つからないので注意です。

MRTKv2 のビルドを行う

MRTKv2は、Windows SDK 18362が必要ですが、これがHosted Agentに来てビルドできるようになったのは6/25です。 Sprint 153で追加対応が来てから、自分たちのAgentにくるまで約2週間かかりました。

MRTKv2のビルドは、Microsoft.MixedReality.Toolkit.Build.Editor.UnityPlayerBuildTools.StartCommandLineBuildメソッドを使います。 相変わらずDevelopmentビルドの指定ができないのはアレなのでラッパーを書くことになるでしょう。

MRTKv1を使ったビルドとYAML定義を含んだリポジトリです。

github.com

ビルド定義のYAMLは次のようになります。

gist.github.com

途中のコメントを外すとsln一式がartifactsから取得できます。

# if you want to build locally
#- task: PublishPipelineArtifact@0
#  displayName: 'Publish Pipeline Artifact'
#  inputs:
#    artifactName: 'sln'
#    targetPath: 'Builds/WSAPlayer'

MRTKv2のサンプルシーンをビルドしてみると、ビルドに30min、長い。

MRTKv2 の Azure DevOps Microsoft-host Agent でのビルド

プロジェクト固有の情報を知らずビルドするコツとして、VSビルド時にslnファイルを指定するのではなくslnのあるフォルダを指定と書くことでslnビルドできます。先ほどと違い、/ で終わるとslnが見つからないので注意です。

学び

Unityのインストールにかかる時間

Microsft-hosted Agent にはUnityがインストールされていません。 そのためこのYAMLではUnityを都度インストールしています。

このUnityの準備にかかる時間をリードタイムとしてみると、10min程度かかります。 毎ビルドで10minかかるのはアレでもあり、その程度で済むなら許容できるケースも。

Output変数が定義されたタスクの変数はnameを指定することでとれるようになる

UnityGetProjectVersionTask@1で取得したUnityバージョンを変数に出力します。 これを使うことでUnityプロジェクトのバージョンを知ることなく、同じYAMLをどのUnityバージョンでも変わらず使えます。

さて、UIと違ってYAMLではreference variableの設定はサポートされていません。 しかしTASKで出力変数が設定されている場合は、nameをつけることで取得できます。

- task: DinomiteStudios.64e90d50-a9c0-11e8-a356-d3eab7857116.custom-unity-get-project-version-task.UnityGetProjectVersionTask@1
  displayName: 'Unity Get Project Version'
  name: unitygetprojectversion

これで、後段のstepにおいて$(unitygetprojectversion.projectVersion)で参照できます。 教えてもらって気づきました、これはむりげー。

*1:macOS/Linuxでは、-logFileを無引数で与えるとログが標準出力に出ます

*2:MRTKv1で私の環境ではビルドが60min立っても終わらない状況も発生しました

*3:↑の記事より前に作ったのですが、結果似たことしててあぁって感じです。悲しい

*4:Unity BatchビルドはDevelopment指定が引数でできないのがアレなので、たいがいラッパーを書いている気がします。