rebar 是一个遵循 Erlang/OTP 原则的 Erlang 项目构建工具,使用它能够减小构建标准 Erlang/OTP 项目架构配置的工做量,而且能够很容易的编译、测试、发布 Erlang 应用程序。更强大的是,rebar 提供一种依赖管理机制,它可使开发者很方便地经过 Git、Hg 等方式重用常见的第三方 Erlang 模块或库。html
安装 rebarnode
你能够从 https://github.com/rebar/rebar/wiki/rebar 下载编译好的版本,也能够本身下载 rebar 的源代码,本身编译一个:git
1github 2shell 3bootstrap |
git clone git://github.com/rebar/rebar.gitbash cdrebar架构 ./bootstrapapp |
上面编译好以后,在当前目录下就会生成一个名为 "rebar" 独立的 erlang 脚本(escript),把它放在你想建立标准 Erlang/OTP 项目的目录路径下便可使用,或者把 rebar 放在系统目录的 Path 下,方便在终端使用:框架
1 |
sudomvrebar /usr/local/bin |
在终端输入 "rebar -c" 将列出全部可执行的 rebar 命令。或者输入 "rebar -h" 查看更多的 rebar 参数信息。
用 rebar 构建项目
建立一个名为 rebarapp 的文件夹
1 2 |
mkdirrebarapp cdrebarapp |
建立名为 rebarapp 项目:
1 |
rebar create-app appid=rebarapp |
rebar 会根据默认模板(template)在当前目录下生成一个 src 文件夹,里面包含下面3个文件:
rebarapp.app.src 应用的资源描述文件,影响后面编译生成的 rebarapp.app 里的内容
rebarapp_app.erl 应用的 Application Behaviour 代码文件
rebarapp_sup.erl 应用的 Supervisor Behaviour 代码文件
rebar 还内置了 gen_server、gen_fsm、application 等 Erlang/OTP 行为模式的模板,能够自动生成这些行为模式的框架代码。这里以 gen_server 为例,给应用添加一个名为 rebarapp_server 的 gen_server 行为模式。在应用根目录执行如下命令:
1 |
rebar create template=simplesrv srvid=rebarapp_server |
执行完后自动会在 src 文件夹里生成一个 rebarapp_server.erl 的 gen_server 框架格式的文件,simplesrv 是 gen_server 模板的名称(gen_fsm、application对应的是simplefsm、simpleapp),srvid 则是该 gen_server 模板的ID(gen_fsm、application对应的是fsmid、appid)。
为了测试,这里对 rebarapp_server.erl 进行修改,export 一个 hello 方法,并添加一个 cast 的消息输出,修改后的 rebarapp_server.erl 文件内容以下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
-module(rebarapp_server). -behaviour(gen_server). -define(SERVER, ?MODULE).
%% ------------------------------------------------------------------ %% API Function Exports %% ------------------------------------------------------------------
-export([start_link/0, hello/0]).
%% ------------------------------------------------------------------ %% gen_server Function Exports %% ------------------------------------------------------------------
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%% ------------------------------------------------------------------ %% API Function Definitions %% ------------------------------------------------------------------
start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%% @doc just a test hello() -> gen_server:cast(?SERVER, 'HELLO').
%% ------------------------------------------------------------------ %% gen_server Function Definitions %% ------------------------------------------------------------------
init(Args) -> {ok, Args}.
handle_call(_Request, _From, State) -> {reply, ok, State}.
handle_cast('HELLO', State) -> io:format("Hello World!~n"), {noreply, State};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
%% ------------------------------------------------------------------ %% Internal Function Definitions %% ------------------------------------------------------------------ |
修改 rebarapp_sup.erl 的 init 函数,把 rebarapp_server 做为应用管理者 rebarapp_sup 的工做进程启动,修改以下:
1 2 3 |
init([]) -> RebarappServer= ?CHILD(rebarapp_server, worker), {ok, { {one_for_one, 5, 10}, [RebarappServer]} }. |
编译应用
1 |
rebar compile |
编译完后,会在根目录下生成一个 ebin 的文件夹,里面存放的是该应用的资源文件 rebarapp.app 和应用的 beam 文件,也能够执行如下命令对编译生成的应用文件进行清理:
1 |
rebar clean |
使用 Edoc 生成应用文档
1 |
rebar doc |
命令执行完后,会在根目录生成一个 doc 的文件夹,打开里面的 index.html 就能够很直观地看到该应用的模块 API 概览。
eunit 测试
rebar 会根据一个名为 rebar.config 的文件里的 eunit 配置选项来对应用进行测试,rebar.config 详细地配置选项信息能够查看官方上的 rebar.config.sample。在应用的根目录下建立一个 rebar.config,填入如下内容:
1 2 3 4 5 6 7 8 9 10 |
%%-*- mode: erlang -*-
%% Erlang compiler options {erl_opts, [debug_info, {i, "test"}, {src_dirs, ["src"]}]}.
{eunit_opts, [verbose, {report, {eunit_surefire, [{dir, "."}]}}]}.
{cover_enabled, true}. |
上面的配置将会加载根目录下的 test 文件夹里的文件,因此须要在根目录下建立一个 test 文件夹:
1 |
mkdir-p test |
这里 test 文件夹将存放 eunit 的测试用例,在 test 文件夹里新建一个名为 rebarapp_test.hrl 的测试用例文件,内容以下:
1 2 3 4 5 6 7 8 9 |
-include_lib("eunit/include/eunit.hrl").
my_test() -> ?assert(1 + 2 =:= 3).
simple_test() -> ok = application:start(rebarapp), ?assertNot(undefined =:= whereis(rebarapp_sup)). |
而后在 rebarapp_server.erl 的文件末尾加上如下测试代码:
1 2 3 |
-ifdef(TEST). -include("rebarapp_test.hrl"). -endif. |
固然,若是有必要的话也能够在每一个模块文件上加上面测试代码。执行如下命令进行 eunit 测试:
1 |
rebar compile eunit |
若是应用文件没什么变化修改,也能够直接运行 "rebar eunit"。这时终端出现如下相似显示,则 eunit 测试完成:
1 2 3 4 5 6 7 8 9 10 11 |
==> rebarapp (eunit) ======================== EUnit ======================== module 'rebarapp_app' module 'rebarapp_server' rebarapp_server: my_test...ok rebarapp_server: simple_test...[0.014 s] ok [done in 0.019 s] module 'rebarapp_sup' ======================================================= All 2 tests passed. Cover analysis: /Users/dengjoe/erlang/rebarapp/.eunit/index.html |
能够打开根目录下的.eunit/index.html 查看测试报告。
发布应用
在应用根目录下建立一个名为 rel 的文件夹,用来做为应用发布的文件夹:
1 2 |
mkdir-p rel cdrel |
在当前 rel 文件夹里建立一个名为 rebarapp 的独立的 Erlang VM 节点:
1 |
rebar create-node nodeid=rebarapp |
修改 rel/reltool.config 里的 lib_dirs 的值,默认是一个空列表 "[]",改成应用所在的目录路径 '["../../"]',否则到后面编译发布时会报 "Missing application directory" 的错误出来,修改后的 reltool.config 配置内容以下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
{sys, [ {lib_dirs, ["../../"]}, {erts, [{mod_cond, derived}, {app_file, strip}]}, {app_file, strip}, {rel, "rebarapp", "1", [ kernel, stdlib, sasl, rebarapp ]}, {rel, "start_clean", "", [ kernel, stdlib ]}, {boot_rel, "rebarapp"}, {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, rebarapp, [{mod_cond, app}, {incl_cond, include}]} ]}.
{target_dir, "rebarapp"}.
{overlay, [ {mkdir, "log/sasl"}, {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, {copy, "files/rebarapp", "bin/rebarapp"}, {copy, "files/rebarapp.cmd", "bin/rebarapp.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"} ]}. |
返回应用的根目录,在 rebar.config 加上如下一行,把新建的 rel 文件夹放入到 rebar 可访问的子文件夹里,做为应用内容发布文件夹:
1 |
{sub_dirs, ["rel"]}. |
再从新编译下应用 rebarapp
1 |
rebar compile |
若是报什么错,应用 rebarapp 就能够发布了:
1 |
rebar generate |
在终端上看到 "==> rel (generate)" 且没报什么错,应用 rebarapp 发布成功,并在 rel/rebarapp/bin 目录下生成一个用来启动应用或中止应用等操控动做的 shell 文件 rebarapp。
操控文件 rel/rebarapp/bin/rebarapp 用法:
1 |
rebarapp {start|start_boot |foreground|stop|restart|reboot|ping|console|console_clean|console_boot |attach|remote_console|upgrade} |
例如:
启动应用 rebarapp
1 |
rel/rebarapp/bin/rebarapp start |
中止应用 rebarapp
1 |
rel/rebarapp/bin/rebarapp stop |
或者启动应用 rebarapp 后返回一个 erlang shell 的控制台
1 |
rel/rebarapp/bin/rebarapp console |
OK,在 erlang shell 的控制台上调用 rebarapp_server:hello() 输出一个 "Hello World!" 吧。