Flutter Desktop EmbeddingをWindowsでビルド

## はじめに

令和元年5月6日時点における情報になります。

`Flutter Desktop Embedding` を触ってみようとしたところ、ビルド方法が `GN` + `Ninja` を使用するように変更されていました。
この `Ninja` を使ったビルド方法についての情報が見つけられなかったので残しておきます。

## 環境構築

**Windows10 Pro ver.1803** において、以下3点の環境構築を行いました。

* C++開発環境
* ビルドツール `Ninja`, `GN`
* `Flutter` と `Flutter Desktop Embedding` のソース

### C++開発環境

*Visual Studio 2017* を入れてなかったので *Build Tools* を使ってみることにしました。
すでに *Visual Studio 2017* の環境がある方は、 **Desktop development with C++** も入っていれば大丈夫なようです。

[Visual Studio][visual_stdio] のダウンロードページから **Build Tools for Visual Studio 2019** をダウンロード。
ダウンロードした `vs_buildtools_*.exe` を実行し、*Visual Studio Installer* をインストール。

![10-54-20-a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238841/3f6d712a-1b78-b2e2-5468-99913aa66e02.jpeg)

*C++ Build Tools* の以下についてインストールする。

  * ツールのコア機能のテスト - ビルドツール
  * MSVC v141 vs 2017
  * Windows 10 SDK 10.0.17134.0 
  ![14-02-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238841/8477d6a3-be97-a1af-da0f-5147751925b0.png)

インストール後、`MSBuild.exe` と `vcvars64.bat` への `PATH` を通す（`MSBulid.exe` はサンプルをビルドする際に使用する）。
今回はユーザー環境変数に追加している。

```powershell:powershell
$vspath = [Environment]::GetEnvironmentVariable('Path', 'User')
$vspath += ';' + 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build'
$vspath += ';' + 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
[Environment]::SetEnvironmentVariable('Path', $vspath, 'User')
```

自環境では `vcvars64.bat` が存在しなかったので作成した。
また `cl.exe` やヘッダーファイルへの `PATH` も通っていなかったので、ここで設定しておく。
ヘッダーファイルは環境変数 `INCLUDE` で設定する。

```powershell:powershell(管理者)
> cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build"
> echo @'
@set PATH=%PATH%;%~dp0..\..\Tools\MSVC\14.16.27023\bin\HostX64\x64
@set INCLUDE=%INCLUDE%;%~dp0..\..\Tools\MSVC\14.16.27023\include
@call "%~dp0vcvarsall.bat" amd64
'@ |
Out-File ".\vcvars64.bat" -Encoding Default
```

`powershell` を再起動して `PATH` を更新する。

```powershell:powershell
PS > vcvars64.bat

**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.0
** Copyright (c) 2019 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
```

### ビルドツール `Ninja`

Makefile代替としてC++プロジェクトをビルドするのに使われるツール。
Makefileと比べて高速でビルドしてくれる。
Chromiumのプロジェクトでも使われているらしい。

