代码束文件在哪里?
where is code beam file?
我打印了所有加载的代码如下,为什么
{lager_default_tracer,[]},束文件在哪里?
(lager_test_1@macbook.local)10> io:format("~p",[code:all_loaded()]).
[{io,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/io.beam"},
{erl_distribution,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/erl_distribution.beam"},
{edlin,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/edlin.beam"},
{beam_clean,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_clean.beam"},
{v3_core,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/v3_core.beam"},
{erl_epmd,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/erl_epmd.beam"},
{love_misc,"/usr/local/bin/lager_test/lib/hanoch-0.0.1.6/ebin/love_misc.beam"},
{zlib,preloaded},
{error_handler,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/error_handler.beam"},
{io_lib,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/io_lib.beam"},
{lib,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/lib.beam"},
{mnesia,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia.beam"},
{lager_test_app,"/usr/local/bin/lager_test/lib/lager_test-0.0.1.0/ebin/lager_test_app.beam"},
{beam_jump,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_jump.beam"},
{v3_codegen,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/v3_codegen.beam"},
{beam_flatten,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_flatten.beam"},
{mnesia_tm,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_tm.beam"},
{prim_eval,preloaded},
{beam_bool,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_bool.beam"},
{error_logger_lager_h,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/error_logger_lager_h.beam"},
{lager_msg,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_msg.beam"},
{mnesia_frag,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_frag.beam"},
{filename,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/filename.beam"},
{lager_default_tracer,[]},
{lager_default_formatter,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_default_formatter.beam"},
{mnesia_locker,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_locker.beam"},
{mnesia_recover,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_recover.beam"},
{mnesia_dumper,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_dumper.beam"},
{mnesia_kernel_sup,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_kernel_sup.beam"},
{mnesia_sp,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_sp.beam"},
{erts_internal,preloaded},
{unicode,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/unicode.beam"},
{lager_backend_throttle,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_backend_throttle.beam"},
{beam_type,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_type.beam"},
{orddict,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/orddict.beam"},
{gb_sets,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/gb_sets.beam"},
{sofs,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/sofs.beam"},
{inet_db,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/inet_db.beam"},
{lager_test_a,"/usr/local/bin/lager_test/lib/lager_test-0.0.1.0/ebin/lager_test_a.beam"},
{inet,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/inet.beam"},
当我调用module_info()时,结果如下:
(lager_test_1@macbook.local)11> lager_default_tracer:module_info().
[{exports,[{table,1},
{handle,1},
{module_info,0},
{module_info,1},
{info,1}]},
{imports,[]},
{attributes,[{vsn,[203040246025344403396962742072895880482]}]},
{compile,[{options,[]},
{version,"5.0.3"},
{time,{2017,8,27,5,43,32}},
{source,"/private/tmp/lager_test-0.0.1.0"}]}]
当我调用lager_default_tracer:table(111)
时,结果如下:
(lager_test_1@macbook.local)12> lager_default_tracer:table(aaa).
** exception error: bad argument
in function lager_default_tracer:table/1
lager_default_tracer
模块没有关联的光束文件,因为它是在 运行 时间创建的。 lager
应用使用goldrush
,其中使用运行时间码编译加载
如果你翻阅goldrush
sources you'll see that it calls the standard compile:forms/2
for dynamic compilation. By tracing that call, we can reconstruct the source code for lager_default_tracer
using the steps below, which assume you've already cloned the lager
source repository,编译成功。在某些步骤中,Erlang shell 命令的输出太大而无法放在这里,因此这些部分使用省略号缩写。
在您已经编译的克隆 lager
回购目录中,运行 rebar shell
启动一个 Erlang shell,确保所有必要的目录都是在 Erlang 加载路径中。
在shell中,打开dbg
tracing并跟踪compile:forms/2
:
1> dbg:tracer(), dbg:p(all, call).
{ok,[{matched,nonode@nohost,34}]}
2> dbg:tpl(compile, forms, []).
{ok,[{matched,nonode@nohost,2}]}
启动 lager
应用程序及其依赖项:
3> application:ensure_all_started(lager).
这将导致 dbg
跟踪产生一些冗长的输出,如下所示:
(<0.94.0>) call compile:forms([{attribute,0,module,lager_default_tracer},
...
{tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}],[nowarn_unused_vars])
{ok,[syntax_tools,compiler,goldrush,lager]}
08:29:21.478 [info] Application lager started on node nonode@nohost
此处,输出被缩写为仅显示第一行和最后几行。最后两行是 application:ensure_all_started/1
的结果。这些行上方的所有内容都是 lager_default_tracer
模块的 abstract format。
复制跟踪输出,从输出跟踪第一行的 [{attribute,0,module,lager_default_tracer}
一直到输出跟踪最后一行的 {tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}]
。不要在复制的内容中包含结尾文本 [nowarn_unused_vars])
。
粘贴复制的数据以将其分配给 Erlang 中名为 M
的变量 shell:
4> M = [{attribute,0,module,lager_default_tracer},
...
{tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}].
不要忘记添加最后一个句点(又名句号)来完成表达式。
关闭dbg
跟踪:
5> dbg:stop_clear().
ok
编译摘要格式:
6> {ok, _, B} = compile:forms(M, [no_unused_vars, debug_info]).
{ok,lager_default_tracer,
<<70,79,82,49,0,0,6,164,66,69,65,77,65,116,85,56,0,0,1,9,
0,0,0,23,20,108,...>>}
变量 B
现在以二进制形式保存 lager_default_tracer
模块的编译代码。
从存储在B
:
中的已编译二进制文件中提取抽象代码块
7> {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(B,[abstract_code]).
{ok,{lager_default_tracer,
[{abstract_code,
...
[{clause,0,[{var,0,'Event'}],[],[{call,...}]}]}]}}]}}
变量AC
现在保存抽象代码。
使用抽象代码打印 lager_default_tracer
模块的重构源代码:
8> io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
-module(lager_default_tracer).
-export([info/1, reset_counters/1, table/1, handle/1]).
...
handle_(Event) ->
gr_counter:update_counter(table(counters), filter,
{2, 1}).
ok
最后一步和之前的一步取自 "Reconstructing Source Code" 下的 beam_lib
documentation。
毫不奇怪,重构的源代码显示了其他 goldrush
函数的调用,因此如果您想尝试理解重构的代码,您需要访问 goldrush
sources。
我打印了所有加载的代码如下,为什么 {lager_default_tracer,[]},束文件在哪里?
(lager_test_1@macbook.local)10> io:format("~p",[code:all_loaded()]).
[{io,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/io.beam"},
{erl_distribution,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/erl_distribution.beam"},
{edlin,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/edlin.beam"},
{beam_clean,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_clean.beam"},
{v3_core,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/v3_core.beam"},
{erl_epmd,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/erl_epmd.beam"},
{love_misc,"/usr/local/bin/lager_test/lib/hanoch-0.0.1.6/ebin/love_misc.beam"},
{zlib,preloaded},
{error_handler,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/error_handler.beam"},
{io_lib,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/io_lib.beam"},
{lib,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/lib.beam"},
{mnesia,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia.beam"},
{lager_test_app,"/usr/local/bin/lager_test/lib/lager_test-0.0.1.0/ebin/lager_test_app.beam"},
{beam_jump,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_jump.beam"},
{v3_codegen,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/v3_codegen.beam"},
{beam_flatten,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_flatten.beam"},
{mnesia_tm,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_tm.beam"},
{prim_eval,preloaded},
{beam_bool,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_bool.beam"},
{error_logger_lager_h,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/error_logger_lager_h.beam"},
{lager_msg,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_msg.beam"},
{mnesia_frag,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_frag.beam"},
{filename,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/filename.beam"},
{lager_default_tracer,[]},
{lager_default_formatter,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_default_formatter.beam"},
{mnesia_locker,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_locker.beam"},
{mnesia_recover,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_recover.beam"},
{mnesia_dumper,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_dumper.beam"},
{mnesia_kernel_sup,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_kernel_sup.beam"},
{mnesia_sp,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_sp.beam"},
{erts_internal,preloaded},
{unicode,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/unicode.beam"},
{lager_backend_throttle,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_backend_throttle.beam"},
{beam_type,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_type.beam"},
{orddict,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/orddict.beam"},
{gb_sets,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/gb_sets.beam"},
{sofs,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/sofs.beam"},
{inet_db,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/inet_db.beam"},
{lager_test_a,"/usr/local/bin/lager_test/lib/lager_test-0.0.1.0/ebin/lager_test_a.beam"},
{inet,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/inet.beam"},
当我调用module_info()时,结果如下:
(lager_test_1@macbook.local)11> lager_default_tracer:module_info().
[{exports,[{table,1},
{handle,1},
{module_info,0},
{module_info,1},
{info,1}]},
{imports,[]},
{attributes,[{vsn,[203040246025344403396962742072895880482]}]},
{compile,[{options,[]},
{version,"5.0.3"},
{time,{2017,8,27,5,43,32}},
{source,"/private/tmp/lager_test-0.0.1.0"}]}]
当我调用lager_default_tracer:table(111)
时,结果如下:
(lager_test_1@macbook.local)12> lager_default_tracer:table(aaa).
** exception error: bad argument
in function lager_default_tracer:table/1
lager_default_tracer
模块没有关联的光束文件,因为它是在 运行 时间创建的。 lager
应用使用goldrush
,其中使用运行时间码编译加载
如果你翻阅goldrush
sources you'll see that it calls the standard compile:forms/2
for dynamic compilation. By tracing that call, we can reconstruct the source code for lager_default_tracer
using the steps below, which assume you've already cloned the lager
source repository,编译成功。在某些步骤中,Erlang shell 命令的输出太大而无法放在这里,因此这些部分使用省略号缩写。
在您已经编译的克隆
lager
回购目录中,运行rebar shell
启动一个 Erlang shell,确保所有必要的目录都是在 Erlang 加载路径中。在shell中,打开
dbg
tracing并跟踪compile:forms/2
:1> dbg:tracer(), dbg:p(all, call). {ok,[{matched,nonode@nohost,34}]} 2> dbg:tpl(compile, forms, []). {ok,[{matched,nonode@nohost,2}]}
启动
lager
应用程序及其依赖项:3> application:ensure_all_started(lager).
这将导致
dbg
跟踪产生一些冗长的输出,如下所示:(<0.94.0>) call compile:forms([{attribute,0,module,lager_default_tracer}, ... {tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}],[nowarn_unused_vars]) {ok,[syntax_tools,compiler,goldrush,lager]} 08:29:21.478 [info] Application lager started on node nonode@nohost
此处,输出被缩写为仅显示第一行和最后几行。最后两行是
application:ensure_all_started/1
的结果。这些行上方的所有内容都是lager_default_tracer
模块的 abstract format。复制跟踪输出,从输出跟踪第一行的
[{attribute,0,module,lager_default_tracer}
一直到输出跟踪最后一行的{tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}]
。不要在复制的内容中包含结尾文本[nowarn_unused_vars])
。粘贴复制的数据以将其分配给 Erlang 中名为
M
的变量 shell:4> M = [{attribute,0,module,lager_default_tracer}, ... {tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}].
不要忘记添加最后一个句点(又名句号)来完成表达式。
关闭
dbg
跟踪:5> dbg:stop_clear(). ok
编译摘要格式:
6> {ok, _, B} = compile:forms(M, [no_unused_vars, debug_info]). {ok,lager_default_tracer, <<70,79,82,49,0,0,6,164,66,69,65,77,65,116,85,56,0,0,1,9, 0,0,0,23,20,108,...>>}
变量
B
现在以二进制形式保存lager_default_tracer
模块的编译代码。从存储在
中的已编译二进制文件中提取抽象代码块B
:7> {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(B,[abstract_code]). {ok,{lager_default_tracer, [{abstract_code, ... [{clause,0,[{var,0,'Event'}],[],[{call,...}]}]}]}}]}}
变量
AC
现在保存抽象代码。使用抽象代码打印
lager_default_tracer
模块的重构源代码:8> io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]). -module(lager_default_tracer). -export([info/1, reset_counters/1, table/1, handle/1]). ... handle_(Event) -> gr_counter:update_counter(table(counters), filter, {2, 1}). ok
最后一步和之前的一步取自 "Reconstructing Source Code" 下的
beam_lib
documentation。
毫不奇怪,重构的源代码显示了其他 goldrush
函数的调用,因此如果您想尝试理解重构的代码,您需要访问 goldrush
sources。