Re: C#(Unity)でHTTP/3通信してみる その壱 ～OSSの選定からビルドまで～

この記事は
[【HTTP/3】C#でHTTP/3通信してみる その壱 ～OSSの選定からquicheの.lib/.dllビルドまで～](https://qiita.com/takehara-ryo/items/93a7885a3193796e5a7b)
を **2020/5/16 (土) 現在** の状況に合わせて修正したものです。

# QUIC, HTTP/3 の現状

[C#でHTTP/3通信してみる その弐](https://qiita.com/takehara-ryo/items/3b8c1882812ae0c4e1d2) から早半年……。
QUIC, HTTP/3 の仕様策定は Late Stage Processing[^1] に入り、いよいよ佳境を迎えています。
実装を巡る状況も大分変わっているので、現状にあわせて **C#でHTTP/3通信してみる** を書き直してみようと思います。
[^1]: https://github.com/quicwg/base-drafts/blob/master/CONTRIBUTING.md


# 前回の記事 [C#でHTTP/3通信してみる その壱](https://qiita.com/takehara-ryo/items/93a7885a3193796e5a7b) からの変更点まとめ

- ゴールの再設定 → **Unity で動作させたい**
- OSS の再選定 → **検討の結果 quiche 続行** (今回の記事のメイン)
- ビルド手順の微修正
    - BoringSSL を git submodule 経由で取得するように変更
    - 最新のバージョンに合わせて quiche のビルド手順を修正


# ゴールを決める

新しいゴール : **Unity で HTTP/3, QUIC 通信する**
個人的な事情により、前回の記事では「気が向いたら」扱いだった Unity での利用をゴールに設定します。
前回同様に C# で動かすモジュールを作成してから、それを Unity で叩く流れを紹介する予定です。
全部を一記事にすると非常に長くなりそうなので連作にする予定は変わらずです。
以下、投稿する予定の記事です。

- Re: C#(Unity)でHTTP/3通信してみる その壱 ～OSSの選定からビルドまで～ 
- Re: C#(Unity)でHTTP/3通信してみる その弐 ～Windowsでquicheのサンプルを動かしてみる～
- Re: C#(Unity)でHTTP/3通信してみる その参 ～Unityから使ってみる～

前回の反省を踏まえ **その参** までの作業を大部分終えて当記事を投稿しているので、今回は記事間隔が数カ月あくような事態は発生しない見込みです。
※その弐は明日 5/18 (日) に、その参は ~~5/23 (土) あたりに公開予定です~~ → 5/24 の週に公開予定です


# 利用する OSS の条件

(Unity で使う関係上、前回に比べて条件を少し厳しくしています)

### 必須

- **HTTP/3 のサポート**
- **Unity で利用したい**
    - C# 製、もしくは筆者の慣れの問題から C/C++ 製がベター
        - ただし、 Unity での利用を想定しているので C# のバージョンに縛り有り
    - RUST の場合は C ラッパが用意されているものであればセーフに
- **Android, iOS のサポート**
    - 自前でビルド通せば動くケースも多々あるが、結構しんどいので公式にサポートしてるかどうかを判断基準に
    - 過去の実績や方針等で今後サポートの可能性が高い場合はセーフに
- **アクティブに更新されているもの**
    - RFC へ追いつかない雰囲気があるものは除外

### できれば欲しい

- **パフォーマンスへの配慮**
    - ゲーム(Unity)で使うことを目指しているのでメモリ周りの制御やスレッドでの動作サポートがデフォルトであるのが望ましい
    - 受信データの随時受け取り等メモリ周りの制御は特に重要
- **qlog への対応**
- **HTTP/2 対応**
    - フォールバック用にサポートしてると楽
- **輻輳制御アルゴリズムに BBR が採用されている**
    - 今回はサーバではなくクライアント向けのライブラリの作成ですが、最近はプレイヤーからの配信やリプレイ等クライアントからのアップロードも増えてきたので重要視してみます
    - 参考 : [IETF QUICの実装に使われている輻輳制御のアルゴリズムを調べてみました。(2019/12/6時点)](https://like-cat.hatenablog.com/entry/2019/12/06/223835) - neko--suki’s blog

### 不要

- **QUIC DATAGRAM[^2] への対応**
    - まだ QUIC DATAGRAM に対応している OSS はほぼ無い為、今回の条件には含めない

[^2]: QUIC DATAGRAM は QUIC 上で信頼性の低いデータ通信を行う為の拡張仕様です。詳細は[『くいっく』DATAGRAM編](https://quic.booth.pm/items/2015228)にて解説していますよ！(宣伝)


# OSS 選定 - 候補を選ぶ

半年前に比べて選択肢がかなり増えたので、一通り再確認していこうと思います。
基本的には [QUIC WG base-drafts の Implementations](https://github.com/quicwg/base-drafts/wiki/Implementations) に掲載されている OSS から選定していきますが、一部例外も有りです。

また、 Robin Marx さんが [A Study of QUIC and HTTP/3 Implementation Diversity - submitted to EPIQ2020](https://qlog.edm.uhasselt.be/epiq/) という記事で QUIC を実装したライブラリを一部ピックアップして、アルゴリズムや性能比較をしてくださっているのでこれも参考にします。

それでは、いってみましょー。

### Apache Traffic Server

- **Language:** C++
- **Roles:** Server, Client
- **HTTP/3 Support:** Yes
- **License:** Apache License Version 2.0
- **Repository**: https://github.com/apache/trafficserver

Apache Traffic Server は Apache Software Foundation が開発を進めている高性能 HTTP キャッシュプロキシサーバ(クライアント実装も有り)です。
以下 [公式ドキュメント](https://cwiki.apache.org/confluence/display/TS/QUIC) より抜粋。

> Apache Traffic Server™ はネットワークの縁で頻繁にアクセスされる情報をキャッシュすることでネットワークの効率とパフォーマンスを改善するハイパフォーマンスなウェブプロキシーキャッシュです。これはより速い配信と帯域使用量の削減を実現すると同時に、エンドユーザに物理的に近いコンテンツを提供します。Traffic Server は企業向けコンテンツ配信、インターネットサービスプロバイダ (ISP) 、バックボーンプロバイダ、そして大きなイントラネットが持つ既存の利用可能な帯域幅を最大化することによって改善するために設計されました。

パフォーマンスに寄せた実装になってそうなので惹かれますが、モバイル系に対応していない(反面、出自的に Linux 系には物凄い強いです)ので今回は採用を見送ります。


### LiteSpeed QUIC (LSQUIC)

- **Language:** C
- **Roles:** Client, Server, Library
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/litespeedtech/lsquic

LSQUIC は Web サーバとして最近名を上げつつある LiteSpeed の開発を手掛ける LiteSpeed Technologies が主導する C 言語製の OSS です。
LiteSpeed Web サーバー、 LiteSpeed ADC 、 OpenLiteSpeed 等の LiteSpeed Technologies の製品・サービスにて利用されているようです。
対応プラットフォームは Linux, FreeBSD, MacOS, Windows とのこと。
サーバ系の利用を目的としたものなのでこちらも出自的に仕方ないですが、モバイル非対応の空気を感じるので今回は採用を見送ります。


### Proxygen

- **Language:** C++
- **Roles:** client, server, library
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/facebook/proxygen

Proxygen は Facebook により開発が進められている C++ 製の OSS です。
同様に Facebook が開発している QUIC を実装する [mvfast](https://github.com/facebookincubator/mvfst) を下層に持ちます。
現在はサーバ側をメインに実装が進んでいるようで、 GSO にも対応している等パフォーマンス的にかなり期待が持てそうです。
現状の対応プラットフォームは Ubuntu 18.04 と Mac OSX です。
将来的には Android, iOS へは対応しているので良さそうな雰囲気なのですが、 Windows をサポートしておらず、 C# へ繋ぐ開発を行うのが結構しんどそうです。
心惹かれるものがありますが今回は採用を見送ります。


### Neqo

- **Language:** Rust
- **Roles:** library, client, server (server needs work)
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/mozilla/neqo

Neqo は Mozila が開発している Rust 製の OSS で、 Firefox に採用されています。
build.rs 見る感じ Windows, Andoroid に対応している(iOS はまだなさげ)のでいい感じなのですが、フル Rust 製(C ラッパが用意されてない)なので今回は採用を見送ります。


### nghttp3

- **Language:** C
- **Roles:** client, library, server
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/ngtcp2/nghttp3

nghttp3 は前回の記事でも検討した C 製の OSS です。
CURL の実装である libcurl の下層（HTTP/2 部)に用いられている nghttp2 のメインコミッターである Tatsuhiro Tsujikawa さんが主導し実装が進められています。
QUIC レイヤーの実装は同じプロジェクト内で開発されている [ngtcp2](https://github.com/ngtcp2/ngtcp2) に依存しています。
現状 Andoroid, iOS には対応していないようですが、過去の実績(nghttp2)から 将来的に対応する可能性は高めです。
条件にマッチしているので **候補1** とします。


### picoquic

- **Language:** C
- **Roles:** library and test tools, test client, test server
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/private-octopus/picoquic

picoquic は [Private Octopus](https://www.privateoctopus.com/index.html) が開発している C 言語製の OSS です。
HTTP 向け以外の QUIC 拡張を試すことを目的の一つとしている点が他の OSS と大きく異なっています。
picoquic をベースにした、 DNS over QUIC の実装である [quicdoq](https://github.com/private-octopus/quicdoq) も同時に開発しているようです。
SiDUCK[^3] にも現時点で既に対応していたり、中々意欲的なプロジェクトだと思います。
[^3]: Simple Datagram Usability and Connectivity Kata の略で、QUIC DATAGRAM の接続性のテストに用いる仕様です。詳細は[『くいっく』DATAGRAM編](https://quic.booth.pm/items/2015228)にて解説していますよ！(宣伝)
Visual Studio 2017 のプロジェクトが用意されていたりと開発もし易そうですが、残念ながら対応プラットフォームが Windows/Linux/MacOZ/FreeBSD とモバイル系には非対応です。
プロジェクトの目的から今後も Andoroid, iOS への対応は期待薄なので今回は採用を見送ります。


### Quant

- **Language:** C11
- **Roles:** client, library, server
- **HTTP/3 Support:** No
- **License:** BSD
- **Repository**: https://github.com/NTAP/quant

QUANT は NetApp により開発されている POSIX 及び IoT プラットフォーム向けに開発されている C11 製の OSS です。
QUIC レイヤーのみの提供で HTTP/3 には対応していない為今回は採用を見送ります。


### quiche

- **Language:** Rust
- **Roles:** library, client, server
- **HTTP/3 Support:** Yes
- **License:** [BSD 2-Clause "Simplified" License](https://github.com/cloudflare/quiche/blob/master/COPYING)
- **Repository**: https://github.com/cloudflare/quiche

quiche は CDN ベンダーの CloudFlare が主導して開発が進められている Rust 製の OSS です。
Rust API の上に被せる C 言語製のラッパも提供しているのも特徴で、 C/C++ のアプリケーションやライブラリからも簡単に呼び出すことができます。
現段階で Android, iOS のビルドについても標準でサポートしているのも強みです。
Windows の標準ビルド環境は整っていませんが、 前回の記事で採用した関係で Windows のビルドについては問題なしとします。
条件にマッチしているので **候補2** とします。


### quicly

- **Language:** C
- **Roles:** client and server
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/h2o/quicly

quicly は H2O HTTP server での利用を目的として開発されている C 製の OSS です。
CDN ベンダーの Fastly 所属である Kazuho Oku 氏と Jana Iyengar 氏が主導し開発が進められているようです。
quicly については [Can QUIC match TCP’s computational efficiency?](https://www.fastly.com/blog/measuring-quic-vs-tcp-computational-efficiency) という記事が書かれる程パフォーマンスについて意識が割かれています。
ただし、非常に残念ながらモバイル系には非対応な為、今回は採用を見送ります。


### Quinn

- **Language:** Rust
- **Roles:** library, client, server
- **HTTP/3 Support:** No (将来的には対応予定)
- **License:** MIT
- **Repository**: quinn

Quinn は Dirkjan Ochtman 氏と Benjamin Saunders 氏によって開発されている Rust 製の OSS です。
現在 Linux/MacOS/Windows に対応しています。
モバイル非対応 & フル Rust 製(C ラッパが用意されてない)ので今回は採用を見送ります。


### libcurl

- **Language:** C
- **Roles:** client
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/curl/curl

libcurl は CURL の内部実装である C 言語製の OSS です。
libcurl 自体には QUIC, HTTP/3 層の実装は含まれておらず、他の OSS(quiche もしくは ngtcp2 のいずれかを選択)に依存しています。
今回紹介する OSS の中でも随一の歴史を誇るだけあり、 HTTP の機能が非常に豊富なのが強みです。
(ただし、その分内部実装も若干歴史を感じさせるものとなっており、オーバーヘッドは若干気になります)
[HTTP3.md](https://github.com/curl/curl/blob/master/docs/HTTP3.md) を見る限りだと現状の対応プラットフォームが謎(プラットフォームも quiche/ngtcp2 に依存？)ですが、過去の実績的には Android/iOS といったモバイルにも対応するのは間違いない安心感があります。
条件にマッチしているので **候補3** とします。


### MsQuic

- **Language:** C
- **Roles:** client, server
- **HTTP/3 Support:** No
- **License:** MIT
- **Repository**: https://github.com/microsoft/msquic

MsQuic は MicroSoft が開発をしている C 言語製の OSS です。
以下を目指して開発が進められています。

- Windows カーネルの HTTP/3 スタックでの利用
- [ASP.NET Core の Kestrel](https://github.com/dotnet/aspnetcore) 及び [.Net の HttpClient](https://github.com/dotnet/runtime) での HTTP/3 のサポート
    - どちらも .Net 5 のプレビュー版にて実装中
    - Kestrel は QUIC 層も完備
- MS365 や Windows SMB での活用

「受信処理を別スレッドで非同期に処理できる」、「受信データを一括ではなく都度処理できる」、「データコピーしない送信モードも完備」、「GRACEFUL シャットダウンも用意されている」等、現時点でも非常に高機能で心惹かれますが **HTTP/3 には非対応** です。かなしい。
と言う訳で今回は採用を見送ります。


### .Net 5

- **Language:** C#
- **Roles:** client, server
- **HTTP/3 Support:** Yes
- **License:** MIT
- **Repository**: https://github.com/dotnet/runtime

MsQuic 項でも触れたように、 .Net 5 において HTTP/3 のモジュールの実装が進められています。
しかし、残念ながら Unity は現状 .Net 5 に対応していない為、今回は採用を見送ります。
また、[Unity Forums のやりとり](https://forum.unity.com/threads/net-5-support.839890/page-2) によると「It is very unlikely that any .NET Core or .NET 5 support will land in 2020 LTS.」とのことなので、Unity 2020 の LTS で .Net 5 対応する可能性は低く、当面利用できないと捉えておくのが良さそうです。
将来的には.Net の Core class ライブラリの利用及び Mono の CoreCLR への置き換えを検討しているようなので、これに期待しましょう。
(CoreCLR は実験的なものだからリリースできるかあやしいとも書いているので過度の期待は厳禁かもしれません)


# OSS 選定 - 利用する OSS の確定

長くなりましたが、候補が nghttp3, quiche, libcurl に絞られました。
前回の記事での検討時にもこの 3 つの OSS は挙がっているので、モバイルも含めての C# での HTTP/3 の実装については、なんだかんだで半年前とあまり状況は変わっていないと言えそうです。
(モバイルは HTTP/3 普及期に入ってから実装が進むと思われるので、これは自然の流れかなと思います)

この 3 ライブラリを **できれば欲しい** の条件 + α で再度検討してみます。

|ライブラリ|スレッド|メモリ|HTTP/2|qlog|輻輳制御|
|:-:|:-:|:-:|:-:|:-:|:-:|
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nghttp3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|×|〇|×|〇|NewReno|
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;quiche&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|×|〇|×|〇|NewReno<br>CUBIC|
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;libcurl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|×|〇|〇|〇|－|

- － : 下層のライブラリの実装に依存
- スレッド : 内部的にスレッドで処理を行うかどうか。非同期ソケットやイベントで動作するのとは別。スレッドセーフかどうかとも別
- メモリ : 受信したデータを都度ライブラリから受け取って処理することができるか

上記の表ベースでは、 HTTP/2 が利用できる面で libcurl が一歩リードしています。
しかし、 [libcurl の GitHub - Wiki](https://github.com/curl/curl/wiki/HTTP3) によると **ストリーム多重化** が現状未実装のようです。
多重化が使えないのは流石に HTTP/3 採用の意味が薄いので、 libcurl での HTTP/3 実装は時期尚早として今回は採用を見送ることにします。

残る nghttp3 と quiche は上記の条件ではほぼ拮抗しているようです。
先ほどの Robin Marx さんの記事  [A Study of QUIC and HTTP/3 Implementation Diversity - submitted to EPIQ2020](https://qlog.edm.uhasselt.be/epiq/) でもそこまで優位な差があるようには見えません。
どちらにするか非常に悩ましいですが、以下の理由から今回は **quiche を選択することに決定とします**。

- quiche は現時点で Android/iOS 対応している
- quiche は Hystart++[^4] に最近対応した
- nghttp3 はサンプルがまだ整備されていない
    - [nghttp3.h](https://github.com/ngtcp2/nghttp3/blob/master/lib/includes/nghttp3/nghttp3.h) にあるリファレンスが丁寧なので、しっかり読めば問題なく使えそうではありますが、前回の記事で触ったことがある quiche に比べるとちょっと心理的なハードルがあります

[^4]: 参考 : [TCP Slow Startを改善する HyStart++について - ASnoKaze blog](https://asnokaze.hatenablog.com/entry/2019/07/12/224758)


### 補足 : 現状での Unity での QUIC, HTTP/3 実装方針例

今回の記事では quiche を使いますが、製品に利用するのであれば libcurl を使う方が HTTP 関連の色々な処理をしてくれて楽なのでお勧めです。
ただし、 libcurl の実装方針が HTTP/2 と HTTP/3 で同様と想定する(現状の実装ではそう見えます)と、パラメータ設定においてかなりの部分が隠蔽されてしまう為に、制御があまり効きません[^5]。
[^5]: 参考 : [【Unity】Unite Tokyo 2019 「大量のアセットも怖くない！～HTTP/2による高速な通信の実装例～」講演と壇上では語られなかった６つのこと。](http://techblog.sega.jp/entry/2019/10/30/100000#HTTP2-%E7%89%B9%E6%9C%89%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%82%92-libcurl-%E3%81%8B%E3%82%89%E8%A1%8C%E3%81%86%E3%81%AB%E3%81%AF) - SEGA TECH BLOG
通常のゲームやアプリにおける HTTP/3 通信で QUIC 関連のパラメータをいじりたいケースは稀なのであまり気にしないで良いとは思いますが、利用する際は心にとめておいた方が良いと思います。

また、今までの内容を踏まえ、お勧めのモバイル環境を含む Unity での QUIC, HTTP/3 実装方針について以下にまとめてみました。
時期別(あくまで個人的な予想ベース)に分けてあるので参考にして頂ければと。

- **今すぐ**
    - QUIC を使いたい場合 → quiche もしくは nghcp2 で頑張ろう
    - HTTP/3 を使いたい場合** → quiche もしくは nghttp3 で頑張ろう
- **libcurl の対応がある程度固まって、 Unity が .Net 5 に対応するまでの間** (予想 : 2020 年後半くらい～)
    - QUIC を使いたい場合 → MsQuic を利用 (タイミング次第ではまだ利用が厳しい可能性あり)
    - HTTP/3 を使いたい場合** → libcurl を利用
- **Unity が .Net 5 に対応した後** (予想 : 2021 年後半くらい～)
    - QUIC を使いたい場合 → Kestrel を利用
    - HTTP/3 を使いたい場合 → HttpClient を利用

.Net 5 対応はよ……。


# quiche をビルドするまでの道のりを確認

**注意 : ここからの内容は前回の記事の内容を最新バージョンの quiche での作業に差し替えて、以下を書き換えたものです**

- BoringSSL を git submodule 経由で取得するように変更
- 最新のバージョンに合わせて quiche のビルド手順を修正


それでは quiche をビルドしてみましょう。
リポジトリ : https://github.com/cloudflare/quiche
前述した通り、 quiche は RUST 製の OSS ですが、C 製のラッパ(quiche.h)も提供してくれています。
筆者は Rust はほとんど触ったことがないレベルなので、今回はこの C ラッパ層を呼び出せるような Windows の動的/静的ライブラリを作成します。
C# から直接 Rust 製の .dll の呼び出しも可能なので、慣れている人はこうしたラッパを作らずにそのまま Rust でビルドしても良いと思います。
(が、C# 層から使い易いようにどちらにせよ一段噛ませた方が良い印象はあります)

ちなみに、 C# から呼び出す段では .dll を作成する必要がありますが、 OSS の上にもう一段ラッパ層を作成する予定なので、quiche のビルドは .lib/.dll どちらでも問題ありません。
好みに合わせて作成できるように、当記事では両方の手順を記載しておきます。

### quiche のビルド方法の確認

quiche のビルドには ``cargo build`` を用います。
``cargo build`` は Rust のビルドシステム&パッケージマネージャである Cargo を使ったビルドコマンドです。

デフォルトの設定では ``libquiche.a`` しかビルドしてくれないようなので、 .lib や .dll をビルド可能なように自前で設定してあげる必要があります。
また、quiche は BoringSSL に依存しているので、こちらも同様に .lib/.dll を用意してあげる必要があります。

> Calling quiche from C/C++
> quiche exposes a thin C API on top of the Rust API that can be used to more easily integrate quiche into C/C++ applications (as well as in other languages that allow calling C APIs via some form of FFI). The C API follows the same design of the Rust one, modulo the constraints imposed by the C language itself.
When running cargo build, a static library called libquiche.a will be built automatically alongside the Rust one. This is fully stand-alone and can be linked directly into C/C++ applications.



# BoringSSL のビルド準備

と言う訳で、まずは BoringSSL を準備しましょう。
quiche のリポジトリが BoringSSL を submodule として取り込んでいるので、まずは quiche を ``--recursive`` 付きで clone します。

~~~
$ git clone --recursive https://github.com/cloudflare/quiche
~~~

BoringSSL の Windows 版(.lib/.dll)ビルドには以下のモジュールが必要です。

- CMake (必須)
- Perl (必須)
- NASM (必須)
- C/C++ コンパイラ (必須)
- Go (必須)
- Ninja (推奨)

1つずつセットアップしていきましょう。

### CMake

3.0 以上が必要です。
https://cmake.org/download/
から Windows 用のインストーラーをダウンロードして展開しましょう。
今回は CMake 3.15.3 を使用しています。

### Perl

Perl の最新バージョンが必要です。
Windows では ActivePerl と MSYS Perl が利用できます。
StrawberryPerl も使えるようですが、 CMake と ``PATH`` の取り扱いで競合が起きるようで面倒とのことです。
ActivePerl は以下のサイトから入手可能です。
https://www.activestate.com/products/activeperl/
アカウント登録をするとリポジトリができるので、「Buildタブ」 ⇒ 「Windows 10 タブ」から好きな形式でダウンロードしましょう。
<img width="500" alt="perl.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258608/557a7e9a-b0de-efe5-a974-0c0774f43c32.png">
インストーラーから入れると勝手にパスが設定されますが、環境変数 ``PERL_EXECUTABLE`` で指定しても OK です。
今回は ActivePerl 5.8 を使用しています。

### NASM

BoringSSL は一部にアセンブリを使用しているようで、 Windows でビルドするには NASM が必要です。
NASM は Netwide Assembler の略で x86 系を対象としたアセンブラです。
https://www.nasm.us/ からダウンロードしてパスを通しましょう。
今回は NASM 2.14.02 を使用しています。

### C/C++ コンパイラ

Windows ビルドでは Platform SDK 8.1 以降を含む MSVC 14(Visual Studio 2015) 以降がサポートされているようです。
GCC 4.8 移行でもいけるようですが、ドキュメントの表記が **maybe** なので MSVC 側を使う方が無難そうです。
CMake 時には MSVC の ``cl.exe`` へのパスを通してあげる必要がありますが、単体でパスを通すのではなく関連の環境変数をまとめせて設定してくれる ``vcvars64.bat`` 等を使いましょう。
参照 [コマンドラインからMicrosoft C ++ツールセットを使用する(MSDN)](https://docs.microsoft.com/ja-jp/cpp/build/building-on-the-command-line?view=vs-2019)
今回は Visual Studio 2019 を使用しています。

### Go

最新の安定バージョンが必要です。
https://golang.org/dl/ 等からインストールしてパスを通しましょう。
パスとを通す代わりに、環境変数 ``GO_EXECUTABLE`` でもパス指定が可能です。
今回は Go 1.13 を使用しています。

### Ninja

Ninja は CMake の置き換えを目指して作られた高速なビルドシステムです。
Windows 版 BoringSSL をビルドするには、 この Ninja を使うか CMake のみで実施するかの二つの選択肢があるようです。
しかし、 Windows 環境での CMake のみでのビルドはメンテされていないようなので、現状では Ninja を使うしかなさそうです(どっちにせよビルドが圧倒的に早いので Ninja の方が良いとは思いますが)。
と言う訳で https://github.com/ninja-build/ninja/releases から Ninja を落としてパスを通してください。
今回は Ninja 1.9.0 を使用しています。


# BoringSSL のビルド

上記の準備が完了したら Ninja を使って BoringSSL のビルドを実行します。
手順はとても簡単です。

最初に clone した quiche のリポジトリの ``deps\boringssl`` に移動して以下のコマンドを叩いてください。

~~~
(必要に応じて MSVC 等へのパスを通す)
$ mkdir build
$ cd build
$ cmake -GNinja ..
$ ninja
~~~

何かしらにパスが通ってないと
``cmake -GNinja ..``
でエラーが出ますが、エラーメッセージが分かり易いので苦労しないと思います。
(vcvars64.bat 実行漏れでのパス設定忘れに注意)

成功すると以下の ``.lib`` ファイルができます。

``build\crypto\crypto.lib``
``build\decrepit\decrepit.lib``
``build\ssl\ssl.lib``

このうち ``crypto.lib`` と ``ssl.lib`` を使用します。

### ビルドオプション

リリースビルドしたい時には ``-DCMAKE_BUILD_TYPE=Release`` を指定します。

~~~
$ cmake -DCMAKE_BUILD_TYPE=Release -GNinja ..
~~~

.dll をビルドしたい時には ``-DBUILD_SHARED_LIBS=1`` を cmake 時のオプションとして指定します。
※ quiche のビルドには .lib が要求されるので今回は不要です

~~~
$ cmake -DBUILD_SHARED_LIBS=1 -GNinja ..
~~~

また、``OPENSSL_SMALL`` を定義するとコードサイズ等削れるようです(詳細は追っていないです)。
今回はお試し実装なので、この設定や使用する暗号スイートの制限等は無しでそのまま使います。

### C ランタイムライブラリの指定

quiche のビルドは Rust の Cargo で行いますが、Cargo では ``MDd``, ``MTd`` を指定することはできません。
また、``MT``のビルドも若干手間が掛かります。
BoringSSL の設定はデフォルトでは ``MD`` でのビルドなので、基本的にはそのまま ``MD`` で行くのが良さそうです。
何らかの事情で ``MT`` でビルドしたい場合には、CMakeLists.txt に以下の変更を加えることで実現可能です。

~~~
set(CompilerFlags
    CMAKE_CXX_FLAGS
    CMAKE_CXX_FLAGS_DEBUG
    CMAKE_CXX_FLAGS_RELEASE
    CMAKE_C_FLAGS
    CMAKE_C_FLAGS_DEBUG
    CMAKE_C_FLAGS_RELEASE)
foreach(CompilerFlag ${CompilerFlags})
    string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()
~~~

``project(BoringSSL NONE)`` の後ろにでも雑に付け加えましょう。
※Windoiws 以外でもビルドする場合は ``if(WIN32)`` 等で囲むこと

Ninja により生成された細かいビルドオプションを確認したい場合は ``cmake -GNinja ..`` 後に生成される build\build.ninja 内にあるので、そちらを参照しましょう。

# quiche のビルド準備

いよいよ quiche のビルドに入ります。

### Rust 環境のセットアップ

先ほども書いたように、 quiche のビルドには Rust のビルドシステム&パッケージマネージャである Cargo が必要です。
Cargo は Rust に付属されているので、まずは Rust をインストールします。
@euledge さんが [Windows10でRustの開発環境を構築](https://qiita.com/euledge/items/ce3e24a2b8020441cd85) をまとめてくださっているので、これを参考に環境を構築してください(詳細は割愛)。
現状 Rust のバージョンは **1.39 かそれ以降**のものを利用する必要があるようです。

### Cargo のコンフィグファイルを修正する

このリポジトリのカレントディレクトリに Cargo.toml という Cargo のコンフィグファイルがあるので、 .lib/.dll がビルドされるようにこのファイルの ``crate-type`` を変更します。

.lib を作りたい場合
``crate-type = ["staticlib"]``

.dll を作りたい場合
``crate-type = ["cdylib"]``

まとめて
``crate-type = ["staticlib", "cdylib"]``

### BoringSSL のライブラリにパスを通す

環境変数 ``QUICHE_BSSL_PATH`` に先ほどビルドした BoringSSL のカレントディレクトリを指定してください。
更に、 BoringSSL でビルドした際に生成されるデフォルトのパスを quiche は見に行かないので、ディレクトリ構成を変更してあげる必要があります。

- Debug 時
    - ``crypto.lib`` 関連ファイルを ``build\crypto\Debug`` に入れる
    - ``ssl.lib`` 関連ファイルを ``build\ssl\Debug`` に入れる
- Release 時
    - ``crypto.lib`` 関連ファイルを ``build\crypto\RelWithDebInfo`` に入れる
    - ``ssl.lib`` 関連ファイルを ``build\ssl\RelWithDebInfo`` に入れる

上記の構成にするのが面倒な場合は BoringSSL 側のコンフィグを直すか、もしくは quiche 内に同梱されている ``src\build.rs`` の以下の内容を任意のパスに修正すると良いです。

~~~
        if cfg!(debug_assertions) {
            return format!("{}/Debug", lib);
        } else {
            return format!("{}/RelWithDebInfo", lib);
        }
~~~

# quiche のビルド

お疲れさまでした。ここまでくればあとは Cargo を叩くだけです！

~~~
$ cargo build
~~~

ビルドが成功するとカレントディレクトリ直下にある ``target¥Debug`` フォルダ内に .lib/.dll が生成されます。
(適当に Visual Studio からリンクして呼び出せることまでは確認してますが割愛します)

Release ビルドしたい時は ``--release`` オプションを付けます。

~~~
$ cargo build --release
~~~


また、この手順で生成されるのはランタイムライブラリは ``MD``、プラットフォームは x64 であることに注意してください(x86 ビルドの方法は未調査です)。
ログの詳細が欲しい場合は ``--verbose`` オプションを付けると若干詳しい内容が出てきます。
ビルドが上手くいかない時は ``cargo clean`` で一度一時ファイルを削除してから試してみてください。

長くなりましたが、以上で **Re: C#(Unity)でHTTP/3通信してみる その壱 ～OSSの選定からビルドまで～** の手順は完了です。
Next!! → [Re: C#(Unity)でHTTP/3通信してみる その弐 ～Windowsでquicheのサンプルを動かしてみる～](https://qiita.com/takehara-ryo/items/4cbb5c291b2e94b4eafd)

### おまけ： quiche を ``MT`` でビルドする

環境変数 RUSTFLAGS に ``MT`` であることを明示する以下のオプションを設定してから ``cargo build`` してください。

~~~
RUSTFLAGS=-C target-feature=+crt-static
~~~

参考 : https://doc.rust-lang.org/reference/linkage.html