今回は [Scoop](https://scoop.sh/) を用いてインストールした。
他の方法として、[Chocolateyを使ったり](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages)、[バイナリをダウンロード](https://github.com/ninja-build/ninja/releases)したりしてください。

```powershell:powershell
> scoop install ninja
> ninja --version
1.9.0
```

### メタビルドツール `Generate Ninja (GN)`

上記 *Ninja* のビルド設定ファイルを出力するツール。
Googleが開発してる。

Windows用のバイナリを [ダウンロード](https://chrome-infra-packages.appspot.com/dl/gn/gn/windows-amd64/+/latest) して `PATH` を通しておく。
今回はユーザー環境変数に追加している。

```powershell:powershell
$syspath = [Environment]::GetEnvironmentVariable('Path', 'User')
$syspath += ';' + '\path\to\gn\bin'
[Environment]::SetEnvironmentVariable('Path', $syspath, 'User')
```

`PATH` を変更したら `powershell` を一度開き直して更新させる。

```powershell:powershell
> gn --version
1565 (d409ab89)
```

### `Flutter` と `Flutter Desktop Embedding`

作成したプロジェクトディレクトリ以下に `flutter` と `flutter-desktop-embedding` のgitリポジトリをクローンする。

```powershell:powershell
mkdir desktop-embed
cd desktop-embed
git clone https://github.com/flutter/flutter
git clone https://github.com/google/flutter-desktop-embedding
```

## ビルド手順

### GNによるNinjaファイルの生成

**直接 `gn` コマンドは使わず、`flutter-desktop-embedding/tools/gn_dart.bat` ファイルを使用する。**

出力ディレクトリは `./out` 以下を指定するのが慣例のようです。

初回は `flutter` の初期化が行われる。

```powershell:powershell
> cd flutter-desktop-embedding
> tools/gn_dart.bat gen out/Default
Checking Dart SDK version...
Downloading Dart SDK from Flutter engine 2f11d3c4a205eca899de19617303ca8174ada7e3...
Unzipping Dart SDK...
Building flutter tool...
Running pub upgrade...
Downloading Material fonts...                                       0.8s
...
Done. Made 3 targets from 7 files in 9ms
```

### Ninjaによるコンパイル

上記で生成されたファイルをもとにコンパイル。

```shell:powershell
ninja -C out/Default
```

いくつかWarnningが出るが、`out\Default\gen\flutter_library` 以下に `flutter_windows.dll` などが生成される。

#### エラー `Your Flutter tree is too old`

`flutter` をshallow copyすると、必要なコミット履歴が見つからずエラーが発生する。
よってshallow copyせずに全履歴をクローンする。

```powershell:powershell
> ninja -C out/Default
...
Running git merge-base --is-ancestor 829130ddfcf84aa683291744fb6d170f61f0287b HEAD
fatal: Not a valid commit name 829130ddfcf84aa683291744fb6d170f61f0287b
Flutter library update aborted: Your Flutter tree is too old for use with this project. Please update to a newer version of Flutter, then try again.

Note that this may require switching to Flutter master. See:
https://github.com/flutter/flutter/wiki/Flutter-build-release-channels
ninja: build stopped: subcommand failed.
```

## サンプル実行

`flutter` ツールを利用して実行できるようになった関係で、初回は必ず `flutter run` から起動しなければいけない。
また `flutter run` 実行前に、環境変数 `ENABLE_FLUTTER_DESKTOP` を `true` に設定しておく。

```powershell:powershell
> cd example
> $env:ENABLE_FLUTTER_DESKTOP="true"
> ..\..\flutter\bin\flutter run
Launching lib/main.dart on Windows in debug mode...
Building Windows application...
[ERROR:c:\b\s\w\ir\k\src\flutter\shell\platform\embedder\embedder_surface_gl.cc(95)] Could not create a resource context for async texture uploads. Expect degraded performance. Set a valid make_resource_current callback on FlutterOpenGLRendererConfig.
[ERROR:c:\b\s\w\ir\k\src\flutter\shell\platform\embedder\embedder_surface_gl.cc(95)] Could not create a resource context for async texture uploads. Expect degraded performance. Set a valid make_resource_current callback on FlutterOpenGLRendererConfig.
Syncing files to device Windows...                               1,555ms
```

上記のエラーは昔から発生しているもので、エラーというより警告と捉えればいいようです。
（[Example on Windows doesnt respond to mouse input · Issue #363 · google/flutter-desktop-embedding](https://github.com/google/flutter-desktop-embedding/issues/363)）

成功すれば下図のようなアプリが立ち上がります。
`+` ボタンを押せば中央の数値が加算されていくのが見て取れます。

![example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238841/8e310e3d-fc92-c92f-718b-451bd5375225.png "Flutter Desktop Embedding example")

### 遭遇したエラー

#### `Unable to locate a development device`

```powershell:powershell
> ..\..\flutter\bin\flutter run
Unable to locate a development device; please run 'flutter doctor' for information about installing
additional components.
```

環境変数 `$env:ENABLE_FLUTTER_DESKTOP="true"` の設定を忘れていると発生する。
`flutter run` 実行前にはちゃんと設定しておきましょう。

```powershell:powershell
$env:ENABLE_FLUTTER_DESKTOP="true"
..\..\flutter\bin\flutter run
```

#### `The current Flutter SDK version is 0.0.0-unknown`

```powershell:powreshell
> ..\..\flutter\bin\flutter run
The current Flutter SDK version is 0.0.0-unknown.

Because example_flutter requires Flutter SDK version >=1.5.9-pre.56, version solving failed.
Running "flutter packages get" in example...
pub get failed (1)
```

`flutter` を `git clone` する際にうまく初期化できていなかったときに起こるエラー。

[Workarounds for common issues - flutter/flutter](https://github.com/flutter/flutter/wiki/Workarounds-for-common-issues#flutter-installation-corrupted) の手順に従えば解決する。

>```shell
>git clean -xfd
>git stash save --keep-index
>git stash drop
>git pull
>flutter doctor
>```

---

## 終わりに

とりあえずライブラリをビルドしてサンプルを動かしただけですが、`Ninja` や `GN` について知らなかったのでつらたんでした。
色々いじってみるのは今後の課題に残します。

`Flutter Desktop Embedding` は開発途中のプロジェクトなので、このビルド方法もいつまで正しいかわからないことはご注意ください。

## 参考

[google/flutter-desktop-embedding](https://github.com/google/flutter-desktop-embedding)
[gn - Git at Google](https://gn.googlesource.com/gn/)
[Ninja, a small build system with a focus on speed](https://ninja-build.org/)

[Address VS 2019 compatibility · Issue #342 · google/flutter-desktop-embedding](https://github.com/google/flutter-desktop-embedding/issues/342)
[ninjaでリソースビルド - Qiita](https://qiita.com/towazumi/items/2bdb590caa9d61121886)
[Flutter desktop embedding を Windows で試す - Qiita](https://qiita.com/kikuchi_kentaro/items/b12754293ae35e7f1f58)

[vs2015でコマンドラインでプログラムをコンパイルする際のincludeパスの設定](https://ja.stackoverflow.com/questions/30403/vs2015でコマンドラインでプログラムをコンパイルする際のincludeパスの設定/30437)
[知っておくと便利な git clone --depth と git diff --indent-heuristic - kakakakakku blog](https://kakakakakku.hatenablog.com/entry/2017/03/22/195640)

[visual_stdio]:https://visualstudio.microsoft.com/ja/downloads/