Skip to content

Commit

Permalink
Add compile_info option to compile
Browse files Browse the repository at this point in the history
This allows compilers built on top of the compile module
to attach external compilation metadata to the compile_info
chunk.

For example, Erlang uses this chunk to store the compiler
version. Elixir and LFE may augment this by also adding
their own compiler versions, which can be useful when
debugging.

The deterministic option does not affect the user supplied
compile_info. It is therefore the responsibility of external
compilers to guarantee any added information does not violate
the determinsitic option, if such option is supported.

Finally, this code moves the building of the compile_info
options to the compile module instead of beam_asm, moving
all of the option mangling code to a single place.
  • Loading branch information
José Valim committed Sep 14, 2017
1 parent fdf359f commit 9bac40f
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 29 deletions.
11 changes: 11 additions & 0 deletions lib/compiler/doc/src/compile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@
in the Efficiency Guide.</p>
</item>

<tag><c>{compile_info, [{atom(), term()}]}</c></tag>
<item>
<p>Allows compilers built on top of <c>compile</c> to attach
extra compilation metadata to the <c>compile_info</c> chunk
in the generated beam file.</p>

<p>It is advised for compilers to remove all non-deterministic
information if the <c>deterministic</c> option is supported and
it was supplied by the user.</p>
</item>

<tag><c>compressed</c></tag>
<item>
<p>The compiler will compress the generated object code,
Expand Down
38 changes: 13 additions & 25 deletions lib/compiler/src/beam_asm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

-module(beam_asm).

-export([module/5]).
-export([module/4]).
-export([encode/2]).

-export_type([fail/0,label/0,reg/0,src/0,module_code/0,function_name/0]).
Expand Down Expand Up @@ -55,20 +55,20 @@
-type module_code() ::
{module(),[_],[_],[asm_function()],pos_integer()}.

-spec module(module_code(), [{binary(), binary()}], [_], [compile:option()], [compile:option()]) ->
-spec module(module_code(), [{binary(), binary()}], [{atom(),term()}], [compile:option()]) ->
{'ok',binary()}.

