- 更新
2014-04-10
- バージョン
0.2.1
- 作者
@voluntas
- URL
reltool 周りについて勉強がてらまとめてみました
- バージョン
17.0
./configure --prefix=/opt/erlang/17.0 --enable-smp-support --enable-darwin-64bit --enable-vm-probes --enable-kernel-poll --enable-hipe --with-dynamic-trace=dtrace --without-javac --enable-dirty-schedulers --disable-native-libs --disable-sctp
GitHub からどうぞ
$ ./rebar --version
rebar 2.2.0 17 20140409_170003 git 2.2.0-47-g0c7fe5f
まずはアプリを作ります
$ ./rebar create-app appid=snowflake
次に rebar.config を作ります。
以下の設定は自分がよく使う設定です。
rebar.config:
$ vim rebar.config
{require_otp_vsn, "17"}.
{erl_opts, [warnings_as_errors,
warn_export_all,
warn_unused_import,
warn_untyped_record]}.
{xref_checks, [fail_on_warning, undefined_function_calls]}.
{clean_files, [".test/*.beam", ".eunit/*", "ebin/*.beam"]}.
{cover_enabled, true}.
{validate_app_modules, true}.
{sub_dirs, ["rel"]}.
ポイントは sub_dirs です。"rel" を登録しましょう。
rel/の中身を生成して reltool.config を設定します。
変更する前の部分をコメントで書いてあります
reltool.config:
$ cd rel
$ ../rebar create-node nodeid=snowflake
$ vim reltool.config
{sys, [
%% 変更前 {lib_dirs, []},
{lib_dirs, ["../deps"]},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "snowflake", "1",
[
kernel,
stdlib,
sasl,
snowflake
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "snowflake"},
{profile, embedded},
{incl_cond, derived},
{mod_cond, derived},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, hipe, [{incl_cond, exclude}]},
%% 変更前 {app, snowflake, [{mod_cond, app}, {incl_cond, include}]}
{app, snowflake, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}
]}.
{target_dir, "snowflake"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/snowflake", "bin/snowflake"},
{copy, "files/snowflake.cmd", "bin/snowflake.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.
コンパイル時に hipe を無効にしている場合でも reltool では hipe を要求してきます。 この辺は根が深い問題らしいので、そっと「あぁそうなんだ」で許してください。
そのため以下の内容を追加する必要があります。
{app, hipe, [{incl_cond, exclude}]}
rebar generate を打てば生成されます
$ cd rel
$ ../rebar generate
ポイントは rel の中から rebar generate を実行することです
rel の下に snowflake というディレクトリが出来ているはずです。さっそく実行してみましょう。
$ ./rel/snowflake/bin/snowflake console
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Eshell V6.0 (abort with ^G)
(snowflake@127.0.0.1)1>
起動しました。start で起動すればデーモンとして上がりますし、stop すれば終了します。
リリースしたのはいいのですが、このままでは ebin や deps に変更をするたび ./rebar generate する必要があります。そんな面倒なことは嫌なので、色々置き換える事で効率よく開発出来るようにします。
やることはシンプルで rel のライブラリを全てシンボリックリンクで開発の deps, priv, ebin に置き換えてしまう仕組みです。
ただし、少し問題がありまして、rebar の create-node で作ったファイルそのままでは動かない事がわかっています。
これは -mode emmbedded で動かした場合はライブラリは全てバージョンが指定されている必要があります。今回の方法ではメインの snowflake のバージョンを指定していないため、このままでは動きません。
そのため files/snowflake に少しだけ手を入れる必要があります。手を入れるのは以下の一行から -mode embedded を削除してください
-mode embedded 削除前:
$ vim rel/files/snowflake
CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH"
-mode embedded 削除後:
$ vim rel/files/snowflake
CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH"
後は、deps や ebin 、さらに priv を書き換える仕組みを Makefile に追加します
Makefile 一部抜粋:
devrel: rel
$(foreach dep,$(wildcard deps/*), rm -rf dev/$(APP_NAME)/lib/$(shell basename $(dep))-* && ln -sf $(abspath $(dep)) dev/$(APP_NAME)/lib;)
rm -rf dev/$(APP_NAME)/lib/$(APP_NAME)-*
rm -rf dev/$(APP_NAME)/lib/$(APP_NAME)
mkdir dev/$(APP_NAME)/lib/$(APP_NAME)
ln -sf $(abspath ebin) dev/$(APP_NAME)/lib/$(APP_NAME)/ebin
ln -sf $(abspath priv) dev/$(APP_NAME)/lib/$(APP_NAME)/priv
rel: compile
mkdir -p dev
mkdir -p deps
(cd rel && rm -rf ../dev/$(APP_NAME) && ../rebar generate && ../rebar generate target_dir=../dev/$(APP_NAME))
rel は ./rebar generate する際に dev というフォルダ以下に出力するのを明示的にしています。
devrel は deps と ebn と priv をシンボリックリンクで書き換えています。こうすることで毎回リリースする事無く、コードを書いてコンパイルするだけで反映されるようになります。
mochiweb の reloader を上手く使うと、コンパイルすると自動で反映してくれるという仕組みが使えます。また watchdog あたりを使って変更を見てコンパイルする仕組みを入れることでさらに効率が上がります。
rebar.config の deps に reloader を追加します。
rebar.config:
%% debug
{reloader,
".*", {git, "git@github.com:oinksoft/reloader.git", {branch, "master"}}}
さらに rel/files/vm.args の中に -s reloader を追加します。
vm.args:
## Name of the node
-name <nodename>@127.0.0.1
## reloader を読み込むようにする
-s reloader
## Cookie for distributed erlang
-setcookie spam
## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive
## (Disabled by default..use with caution!)
##-heart
## Enable kernel poll and a few async threads
##+K true
##+A 5
## Increase number of concurrent ports/sockets
##-env ERL_MAX_PORTS 4096
## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10
開発者リリースをさらに効率化させます。通常リリース、開発者リリースまでは Erlang/OTP を含んでいましたが、これすらも省略する事が出来ます。
ポイントは R15B02 から reltool に導入された {excl_lib, otp_root} を使います。
reltool.config に {excl_lib, otp_root} を追加してください。それ以外の変更は不要です。
reltool.config:
$ cd rel
$ ../rebar create-node nodeid=snowflake
$ vim reltool.config
{sys, [
{lib_dirs, ["../deps"]},
%% この一行を追加する
{excl_lib, otp_root},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "snowflake", "1",
[
kernel,
stdlib,
sasl,
snowflake
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "snowflake"},
{profile, embedded},
{incl_cond, derived},
{mod_cond, derived},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, hipe, [{incl_cond, exclude}]},
{app, snowflake, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}
]}.
{target_dir, "snowflake"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/snowflake", "bin/snowflake"},
{copy, "files/snowflake.cmd", "bin/snowflake.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.
スリムリリースでは起動スクリプトを変更する必要があります。
erl -boot_var RELTOOL_EXT_LIB $RUNNER_BASE_DIR/lib -boot \
$RUNNER_BASE_DIR/releases/1/<nodeid> -sasl releases_dir \
\"$RUNNER_BASE_DIR/releases\"
つづく ...
以下は参考までに良く自分がベースにする Makefile です
.PHONY: all compile deps clean test devrel rel
REBAR_CONFIG = rebar.config
APP_NAME = snowflake
all: clean deps test
deps: get-deps update-deps
@./rebar -C $(REBAR_CONFIG) compile
update-deps:
@./rebar -C $(REBAR_CONFIG) update-deps
get-deps:
@./rebar -C $(REBAR_CONFIG) get-deps
compile:
@./rebar -C $(REBAR_CONFIG) compile skip_deps=true
@./rebar -C $(REBAR_CONFIG) xref skip_deps=true
devrel: rel
$(foreach dep,$(wildcard deps/*), rm -rf dev/$(APP_NAME)/lib/$(shell basename $(dep))-* && ln -sf $(abspath $(dep)) dev/$(APP_NAME)/lib;)
rm -rf dev/$(APP_NAME)/lib/$(APP_NAME)-*
rm -rf dev/$(APP_NAME)/lib/$(APP_NAME)
mkdir dev/$(APP_NAME)/lib/$(APP_NAME)
ln -sf $(abspath ebin) dev/$(APP_NAME)/lib/$(APP_NAME)/ebin
ln -sf $(abspath priv) dev/$(APP_NAME)/lib/$(APP_NAME)/priv
rel: compile
mkdir -p dev
mkdir -p deps
(cd rel && rm -rf ../dev/$(APP_NAME) && ../rebar generate target_dir=../dev/$(APP_NAME))
test:
rm -rf .eunit
@./rebar -C $(REBAR_CONFIG) eunit skip_deps=true
clean:
@./rebar -C $(REBAR_CONFIG) clean skip_deps=true
distclean: clean
@./rebar -C $(REBAR_CONFIG) clean
@./rebar -C $(REBAR_CONFIG) delete-deps
rm -rf dev
dialyze-init:
dialyzer --build_plt --apps erts kernel stdlib mnesia crypto public_key snmp reltool
dialyzer --add_to_plt --plt ~/.dialyzer_plt --output_plt $(APP_NAME).plt -c .
dialyzer -c ebin -Wunmatched_returns -Werror_handling -Wrace_conditions -Wunderspecs
dialyze: compile
dialyzer --check_plt --plt $(APP_NAME).plt -c .
dialyzer -c ebin
この記事を書くに当たって @shino (@itawasa) に色々教えていただきました。 おそらく日本で一番 rebar と reltool 周りに詳しいと思います。本当にありがとうございます。
- rebar generateでErlangアプリをパッケージ化したときのメモ - ごろねこ日記
- Change to slim release · 95ec813 · shino/slim_sample
https://github.com/shino/slim_sample/commit/95ec813b74360e19b522c806292cdd582a2d5c46
- rebar/priv/templates/simplenode.runner at slim · tuncer/rebar
https://github.com/tuncer/rebar/blob/slim/priv/templates/simplenode.runner
- Comparing aa0b0b44a5...0426492c5a · voluntas/snowflake
https://github.com/voluntas/snowflake/compare/aa0b0b44a5...0426492c5a
- Add slim release support · Issue #7 · rebar/rebar