libh2o をビルドする


[h2o Advent Calendar](http://qiita.com/advent-calendar/2014/h2o) の2日目です。

h2o はスタンドアロンの HTTP サーバーだけでなく、 libh2o というライブラリとしてビルドすることもできます。今回は libh2o をビルドして、 hello world サーバーを作るまでやってみます。

環境は Ubuntu と Mac OS X を想定しています。

## cmake

h2o はビルドシステムに cmake を利用しています。 brew なり apt-get なりで cmake を用意しておきましょう。

他に、後述する libuv のために automake, libtool が必要です。 C++ も入ってなかったら用意しておきましょう。

## libuv

h2o のスタンドアロン版では libuv 1.0.x への依存が optional なのですが、 libh2o では必須になっているようです（少なくとも僕は libuv 無しでのビルドには失敗しました）。まずは libuv をセットアップしましょう。

libuv の 1.0 系は最近出たばかりなので、ソースからビルドしていきます。 [libuv のサイト](http://libuv.org/) はとてもシンプルで、すぐにダウンロードリンクが見つかるはずです。

以下の手順では、 preifx=`$HOME/local/stow/libuv-1.0.x` にインストールしつつ、 stow で `$HOME/local` 配下に symlink を貼ります。

このへんは好みで直接共通の prefix 配下にインストールするなり、 paco で uninstall 可能にするなり、個別の prefix にインストールして各種PATHを1つ1つ設定するなりしてください。

```
$ wget http://libuv.org/dist/v1.0.1/libuv-v1.0.1.tar.gz
$ tar xf libuv-v1.0.1.tar.gz
$ cd libuv-v1.0.1/
$ ./autogen.sh
$ ./configure --prefix=$HOME/local/stow/libuv-1.0.1
$ make -j4
$ make install
$ cd ~/local/stow
$ stow libuv-1.0.1/
$ ls ../lib
libuv.1.dylib libuv.a       libuv.dylib   libuv.la      pkgconfig
```

## libh2o のビルド

libuv を cmake に見つけさせるためと、 libuv の動的ライブラリをリンクするための環境変数を設定しておきます。

```
$ export CMAKE_INCLUDE_PATH=$HOME/local/include
$ export CMAKE_LIBRARY_PATH=$HOME/local/lib
$ export LD_LIBRARY_PATH=$HOME/local/lib
```

libh2o をチェックアウトします。

```
$ git clone git@github.com:h2o/h2o.git
$ cd h2o
$ git submodule init
Submodule 'deps/klib' (https://github.com/attractivechaos/klib.git) registered for path 'deps/klib'
Submodule 'deps/picohttpparser' (https://github.com/h2o/picohttpparser.git) registered for path 'deps/picohttpparser'
Submodule 'deps/picotest' (https://github.com/h2o/picotest.git) registered for path 'deps/picotest'
Submodule 'deps/yoml' (https://github.com/h2o/yoml.git) registered for path 'deps/yoml'
$ git submodule update
```

ビルド用のディレクトリを作ってそこでビルドします。ディレクトリを作るのは必須ではないですが、 CLion (JetBrains の新しい C/C++ 用IDE) を使うときに無いと警告されますし、実際 cmake が1発で通らなかった時にビルドディレクトリを消すだけでリセットできるのは便利です。

```
$ mkdir build
$ cd build
$ cmake ..
$ make libh2o
$ ls
CMakeCache.txt      CMakeFiles          Makefile            cmake_install.cmake libh2o.a
$ install libh2o.a ~/local/lib
```

## hello world

さて、 libh2o を使ってみましょう。 examples/libh2o ディレクトリの中に simple.c というファイルがあるので、 cp simple.c hello.c して、 hello world を書きます。
改造したソースコードは [gist](https://gist.github.com/methane/2e35cf585a939c1dfa3e) に置きました。

hello world のハンドラになっている関数だけ張っておきます。

```c
static int hello(h2o_handler_t *self, h2o_req_t *req)
{
    static h2o_generator_t generator = { NULL, NULL };
    static h2o_iovec_t body = {H2O_STRLIT("Hello, World!\n")};
    req->res.status = 200;
    req->res.reason = "OK";
    req->res.content_length = body.len;
    h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, H2O_STRLIT("text/plain; charset=utf-8"));
    h2o_start_response(req, &generator);
    h2o_send(req, &body, 1, 1);
    return 0;
}
```

h2o_start_response はまだ何をしているのか把握してなくて、コピペのままです。

h2o_send の第二引数は h2o_iovec_t の配列ですが、これは `char*` と `size_t` の構造体になっていて、文字列リテラルから作る場合は `H2O_STRLIT` マクロが便利です。
第三引数は第二引数の配列の長さ、第四引数は最後の h2o_send かどうか、です。

最初に試した時は transfer-encoding: chunked だったので、 `req->res` に当たりをつけて Clion で . をタイプしたらすぐに content_length が補完候補に見つかったので、 body.len を突っ込んでシンプルなレスポンスにします。

これをビルドしてみます。いいビルド方法が見つからなかったのでCコンパイラを直接叩いています。 Mac でビルドすると勝手にシステムの openssl を見つけられたので `-lssl -lcrypto` をつけていますが、 Ubuntu などで openssl 無しでビルドする場合は外してください。

```
$ cc -O2 -I ../../include -I ../../deps/picohttpparser  -I ../../deps/yoml  -I $HOME/local/include -L $HOME/local/lib hello.c -lh2o -luv -lcrypto -lssl -o hello
```

起動してみましょう。

```
$ ./hello
```

別セッションから叩いてみます。

```
$ curl -vv http://localhost:7890/
* Adding handle: conn: 0x7fc0b9004000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7fc0b9004000) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 7890 (#0)
*   Trying ::1...
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 7890 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:7890
> Accept: */*
>
< HTTP/1.1 200 OK
< date: Mon, 01 Dec 2014 15:49:34 GMT
* Server h2o/0.1 is not blacklisted
< server: h2o/0.1
< connection: keep-alive
< content-length: 14
< content-type: text/plain; charset=utf-8
<
Hello, World!
* Connection #0 to host localhost left intact

$ wrk http://localhost:7890/
Running 10s test @ http://localhost:7890/
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   206.67us  206.17us   6.16ms   95.23%
    Req/Sec    24.35k     5.45k   30.78k    78.49%
  461496 requests in 10.00s, 75.70MB read
Requests/sec:  46153.12
Transfer/sec:      7.57MB
```

どうやらちゃんと動いているようです。