How does rebar escriptize work?
Hello World
You can create Erlang scripts quite simply. Just create a file something like the following:
#!/usr/bin/env escript
main(_Args) ->
io:format("Hello World~n").
Then run it:
escript hello
Or:
chmod +x hello
./hello
rebar escriptize
If you want to include multiple Erlang modules in your script, you can take
advantage of the fact that escript
allows loading from an embedded ZIP
resource.
This is what the rebar escriptize
command does. You can create a skeleton application using rebar:
Note: I’m using rebar 2 in these examples.
# Create the skeleton application:
rebar create-app appid=hello
# Remove the boilerplate:
rm src/hello_app.erl src/hello_sup.erl
# Remove the {mod, {hello_app, ...}} line from the .app.src file:
sed -i '/{mod.*}/d' src/hello.app.src
You need to create an entry point in src/hello.erl
:
-module(hello).
-export([main/1]).
main(_Args) ->
io:format(hello_greetings:world()).
For demonstration purposes, I’ve created another module:
-module(hello_greetings).
-export([world/0]).
world() ->
"Hello World!~n".
Compile it using rebar compile escriptize
; run it with ./hello
.
Dependencies
The useful part about using rebar
is that it can manage dependencies for you.
For example, if we needed to load some JSON, we might want to use mochijson2.
To do this, create rebar.config
:
{deps,
[
{mochijson2, ".*",
{git, "https://github.com/rlipscombe/mochijson2.git"}}
]}.
{escript_incl_apps, [mochijson2]}.
Update hello.erl
to use a new module:
-module(hello).
-export([main/1]).
main([Path] = _Args) ->
io:format("~s~n", [hello_json:from_file(Path)]).
Create the hello_json.erl
file:
-module(hello_json).
-export([from_file/1]).
from_file(Path) ->
{ok, JSON} = file:read_file(Path),
{struct, Props} = mochijson2:decode(JSON),
proplists:get_value(<<"greeting">>, Props).
And, to save typing, a Makefile:
all:
rebar get-deps compile escriptize
Create a sample world.json
file:
{"greeting": "Hello World!"}
Compile and run it:
make && ./hello world.json
How does that work, then?
The hello
script actually looks like this:
#!/usr/bin/env escript
%%
%%! -pa hello/hello/ebin
PK...
…where PK
is the ZIP file magic number. That is: it’s got a shebang header,
some escript directives and then everything else is attached as a ZIP file.
What’s in the ZIP file?
$ unzip -l hello
Archive: hello
warning [hello]: 51 extra bytes at beginning or within zipfile
(attempting to process anyway)
Length Date Time Name
--------- ---------- ----- ----
0 2015-10-21 10:13 hello/
0 2015-10-21 10:13 hello/ebin/
240 2015-10-21 10:13 hello/ebin/hello.app
944 2015-10-21 10:13 hello/ebin/hello.beam
812 2015-10-21 10:13 hello/ebin/hello_greetings.beam
1144 2015-10-21 10:13 hello/ebin/hello_json.beam
0 2015-10-21 10:13 mochijson2/
0 2015-10-21 10:13 mochijson2/ebin/
234 2015-10-21 10:13 mochijson2/ebin/mochijson2.app
43544 2015-10-21 10:13 mochijson2/ebin/mochijson2.beam
16100 2015-10-21 10:13 mochijson2/ebin/mochinum.beam
--------- -------
63018 11 files
We can do that ourselves!
You don’t need rebar escriptize
to do this; it’s quite simple to write an
escriptize
script. See https://github.com/rlipscombe/escriptize for example.