When I start up a function within the erl shell, it works fine. When I try to invoke the same function with erl ... -s module function, it fails.
The line of code that eventually fails is:
start(Port) ->
mochiweb_http:start([{port, Port}, {loop, fun dispatch_requests/1}]).
I'm positive that Port is set correctly. My error message is:
=CRASH REPORT==== 17-Jan-2010::00:21:09 ===
crasher:
initial call: mochiweb_socket_server:acceptor_loop/1
pid: <0.65.0>
registered_name: []
exception exit: {error,closed}
in function mochiweb_socket_server:acceptor_loop/1
ancestors: [mochiweb_http,<0.1.0>]
messages: []
links: []
dictionary: []
trap_exit: false
status: running
heap_size: 377
stack_size: 24
reductions: 93
neighbours:
I tried the debugger and it lets me step through right up until the line of code above is given. After I pass that, it gives me this crash report.
Any help is greatly appreciated.
Hm, I think that should work.
Are all modules compiled with the same compiler version? IIRC there might be weird errors on the socket level if not.
BTW, you might call your entry point function start which is the default for -s.
Alternatively you can try the -eval option:
erl -eval 'module:start(9090).'
when using -s, the arguments are collected into a list, so the port would actually be enclosed in a list. you can check both cases (list or int) with a wrapper function (like start([Port])).
When you use -s to run Erlang functions, arguments are put into a list of atoms. When you use -run to run Erlang functions, arguments are put into a list of strings.
If you need an integer value to pass on, you will need to do the proper conversions. If you want to cover all cases, something like this could help:
start([Port]) when is_atom(Port) ->
start([atom_to_list(Port)]);
start([Port]) when is_list(Port) ->
start(list_to_integer(Port));
start(Port) when is_integer(Port) ->
mochiweb_http:start([{port, Port}, {loop, fun dispatch_requests/1}]).
Consult the man page for erl ("erl -man erl") for details.
Related
I'm working on a Erlang. How can I pass command line parameters to it?
Program File-
-module(program).
-export([main/0]).
main() ->
io:fwrite("Hello, world!\n").
Compilation Command:
erlc Program.erl
Execution Command-
erl -noshell -s program main -s init stop
I need to pass arguments through execution command and want to access them inside main written in program's main.
$ cat program.erl
-module(program).
-export([main/1]).
main(Args) ->
io:format("Args: ~p\n", [Args]).
$ erlc program.erl
$ erl -noshell -s program main foo bar -s init stop
Args: [foo,bar]
$ erl -noshell -run program main foo bar -s init stop
Args: ["foo","bar"]
It is documented in erl man page.
I would recommend using escript for this purpose because it has a simpler invocation.
These are not really commandline-parameters, but if you want to use environment-variables, the os-module might help. os:getenv() gives you a list of all environment variables. os:getenv(Var) gives you the value of the variable as a string, or returns false if Var is not an environment-variable.
These env-variables should be set before you start the application.
I always use an idiom like this to start (on a bash-shell):
export PORT=8080 && erl -noshell -s program main
If you want "named" argument, with possible default values, you can use this command line (from a toy appli I made):
erl -pa "./ebin" -s lavie -noshell -detach -width 100 -height 80 -zoom 6
lavie:start does nothing more than starting an erlang application:
-module (lavie).
-export ([start/0]).
start() -> application:start(lavie).
which in turn start the application where I defined default value for parameters, here is the app.src (rebar build):
{application, lavie,
[
{description, "Le jeu de la vie selon Conway"},
{vsn, "1.3.0"},
{registered, [lavie_sup,lavie_wx,lavie_fsm,lavie_server,rule_wx]},
{applications, [
kernel,
stdlib
]},
{mod, { lavie_app, [200,50,2]}}, %% with default parameters
{env, []}
]}.
then, in the application code, you can use init:get_argument/1 to get the value associated to each option if it was defined in the command line.
-module(lavie_app).
-behaviour(application).
%% Application callbacks
-export([start/2, stop/1]).
%% ===================================================================
%% Application callbacks
%% ===================================================================
start(_StartType, [W1,H1,Z1]) ->
W = get(width,W1),
H = get(height,H1),
Z = get(zoom,Z1),
lavie_sup:start_link([W,H,Z]).
stop(_State) ->
% init:stop().
ok.
get(Name,Def) ->
case init:get_argument(Name) of
{ok,[[L]]} -> list_to_integer(L);
_ -> Def
end.
Definitively more complex than #Hynek proposal, but it gives you more flexibility, and I find the command line less opaque.
Here's my code in 'factorial.erl':
-module(factorial).
-author("jasonzhu").
%% API
-export([fac/1]).
fac(0) -> 1;
fac(N) -> N * fac(N-1).
When interacting this code in prompt, it works fine:
1> c(factorial).
{ok,factorial}
2> factorial:fac(20).
2432902008176640000
But if I compile and execute it from command line, some errors occurred.
Jasons-MacBook-Pro:src jasonzhu$ erlc factorial.erl
Jasons-MacBook-Pro:src jasonzhu$ erl -noshell -s factorial fac 20 -s init stop
{"init terminating in do_boot",{badarith,[{factorial,fac,1,[{file,"factorial.erl"},{line,8}]},{init,start_it,1,[]},{init,start_em,1,[]}]}}
Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
Could anyone help me out? I'm a newbie on Erlang, many thanks!
-noshell syntax is
erl -noshell -s Module Function Arguments
where Arguments is a list of atoms. So you have to get 'fac' argument from list and convert it to integer.
This
-module(factorial).
-export([fac/1]).
fac([N]) ->
X = fac(list_to_integer(atom_to_list(N))),
io:format("~p~n", [X]);
fac(0) -> 1;
fac(N) -> N * fac(N-1).
works
>>> erl -noshell -s factorial fac 20 -s init stop
2432902008176640000
This option is not specific to the OP's question just may be useful for someone coming from “init terminating in do_boot” search in addition to the official doc How to Interpret the Erlang Crash Dumps
If your code is laying around for some time and you start working with it again, recompilation may make this error gone
Delete _build/ directory
Delete rebar.lock file
Compile /dir_with_rebarconfig$ rebar3 release
I need to pass two arguments to my Erlang code. it is working fine in the Erlang shell.
2> crop:fall_velocity(x,23).
21.23205124334434
but how should i run the Erlang code without the Erlang shell. like normal python,c programs.
./program_name (not passing $1 $2 arguments).
I was trying this
erl -noshell -s crop fall_velocity(x,20) -s init stop
But it is giving unexpected token error.
As documentation states, the -s passes all parameters supplied as just one list of atoms and -run does the same but as a list of strings. If you want to call arbitrary function with arbitrary parameter count and types you should use -eval:
$ erl -noshell -eval 'io:format("test\n",[]),init:stop()'
test
$
You can use escript to run Erlang scripts from the command line. In that script you should create a main function which takes an array of arguments as a string.
#!/usr/bin/env escript
main(Args) ->
io:format("Printing arguments:~n"),
lists:foreach(fun(Arg) -> io:format("Got argument: ~p~n", [Arg]) end,Args).
Output:
./escripter.erl hi what is your name 5 6 7 9
Printing arguments:
Got argument: "hi"
Got argument: "what"
Got argument: "is"
Got argument: "your"
Got argument: "name"
Got argument: "5"
Got argument: "6"
Got argument: "7"
Got argument: "9"
I try to make a comet-server using Mochiweb like there.
If I do it from erlang shell, it's alright.
But If try to start 1st node with mochiweb from command line:
erl -pa ebin edit deps/*/ebin -boot start_sasl -sname n1 -s server +K true -setcookie secret_key -s reloader
And 2nd one with router:
erl -pa ebin edit deps/*/ebin -boot start_sasl -sname router -setcookie secret_key -eval 'net_adm:ping(n1#localhost), router:start_link().'
If I connect to mochiweb from browser I have this error
=CRASH REPORT==== 18-Jul-2012::19:04:45 ===
crasher:
initial call: mochiweb_acceptor:init/3
pid: <0.73.0>
registered_name: []
exception exit: {noproc,
{gen_server,call,
[undefined,{login,"234567e",<0.73.0>}]}}
in function gen_server:call/2
in call from server_web:loop/2
in call from mochiweb_http:headers/5
ancestors: [server_web,server_sup,<0.55.0>]
messages: []
links: [<0.57.0>,#Port<0.1406>]
dictionary: [{mochiweb_request_qs,
[{"session_id","234567e"},{"obj_id","page"}]},
{mochiweb_request_path,"/polling"}]
trap_exit: false
status: running
heap_size: 2584
stack_size: 24
reductions: 1516
I think that problem is in this string from router.erl:
-define(SERVER, global:whereis_name(?MODULE)).
Because first part of -eval (net_adm:ping(n1#localhost)) was started without errors and I could see n1#localhost in nodes().. But the second part of -eval (router:start_link()) was not available for ?MODULE.
How can I resolve this problem?
Looks like the gen_server that was supposed to be globally registered with name of current module (?MODULE is replaced with it) just has not been started yet. global:whereis_name(?MODULE) will return undefined right in this case, like you see in log you posted.
Find the part of your code that's supposed to do that (by grepping for ?MODULe and/or gen_server:start_link in that module) and make sure it was executed on the first node.
I'm write a test with EUnit, but not anything exception detail output in console.
exp_test() ->
?assertEqual(0, 1/0).
Run this module:exp_test() in the Erlang Shell output following
** exception error: bad argument in an arithmetic expression
in function exp_test:'-exp_test/0-fun-0-'/1 (src/test/eunit/xxx_test.erl, line 8)
But in EUnit output following
> eunit:test(xxx).
> xxx_test: exp_test...*failed*
::badarith
EUnit not output anything exception trace info
Im trying the verbose config in eunit, but no effect.
I want to output some exception detail in eunit test result.
Thanks~
The problem seems to be that the version of eunit shipped with R15 does not understand the new stack trace format in R15. This has been fixed in the development version of eunit: github.com/richcarl/eunit
For example:
Eshell V5.10 (abort with ^G)
1> eunit:test(fun() -> (fun() -> exit(foo), ok end)() end).
erl_eval: expr...*failed*
in function erl_eval:do_apply/6 (erl_eval.erl, line 576)
in call from erl_eval:exprs/5 (erl_eval.erl, line 118)
**exit:foo
I hope this will make it into the next release of OTP R15.
This is a known problem in eunit as released in R15B and R15B01. This has been fixed in release R15B02. If you're stuck with an earlier version, you can download and apply a patch:
A workaround for releases before R15B02
You can fix the problem in your local installation by recompiling the affected module:
Download and unpack the Erlang/OTP sources, if you don't have them already.
wget http://www.erlang.org/download/otp_src_R15B01.tar.gz
tar xzf otp_src_R15B01.tar.gz
cd otp_src_R15B01
Download and apply the patch.
wget -O eunit-stacktrace.patch https://github.com/erlang/otp/commit/73b94a990bb91fd263dace4ccbaef6ff727a9637.patch
patch -p1 < eunit-stacktrace.patch
Recompile eunit_lib.erl.
cd lib/eunit
erlc -o ebin -I include src/eunit_lib.erl
Copy the new eunit_lib.beam over the old one (usually somewhere below /usr/local).
ls /usr/local/lib/erlang/lib/eunit-2.2.2/ebin/
# check that eunit_lib.beam is actually there
sudo cp ebin/eunit_lib.beam /usr/local/lib/erlang/lib/eunit-2.2.2/ebin/
Eunit is quite old and while it is officially maintained by the OTP team at Ericsson, it is usually uncared for. Eunit currently has the bad habit of eating up stack traces, and hasn't been updated for R15's line numbers in exceptions.
I wouldn't argue that "that's how it's supposed to work". No sane test tool should hide exception details and line numbers for you.
A trick I like to use is ?debugVal(catch expr) where expr is either a begin end block
or a call to the failing function. For example, ?debugVal(catch begin 1 = 2 end) will output a stacktrace in your tests.