Rerbar is an Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. Its a self-contained binary.
Using rebar
Either install from distribution repo (if available), use prebuild binary, or compile from the source.
# requirements, see http://www.erlang.org/doc/installation_guide/INSTALL.html
$ sudo apt-get install erlang
# either from repo (not recomended, too old)
$ sudo apt-get install rebar
# or compile from source
...
# or pre-build binary (recomended)
$ wget https://github.com/rebar/rebar/wiki/rebar ; chmod +x rebar
from rebar@github
Use a template to create new application that follows OTP Design Principles.
$ mkdir rebar-helloworld ; cd rebar-helloworld
$ ../rebar create-app appid=app1
==> app1 (create-app)
Writing src/app1.app.src # Application descriptor
Writing src/app1_app.erl # Application callback module
Writing src/app1_sup.erl # Supervisor callback module
Next add a generic server to the application. A gen_server is the server implementation of a client-server. You have to fill in the pre-defined set of function in a callback module.
# either create file
$ cat src/app1_srv.erl
-module(app1_server).
-behaviour(gen_server).
-export([start_link/0, say_hello/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
{ok, []}.
say_hello() ->
gen_server:call(?MODULE, hello).
%% callbacks
handle_call(hello, _From, State) ->
io:format("Hello from server!~n", []),
{reply, ok, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
# or use template
$ rebar create template=simplesrv srvid=app1_srv
==> app1 (create)
Writing src/app1_srv.erl
# and add say_hello/0 function
-export([start_link/0, say_hello/0, stop/0]).
%% API Function Definitions
say_hello() ->
gen_server:call(?MODULE, hello).
stop() ->
gen_server:cast(?MODULE, stop).
%% callbacks (gen_server Function Definitions)
handle_call(hello, _From, State) ->
io:format("Hello from srv!~n", []),
{reply, ok, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast(stop, State) ->
{stop, normal, State};
We could compile now, but lets create another application lib1 and compile both.
# move both apps to '/apps'
$ mkdir -p apps/{app1,lib1}
$ mv src apps/app1/
$ cd apps/lib1
$ rebar create-app appid=lib1
$ cat src/hello.erl
-module(hello).
-export([hello/0]).
hello() ->
io:format("Hello for lib!", []).
# compile both
$ cd ../..
$ cat rebar.config
{sub_dirs, ["apps/app1", "apps/lib1"] }.
$ tree
.
├── apps
│ ├── app1
│ │ └── src
│ │ ├── app1_app.erl
│ │ ├── app1.app.src
│ │ ├── app1_srv.erl
│ │ └── app1_sup.erl
│ └── lib1
│ └── src
│ ├── hello.erl
│ ├── lib1_app.erl
│ ├── lib1.app.src
│ └── lib1_sup.erl
└── rebar.config
$ rebar compile
==> app1 (compile)
==> src (compile)
==> lib1 (compile)
Compiled src/hello.erl
==> src (compile)
==> app1 (compile)
# test (in development)
$ erl -pa apps/*/ebin
1> app1_srv:start_link().
{ok,}
2> app1_srv:say_hello().
Hello from server!
3> app1_srv:stop().
ok
4> hello:hello().
Hello from lib!
ok
How can I call a library function from lib1 in a app1 ?
$ cat apps/app1/src/app1_srv.erl
...
%% callbacks
handle_call(hello, _From, State) ->
hello:hello(),
io:format("~nHello from srv!~n", []),
{reply, ok, State}.
$ cat apps/app1/src/app1_sup.erl
...
init([]) ->
{ok, {{one_for_one, 1, 60}, [?CHILD(app1_srv, worker)]}}.
# recompile and test
$ rebar clean compile
$ erl -pa apps/*/ebin
1> app1_sup:start_link().
{ok,}
2> app1_srv:say_hello().
Hello for lib!Hello from server!
ok
To make the application work like a service (start, stop, console, …), create release. Its a complete system consisting of these applications and a subset of the Erlang/OTP applications. Including a way to make application work like a service (start, stop, console, …).
$ mkdir rel; cd rel
$ rebar create-node nodeid=app1
==> rel (create-node)
Writing reltool.config
Writing files/erl
Writing files/nodetool
Writing files/app1
Writing files/sys.config
Writing files/vm.args
Writing files/app1.cmd
Writing files/start_erl.cmd
Writing files/install_upgrade.escript
$ cd -
$ cat rel/reltool.config
{lib_dirs, ["../apps"]},
$ cat rebar.config
{sub_dirs, ["apps/app1", "apps/lib1", "rel"] }.
# compile and generate release
$ rebar clean compile generate
# if "ERROR: Unable to generate spec: read file info /usr/lib/erlang/man/man1/XPTO.gz" failed then "sudo rm /usr/lib/erlang/man/man1/XPTO.gz"
# ignore "WARN: 'generate' command does not apply to directory", see https://github.com/rebar/rebar/issues/253
$ ls rel/app1
bin erts-6.1 etc lib log releases
# test using console
$ ./rel/app1/bin/app1 console
# if "...'cannot load',elf_format,get_files}}" then add to 'reltool.config'
{app, hipe, [{incl_cond, exclude}]},
mysample@127.0.0.1)1> application:which_applications().
[{app1,[],"1"},
{sasl,"SASL CXC 138 11","2.4"},
{stdlib,"ERTS CXC 138 10","2.1"},
{kernel,"ERTS CXC 138 10","3.0.1"}]
(mysample@127.0.0.1)2> app1_srv:say_hello().
Hello for lib!Hello from server!
ok
# start and attach to get console
$ ./rel/app1/bin/app1 start ; ./rel/app1/bin/app1 attach
# deploy/export
$ tar -C rel -czvf app1.tar.gz app1
from release-handling@github
Rebar makes building Erlang releases easy. One of the advantages of using OTP releases is the ability to perform hot-code upgrades. To do this you need to build a upgrade package that contains the built modules and instructions telling OTP how to upgrade your application.
# generate first release
$ rebar clean compile generate
$ mv rel/app1 rel/app1_1.0
# change 'hello' function
$ cat apps/app1/src/app1_srv.erl
handle_call(hello, _From, State) ->
hello:hello(),
{_,{Hour,Min,Sec}} = erlang:localtime(),
io:format("Hello from server at ~2w:~2..0w:~2..0w!~n", [Hour,Min,Sec]),
{reply, ok, State};
# bump version and generate new release
$ cat rel/reltool.config
{rel, "app1", "2",
$ cat ../apps/app1/src/app1.app.src
{vsn, "2"},
$ rebar clean compile generate
$ tree rel -d -L 2
rel
├── app1
│ ├── bin
│ ├── erts-6.1
│ ├── lib
│ ├── log
│ └── releases
│ └── 1
├── app1_1.0
│ ├── bin
│ ├── erts-6.1
│ ├── lib
│ ├── log
│ └── releases
│ └── 2
└── files
In order to make an upgrade, you must have a valid .appup file. This tells the erlang release_handler how to upgrade and downgrade between specific versions of your application.
# generate '.appup' upgrade instructions
$ cd rel ; rebar generate-appups previous_release=app1_1.0
==> rel (generate-appups)
Generated appup for app1
Appup generation complete
# see './app1/lib/app1-2/ebin/app1.appup'
% appup generated for app1 by rebar ("2015/01/23 16:03:24")
{"2", [{"1", [{update,app1_srv,{advanced,[]},[]}]}], [{"1", []}]}.
# now create the upgrade package
$ cd rel ; rebar generate-upgrade previous_release=app1_1.0
==> rel (generate-upgrade)
app1_2 upgrade package created
$ ls rel
app1 app1_1.0 app1_2.tar.gz files reltool.config
# install upgrade using 'release_handler'
$ mv rel/app1_2.tar.gz rel/app1_1.0/releases
$ ./rel/app1_1.0/bin/app1 console
1> release_handler:which_releases().
[{"app1","1",[],permanent}]
2> release_handler:unpack_release("app1_2").
{ok,"2"}
3> release_handler:install_release("2").
{ok,"1",[]}
4> release_handler:make_permanent("2").
ok
5> app1_srv:say_hello().
Hello for lib!Hello from server at 16:15:24!
ok
6> release_handler:which_releases().
[{"app1","2",[],permanent},{"app1","1",[],old}]
# generating a v3
$ mv rel/app1 rel/app1_2.0
# make code change ... and compile/generate upgrade package
$ rebar clean compile generate
$ cd rel ; generate-appups previous_release=app1_2.0
$ rebar generate-upgrade previous_release=app1_2.0
$ ls
app1 app1_1.0 app1_2.0 app1_3.tar.gz files reltool.config
from upgrades@github and rebar tutorial.
Rebar can fetch and build projects including source code from external sources (git, hg, etc.). See erlang-libs.
$ cat rebar.config
deps, [
{'erlcloud', ".*", { git, "https://github.com/gleber/erlcloud.git"}},
{'lager', ".*", { git, "git://github.com/basho/lager.git"} }
]}.
$ rebar update-deps
$ cat src/app1.app.src
{applications, [
..., erlcloud, lager
]},
from [https://github.com/rebar/rebar/wiki/Dependency-management](dependency management)
All code is available in erlang-otp-helloworld@github.
Using rebar3
Rebar3 is an experimental branch that tries to solve some issues, see annoucement.
$ wget https://s3.amazonaws.com/rebar3/rebar3 ; chmod +x rebar3
It comes with templates for creating applications, library applications (with no start/2), releases and plugins. Use the new command to create a project with from a template. It accepts lib, app, release and plugin as the first argument and the name for each as the second argument.
# create new application and release
$ rebar3 new release app1
===> Writing app1/apps/app1/src/app1_app.erl
===> Writing app1/apps/app1/src/app1_sup.erl
===> Writing app1/apps/app1/src/app1.app.src
===> Writing app1/rebar.config
===> Writing app1/config/sys.config
===> Writing app1/config/vm.args
===> Writing app1/.gitignore
===> Writing app1/LICENSE
===> Writing app1/README.md
# optionally add dependencies
$ cat rebar.config
{deps, [{cowboy, {git, "git://github.com/ninenines/cowboy.git", {tag, "1.0.1"}}}]}.
# add host to nodename otherwise you get "Can't set long node name" when starting console
$ cat config/vm.args
-name app1@127.0.0.1
# and release (uses relx instead of reltool)
$ rebar3 release
===> Resolved app1-0.1.0
===> Dev mode enabled, release will be symlinked
===> release successfully created!
# if "Missing beam file elf_format ... elf_format.beam" then 'sudo apt-get install erlang-base-hipe'
# test using console
$ ./_build/rel/app1/bin/app1-0.1.0 console
1> app1_srv:say_hello().
Hello from server!
ok
# deploy/export
$ REBAR_PROFILE=prod rebar3 tar
===> tarball .../_build/rel/app1/app1-0.1.0.tar.gz successfully created!
# upgrading
$ cat apps/app1/src/app1.app.src
,{vsn, "0.2.0"}
$ cat rebar.config
{relx, [{release, {'app1', "0.2.0"},
$ cat apps/app1/src/app1_srv.erl
io:format("Hello from server v2!~n"),
$ mv _build/rel _build/rel_0.1.0
$ REBAR_PROFILE=prod ../rebar3 tar
===> tarball .../_build/rel/app1/app1-0.2.0.tar.gz successfully created!
$ cp _build/rel/app1/app1-0.2.0.tar.gz _build/rel_0.1.0/app1/releases/app1_0.2.0.tar.gz
$ _build/rel_0.1.0/app1/bin/app1 start
$ _build/rel_0.1.0/app1/bin/app1 upgrade 0.2.0
# you will get "noent ... reup" because '.appup' is missing, see https://github.com/rebar/rebar3/issues/57
from basic usage