module(Code, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
{ok,assemble(Code, ExtraChunks, SourceFile, Opts, CompilerOpts)}.
module(Code, ExtraChunks, CompileInfo, CompilerOpts) ->
{ok,assemble(Code, ExtraChunks, CompileInfo, CompilerOpts)}.

assemble({Mod,Exp0,Attr0,Asm0,NumLabels}, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
assemble({Mod,Exp0,Attr0,Asm0,NumLabels}, ExtraChunks, CompileInfo, CompilerOpts) ->
{1,Dict0} = beam_dict:atom(Mod, beam_dict:new()),
{0,Dict1} = beam_dict:fname(atom_to_list(Mod) ++ ".erl", Dict0),
NumFuncs = length(Asm0),
{Asm,Attr} = on_load(Asm0, Attr0),
Exp = cerl_sets:from_list(Exp0),
{Code,Dict2} = assemble_1(Asm, Exp, Dict1, []),
build_file(Code, Attr, Dict2, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts, CompilerOpts).
build_file(Code, Attr, Dict2, NumLabels, NumFuncs, ExtraChunks, CompileInfo, CompilerOpts).

on_load(Fs0, Attr0) ->
case proplists:get_value(on_load, Attr0) of
Expand Down Expand Up @@ -111,7 +111,7 @@ assemble_function([H|T], Acc, Dict0) ->
assemble_function([], Code, Dict) ->
{Code, Dict}.

build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, CompileInfo, CompilerOpts) ->
%% Create the code chunk.

CodeChunk = chunk(<<"Code">>,
Expand Down Expand Up @@ -182,7 +182,7 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts,
Essentials1 = [iolist_to_binary(C) || C <- Essentials0],
MD5 = module_md5(Essentials1),
Essentials = finalize_fun_table(Essentials1, MD5),
{Attributes,Compile} = build_attributes(Opts, SourceFile, Attr, MD5),
{Attributes,Compile} = build_attributes(Attr, CompileInfo, MD5),
AttrChunk = chunk(<<"Attr">>, Attributes),
CompileChunk = chunk(<<"CInf">>, Compile),

Expand All @@ -192,7 +192,7 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts,

%% Create IFF chunk.

Chunks = case member(slim, Opts) of
Chunks = case member(slim, CompilerOpts) of
true ->
[Essentials,AttrChunk];
false ->
Expand Down Expand Up @@ -264,22 +264,10 @@ flatten_exports(Exps) ->
flatten_imports(Imps) ->
list_to_binary(map(fun({M,F,A}) -> <<M:32,F:32,A:32>> end, Imps)).

build_attributes(Opts, SourceFile, Attr, MD5) ->
Misc0 = case SourceFile of
[] -> [];
[_|_] -> [{source,SourceFile}]
end,
Misc = case member(slim, Opts) of
false -> Misc0;
true -> []
end,
Compile = case member(deterministic, Opts) of
false ->
[{options,Opts},{version,?COMPILER_VSN}|Misc];
true ->
[{version,?COMPILER_VSN}]
end,
{term_to_binary(set_vsn_attribute(Attr, MD5)),term_to_binary(Compile)}.
build_attributes(Attr, Compile, MD5) ->
AttrBinary = term_to_binary(set_vsn_attribute(Attr, MD5)),
CompileBinary = term_to_binary([{version,?COMPILER_VSN}|Compile]),
{AttrBinary,CompileBinary}.

build_line_table(Dict) ->
{NumLineInstrs,NumFnames0,Fnames0,NumLines,Lines0} =
Expand Down
22 changes: 20 additions & 2 deletions lib/compiler/src/compile.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1448,15 +1448,33 @@ save_core_code(Code, St) ->
beam_asm(Code0, #compile{ifile=File,extra_chunks=ExtraChunks,options=CompilerOpts}=St) ->
case debug_info(St) of
{ok,DebugInfo,Opts0} ->
Source = paranoid_absname(File),
Opts1 = [O || O <- Opts0, effects_code_generation(O)],
Chunks = [{<<"Dbgi">>, DebugInfo} | ExtraChunks],
{ok,Code} = beam_asm:module(Code0, Chunks, Source, Opts1, CompilerOpts),
CompileInfo = compile_info(File, Opts1),
{ok,Code} = beam_asm:module(Code0, Chunks, CompileInfo, CompilerOpts),
{ok,Code,St#compile{abstract_code=[]}};
{error,Es} ->
{error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
end.

compile_info(File, Opts) ->
IsSlim = member(slim, Opts),
IsDeterministic = member(deterministic, Opts),
Info0 = proplists:get_value(compile_info, Opts, []),
Info1 =
case paranoid_absname(File) of
[_|_] = Source when not IsSlim, not IsDeterministic ->
[{source,Source} | Info0];
_ ->
Info0
end,
Info2 =
case IsDeterministic of
false -> [{options,proplists:delete(compile_info, Opts)} | Info1];
true -> Info1
end,
Info2.

paranoid_absname(""=File) ->
File;
paranoid_absname(File) ->
Expand Down
22 changes: 20 additions & 2 deletions lib/compiler/test/compile_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
app_test/1,appup_test/1,
debug_info/4, custom_debug_info/1,
debug_info/4, custom_debug_info/1, custom_compile_info/1,
file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
other_output/1, kernel_listing/1, encrypted_abstr/1,
Expand All @@ -53,7 +53,8 @@ all() ->
strict_record, utf8_atoms, utf8_functions, extra_chunks,
cover, env, core_pp, core_roundtrip, asm, optimized_guards,
sys_pre_attributes, dialyzer, warnings, pre_load_check,
env_compiler_options, custom_debug_info, bc_options].
env_compiler_options, custom_debug_info, bc_options,
custom_compile_info].

groups() ->
[].
Expand Down Expand Up @@ -649,6 +650,23 @@ custom_debug_info(Config) when is_list(Config) ->
{ok,{simple,[{debug_info,{debug_info_v1,?MODULE,error}}]}} =
beam_lib:chunks(ErrorBin, [debug_info]).

custom_compile_info(Config) when is_list(Config) ->
Anno = erl_anno:new(1),
Forms = [{attribute,Anno,module,custom_compile_info}],
Opts = [binary,{compile_info,[{another,version}]}],

{ok,custom_compile_info,Bin} = compile:forms(Forms, Opts),
{ok,{custom_compile_info,[{compile_info,CompileInfo}]}} =
beam_lib:chunks(Bin, [compile_info]),
version = proplists:get_value(another, CompileInfo),
CompileOpts = proplists:get_value(options, CompileInfo),
undefined = proplists:get_value(compile_info, CompileOpts),

{ok,custom_compile_info,DetBin} = compile:forms(Forms, [deterministic|Opts]),
{ok,{custom_compile_info,[{compile_info,DetInfo}]}} =
beam_lib:chunks(DetBin, [compile_info]),
version = proplists:get_value(another, DetInfo).

cover(Config) when is_list(Config) ->
io:format("~p\n", [compile:options()]),
ok.
Expand Down

0 comments on commit 9bac40f

Please sign in to comment.