Skip to content

How to launch an application created using "rebar3 new app" and "rebar3 escriptize"? #1740

Closed
@lfmunoz

Description

@lfmunoz

I'm trying to create a simple hello world program...

-module(myapp_app).
-behaviour(application).

%% Application callbacks
-export([start/2, stop/1]).

%%====================================================================
%% API
%%====================================================================
start(_StartType, _StartArgs) ->
    io:format("hello world~n"),
    myapp_sup:start_link().

%%--------------------------------------------------------------------
stop(_State) ->
    ok.

These are the steps...

~$ rebar3 new app myapp                                                                                                              
===> Writing myapp/src/myapp_app.erl                                                                                                                      
===> Writing myapp/src/myapp_sup.erl                                                                                                                      
===> Writing myapp/src/myapp.app.src                                                                                                                      
===> Writing myapp/rebar.config                                                                                                                           
===> Writing myapp/.gitignore                                                                                                                             
===> Writing myapp/LICENSE                                                                                                                                
===> Writing myapp/README.md            

~$ rebar3 escriptize
===> Verifying dependencies...
===> Compiling myapp
===> Building escript...

~$ _build/default/bin/myapp
escript: exception error: undefined function myapp:main/1
  in function  escript:run/2 (escript.erl, line 759)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1
  in call from init:do_boot/3

...

Why doesn't this work what do I have to do so it launches my application?

Using shell does work...

rebar3 shell --apps myapp
===> Verifying dependencies...
===> Compiling myapp
Erlang/OTP 20 [erts-9.0.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:0] [kernel-poll:false]

Eshell V9.0.4  (abort with ^G)
1> ===> The rebar3 shell is a development tool; to deploy applications in production, consider using releases (http://www.rebar3.org/docs/releases)
hello world
===> Booted myapp

I want to run it the application in the background not use a shell to attach. How do I create the escript to launch it or do I have to do a release? I apologize if this is a newbie question, but I feel like this should be the easiest thing to do but I cannot figure it out :/

Activity

fenollp

fenollp commented on Apr 6, 2018

@fenollp
Contributor

What you seem to be looking for is how to create a simple CLI app with Erlang. rebar3 escriptize is the right way to go however you got that error message:

escript: exception error: undefined function myapp:main/1

meaning you need to create a module called myapp which has to export a main function taking 1 argument. You should put your hello world code in there.

Here's more info on Erlang CLI apps (they're called escripts).

added
questionquestion relative to the project
on Apr 6, 2018
lfmunoz

lfmunoz commented on Apr 6, 2018

@lfmunoz
Author

@fenollp thank you, that got me a step further, but I can't get the application to start. I tried the following

-module(myapp).
-export([main/1]).

main(_Any) ->
  myapp_sup:start_link(),
  %application:start(webSockInter),
  io:format("working?"),
 % prevent the shutting down of the erlang runtime
  receive after infinity -> stop end. 

myapp_up:start_link() appears to be doing nothing. The above is just a simple example but I am actually running a tcp service that suppose to accept connections.

I think rebar3 escriptize doesn't package the full vm runtime, so I tried including that in rebar.config

%% apps (other than main and deps) to be included
{escript_incl_apps, [kernel, stdlib]}.

That doesn't work, gets error when trying to "process kernel"

===> processing <<"kernel">>                        
===> Uncaught error in rebar_core. Run with DEBUG=1 to see stacktrace or consult rebar3.crashdump       
===> Uncaught error: {badmatch,error}               
===> Stack trace to the error location:             
[{rebar_prv_escriptize,find_deps_of_deps,3,         
                       [{file,"/home/tristan/Devel/rebar3/_build/default/lib/rebar/src/rebar_prv_escriptize.erl"},                                                                                              
                        {line,246}]},               
 {rebar_prv_escriptize,find_deps,2,                 
                       [{file,"/home/tristan/Devel/rebar3/_build/default/lib/rebar/src/rebar_prv_escriptize.erl"},                                                                                              
                        {line,240}]},               
 {rebar_prv_escriptize,escriptize,2,                
                       [{file,"/home/tristan/Devel/rebar3/_build/default/lib/rebar/src/rebar_prv_escriptize.erl"},                                                                                              
                        {line,104}]},               
 {rebar_prv_escriptize,do,1,                        
                       [{file,"/home/tristan/Devel/rebar3/_build/default/lib/rebar/src/rebar_prv_escriptize.erl"},                                                                                              
                        {line,80}]},                
 {rebar_core,do,2,                                  
             [{file,"/home/tristan/Devel/rebar3/_build/default/lib/rebar/src/rebar_core.erl"},          
              {line,153}]},                         
 {rebar3,main,1,                                    
         [{file,"/home/tristan/Devel/rebar3/_build/default/lib/rebar/src/rebar3.erl"},                  
          {line,66}]},                              
 {escript,run,2,[{file,"escript.erl"},{line,759}]}, 
 {escript,start,1,[{file,"escript.erl"},{line,277}]}]      

I'm gonna stick with releases unless someone can give me a clue on how to get this working.

fenollp

fenollp commented on Apr 8, 2018

@fenollp
Contributor

There is never any VM runtime packaged into an escript. You can take a look at what’s inside an escript with unzip -l my.escript. In my experience you rarely need to ever use escript_incl_apps, you should probably be setting these app dependencies in your .app.src instead.
Note that if your app talks with the web it may already need to have inets there.

ferd

ferd commented on Apr 20, 2018

@ferd
Collaborator

Here's a full example using rebar3 escriptize:

λ /tmp → rebar3 new escript hello
===> Writing hello/src/hello.erl
===> Writing hello/src/hello.app.src
===> Writing hello/rebar.config
===> Writing hello/.gitignore
===> Writing hello/LICENSE
===> Writing hello/README.md
λ /tmp → cd hello
→ vim src/hello.erl
λ hello → cat src/hello.erl
-module(hello).

%% API exports
-export([main/1]).

%% escript Entry point
main(_Args) ->
    io:format("Hello World~n", []),
    erlang:halt(0).
λ hello → rebar3 escriptize
===> Verifying dependencies...
===> Compiling hello
===> Building escript...
λ hello → _build/default/bin/hello
Hello World

So what does this require? First of all, let's take a look at the rebar.config file:

{deps, []}.

{escript_incl_apps,
 [hello]}.
{escript_main_app, hello}.
{escript_name, hello}.
{escript_emu_args, "%%! +sbtu +A0\n"}.
  • the big deal is having the escript_main_app set to the application name I want to use. (here, hello)
  • That application has a module with the same name (hello) that exports a function main/1
  • if your application has runtime dependencies, they should be declared in the applications tuple of your .app.src file (in src/)

With these two things we can build an escript. The escript, as @fenollp said, ships without the Erlang VM and requires it to be installed. It makes Erlang become a scripting language the same way Python or Ruby would be, in some ways. It is still compiled and bundles its own code, but depends on a runtime environment being present.

If you want to boot your application in the escript, then calling application:ensure_all_started(YourApp) is likely the best way to go, and a timer:sleep(infinity). will help things keep running.

Let us know if you need more assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionquestion relative to the project

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @ferd@fenollp@lfmunoz

        Issue actions

          How to launch an application created using "rebar3 new app" and "rebar3 escriptize"? · Issue #1740 · erlang/rebar3