Erlang Notes

rebar3 tricks
Login

rebar3 tricks

  1. Copy scripts from the _build directory after rebar3 escriptize
  2. Create fully self-contained releases
  3. Set emulator flags (like +pc unicode) for rebar3 shell

Copy scripts from the _build directory after rebar3 escriptize

seen in erlperf

Consider the default escript project:

$ rebar3 new escript posthook_example
$ cd posthook_example/
$ rebar3 escriptize
$ ./_build/default/bin/posthook_example some arguments
Args: ["some","arguments"]

it's a bit of extra friction to ask people to run the script from that location, when they've only checked out your project to use your script. You can lower that friction with a posthook that copies the file, by adding this to the rebar.config:

{post_hooks, [
    {"(linux|darwin|solaris|freebsd|netbsd|openbsd)", escriptize,
        "cp \"$REBAR_BUILD_DIR/bin/posthook_example\" ./posthook_example"},
    {"win32", escriptize,
        "robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ posthook_example* " "/njs /njh /nfl /ndl & exit /b 0"}
]}.

Create fully self-contained releases

You make a little app, build a release, go to run it ... and it's obviously incomplete and starting with your system's erlexec? How is that supposed to work?

$ rebar3 new release demo
$ cd demo
$ rebar3 release
$_build/default/rel/demo/bin/demo foreground

That's supposed to work for development. The default relx section in your rebar.config looks like this:

{relx, [{release, {demo, "0.1.0"},
         [demo,
          sasl]},

        {mode, dev},

        %% automatically picked up if the files
        %% exist but can be set manually, which
        %% is required if the names aren't exactly
        %% sys.config and vm.args
        {sys_config, "./config/sys.config"},
        {vm_args, "./config/vm.args"}

        %% the .src form of the configuration files do
        %% not require setting RELX_REPLACE_OS_VARS
        %% {sys_config_src, "./config/sys.config.src"},
        %% {vm_args_src, "./config/vm.args.src"}
]}.

And that {mode, dev} is why. From https://rebar3.org/docs/deployment/releases/#modes,

dev	[{dev_mode, true}, {include_src, true}, {debug_info, keep}, {include_erts, false}]
prod	[{include_src, false}, {debug_info, strip}, {include_erts, true}, {dev_mode, false}]
minimal	[{include_src, false}, {debug_info, strip}, {include_erts, false}, {dev_mode, false}]

dev mode includes your source but excludes erts - the Erlang Runtime System.

To get the release that you expected, you want the production profile that's also in your rebar.config:

{profiles, [{prod, [{relx,
                     [%% prod is the default mode when prod
                      %% profile is used, so does not have
                      %% to be explicitly included like this
                      {mode, prod}

                      %% use minimal mode to exclude ERTS
                      %% {mode, minimal}
                     ]
            }]}]}.

To use that:

$ rebar3 as prod release  # 'prod' here is the *profile* name
$ _build/prod/rel/demo/bin/demo foreground

Now you'll see that it's using the release bundled erts, and you can tar this up and deploy it - to a sufficiently similar machine. You'll probably want an Alpine Linux docker to supply much more Linux-portable binaries.

Note also, erts is huge:

$ tar -C _build/prod/rel -Jcvf demo.tar.xz demo
$ du -sh _build/prod demo.tar.xz
134M    _build/prod
14M     demo.tar.xz

This is 3-4 golang binaries, compressed!

Set emulator flags (like +pc unicode) for rebar3 shell

rebar3 is an escript and it reuses its own node for the shell, so there is no project configuration that can change the emulator flags for rebar3 shell, because the emulator's running before any such configuration can be read.

You'll have to change rebar3's own startup:

  1. Set ERL_FLAGS in the environment:
    ERL_FLAGS="+pc unicode" rebar3 shell
  2. Rebuild rebar3 to have the wanted flags, with e.g. this edit to its rebar.config:
    -{escript_emu_args, "%%! +sbtu +A1\n"}.
    +{escript_emu_args, "%%! +sbtu +A1 +pc unicode\n"}.