既存のnginxモジュールを動的モジュール化するための手順

nginx-1.9.11から動的モジュールの仕組みが導入されたので、自分がメンテしている[ngx_small_light](https://github.com/cubicdaiya/ngx_small_light)や[ngx_dynamic_upstream](https://github.com/cubicdaiya/ngx_dynamic_upstream)でも動的ローディングに対応してみた。手順は公式のWiki(↓)に綺麗にまとまっており、すんなり対応することができた。

[Converting Static Modules to Dynamic Modules](https://www.nginx.com/resources/wiki/extending/converting/)

実際に、「Hello, World!」を返すだけの簡単なnginxモジュールを動的モジュール化する手順について紹介してみる。

# ngx_http_hello_worldモジュールを動的ロードに対応する

https://github.com/cubicdaiya/ngx_http_hello_world

ngx_http_hello_worldは単に「Hello, World!」を返すだけのモジュールである。例えば、以下のnginx.confのlocationにアクセスすると「Hello, World!」が返ってくる。

```nginx
location / {
    hello_world;
}
```

ファイル構成は単純でCのソースファイルが1つとnginxモジュールとしての設定が書かれた`config`ファイルとテストコード、あとREADMEやライセンスのファイルから成る。

```
ngx_http_hello_world
├── COPYING
├── README.md
├── config
├── ngx_http_hello_world_module.c
└── t
    └── 00-hello.t

1 directory, 5 files
```

このモジュールを`load_module`を使って動的にロードできるようにするための差分が[こちら](https://github.com/cubicdaiya/ngx_http_hello_world/commit/5af9b2c8035ebcb4f7662d1e0c94e5349da8a47d)。変更するのは`config`ファイルのみでCのソースコードを修正する必要はない。

```diff
commit 5af9b2c8035ebcb4f7662d1e0c94e5349da8a47d
Author: Tatsuhiko Kubo <cubicdaiya@gmail.com>
Date:   Thu Feb 11 17:00:16 2016 +0900

    supported dynamic loading.

diff --git a/config b/config
index 9e6e5f6..eaea92e 100644
--- a/config
+++ b/config
@@ -1,3 +1,14 @@
 ngx_addon_name=ngx_http_hello_world_module
-HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
+
+if test -n "$ngx_module_link"; then
+    ngx_module_type=HTTP
+    ngx_module_name=$ngx_addon_name
+    ngx_module_incs=
+    ngx_module_deps=
+    ngx_module_srcs="$ngx_addon_dir/ngx_http_hello_world_module.c"
+    ngx_module_libs=
+   . auto/module
+else
+    HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
+    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
+fi
```

順を追って説明すると、元々の`config`ファイルはこうなっていた。

```sh
ngx_addon_name=ngx_http_hello_world_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
```

そして以下が変更後。

```sh
ngx_addon_name=ngx_http_hello_world_module

if test -n "$ngx_module_link"; then
    ngx_module_type=HTTP
    ngx_module_name=$ngx_addon_name
    ngx_module_incs=
    ngx_module_deps=
    ngx_module_srcs="$ngx_addon_dir/ngx_http_hello_world_module.c"
    ngx_module_libs=
   . auto/module
else
    HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
fi
```

動的ローディングが可能かどうかは`$ngx_module_link`変数の有無によって決定される。なければ従来のnginxモジュールと同じように処理されるので、バージョンの古いnginxとの互換性は担保されるし、今まで通り静的なモジュールとして扱うこともできる。

なので従来通り静的なモジュールとして扱うのであれば`--add-module=PATH`を、

```sh
wget http://nginx.org/download/nginx-1.9.11.tar.gz
tar zxvf nginx-1.9.11.tar.gz
./configure \
 --add-module=/path/to/ngx_http_hello_world
make
sudo make install
```

動的にロードしたければ`--add-dynamic-module=PATH`を利用する、といった具合に使い分けることができる。

```sh
wget http://nginx.org/download/nginx-1.9.11.tar.gz
tar zxvf nginx-1.9.11.tar.gz
./configure \
 --add-dynamic-module=/path/to/ngx_http_hello_world
make
sudo make install
```

動的にロードするには[`load_module`](http://nginx.org/en/docs/ngx_core_module.html#load_module)を利用する。

```nginx
# nginx.conf
load_module /path/to/ngx_http_hello_world_module.so;
```