elixir 或 erlang 或其它執行在 beam vm 上的語言,都會被編譯成 .beam
檔案。那麼能否通過這些檔案重建 erlang 程式碼呢?答案是可以的。
[file] = System.argv()
beam = File.read!(file)
{:ok, {_, [{:abstract_code, {_, ac}}]}} = :beam_lib.chunks(beam, [:abstract_code])
out = file <> ".erl"
File.touch!(out)
File.write!(out, :erl_prettypr.format(:erl_syntax.form_list(ac)))
將上面的程式碼儲存為 beam2erl.exs
檔案。
然後我們隨便找一個 elixir 檔案, 比如:
defmodule Demo do
defdelegate puts(str), to: IO
end
將其編譯,然後把對應的 beam 檔案複製到 beam2erl.exs
的目錄下,再執行:
$ elixir beam2erl.exs Elixir.Demo.beam
就能看到生成了一個 .erl
檔案,內容是:
-file("lib/demo.ex", 1).
-module('Elixir.Demo').
-compile([no_auto_import]).
-export(['__info__'/1, puts/1]).
-spec '__info__'(attributes |
compile |
functions |
macros |
md5 |
exports_md5 |
module |
deprecated) -> any().
'__info__'(module) -> 'Elixir.Demo';
'__info__'(functions) -> [{puts, 1}];
'__info__'(macros) -> [];
'__info__'(exports_md5) ->
<<"\n\025Y�a#�x�\201W��a#�">>;
'__info__'(Key = attributes) ->
erlang:get_module_info('Elixir.Demo', Key);
'__info__'(Key = compile) ->
erlang:get_module_info('Elixir.Demo', Key);
'__info__'(Key = md5) ->
erlang:get_module_info('Elixir.Demo', Key);
'__info__'(deprecated) -> [].
puts(_str@1) -> 'Elixir.IO':puts(_str@1).
上面的一大串是模組中內建的函式,最後一行是我們程式碼的內容。
有了這個小指令碼,學習和調整包含複雜的 elixir 巨集的程式碼,就方便多了。