我有以下Erlang代码:
#!/usr/bin/env escript
%%! -pz ../deps/amqp_client ../deps/rabbit_common ../deps/amqp_client/ebin ../deps/rabbit_common/ebin
% RMQ module
-module(rmq).
-export([main/1, send/1, validate/0, test/0]).
-include_lib("../deps/amqp_client/include/amqp_client.hrl").
main(_) ->
%send(<<"test_esio">>),
%validate(),
Pid = spawn(rmq, test, []),
% Pid = spawn(fun() -> test() end), <= I've tried this way too
Pid ! s.
test() ->
receive
s ->
io:format("BAR ~n"),
send(<<"esio">>),
test();
get ->
validate(),
test();
_ ->
io:format("FOO"),
test()
end.
我用以下方式运行:
excript rmq.erl
此代码不起作用。看起来像spawn不起作用。
如果我从main运行它,我的其余代码工作,函数发送和验证正常工作(我已经评论了它)。我做错了什么?
对不起,也许这是一个愚蠢的问题,但我是erlang的初学者。我试过在互联网和书籍上搜索答案,但我失败了......
答案 0 :(得分:3)
问题实际上不是在spawn中,而是在模块/ escript混乱中。
简而言之,即使您使用-module()
指令,escript文件也不是真正的模块,而不是Erlang VM。它们被解释,并且根本没有编译,并且它们不能被像“rmq:test()”这样的模块调用,或者通过spawn
通过动态模块调用来调用它们。
最简单的解决方案是与实际模块分开的脚本。在rmq.es
中,您只需启动一些适当的模块:
#!/usr/bin/env escript
%%! -pz ../deps/amqp_client ../deps/rabbit_common ../deps/amqp_client/ebin ../deps/rabbit_common/ebin
main(_) ->
rmq:start().
模块rmq.erl
:
-module(rmq).
-export([start/0, send/1, validate/0, test/0]).
-include_lib("../deps/amqp_client/include/amqp_client.hrl").
start() ->
Pid = spawn(rmq, test, []),
%% Pid = spawn(?MODULE, test, []), %% works with macro too
%% Pid = spawn(fun() -> test() end), <= I've tried this way too
Pid ! s.
test() ->
receive
s ->
io:format("BAR ~n"),
send(<<"esio">>),
test();
get ->
validate(),
test();
_ ->
io:format("FOO"),
test()
end.
或者您可以在没有escript的情况下启动此模块,并使用-run
这样的标记
erl -pz deps/*/ebin -run rmq start
编辑
使用erlc
command编译模块。只编译使用erlc rmq.erl
,这将在当前目录中生成rmq.beam
文件。但惯例是将所有源文件保存在src
目录中,所有编译文件保存在ebin
目录中,并且运行脚本之类的东西可以放在顶层目录中。这样的事情:
project
|-- ebin
| |-- rmq.beam
|
|-- src
| |-- rmq.erl
|
|-- rmq.es
假设您从project
目录运行所有shell命令,要编译来自src
的所有文件并将.beam
二进制文件放在ebin
中使用erlc src/rmq.erl -o ebin
,或erlc src/* -o ebin
在文档中,您可以找到-o
flag“
-o目录
编译器应放置输出文件的目录。如果未指定,则输出文件将放在当前工作目录中。
然后,在编译之后,您可以使用erl
Erlang VM或使用escript
来运行您的代码(使用erl
时会使用erl
。
*.ebin
从已编译的模块运行代码,为此,他需要能够找到那些已编译的-pa
二进制文件。为此他使用代码路径,这是他将搜索这些文件的导演列表。此列表自动包含标准库目录,当然您可以使用erl -pa ebin
标志将自己的代码添加到目录中。
-pa Dir1 Dir2 ......
将指定的目录添加到代码路径的开头,类似于代码:add_pathsa / 1。见代码(3)。作为-pa的替代方案,如果要为代码添加多个目录并且目录具有公共父目录,则可以在ERL_LIBS环境变量中指定该父目录。见代码(3)。
在您的情况下,它将是erl -pa ebin -pa deps/*/ebin
,或者包含您可以使用*
的所有代码的二进制文件。
在您的escript的第二行中使用了完全相同的选项。除-pa ebin
字符外,它不会像在shell中那样展开。在escript中,您必须分别提供每个依赖项的路径。但是包含{{1}}的想法保持不变。