1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% Purpose: Run the Erlang compiler. 21 22-module(compile). 23 24%% High-level interface. 25-export([file/1,file/2,noenv_file/2,format_error/1]). 26-export([forms/1,forms/2,noenv_forms/2]). 27-export([output_generated/1,noenv_output_generated/1]). 28-export([options/0]). 29-export([env_compiler_options/0]). 30 31%% Erlc interface. 32-export([compile/3,compile_asm/3,compile_core/3,compile_abstr/3]). 33 34%% Utility functions for compiler passes. 35-export([run_sub_passes/2]). 36 37-export_type([option/0]). 38-export_type([forms/0]). 39 40-include("erl_compile.hrl"). 41-include("core_parse.hrl"). 42 43-import(lists, [member/2,reverse/1,reverse/2,keyfind/3,last/1, 44 map/2,flatmap/2,flatten/1,foreach/2,foldr/3,any/2]). 45 46-define(SUB_PASS_TIMES, compile__sub_pass_times). 47 48%%---------------------------------------------------------------------- 49 50-type abstract_code() :: [erl_parse:abstract_form()]. 51 52%% Internal representations used for 'from_asm' compilation can also be valid, 53%% but have no relevant types defined. 54-type forms() :: abstract_code() | cerl:c_module(). 55 56-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}. 57 58-type error_description() :: erl_lint:error_description(). 59-type error_info() :: erl_lint:error_info(). 60-type errors() :: [{file:filename(), [error_info()]}]. 61-type warnings() :: [{file:filename(), [error_info()]}]. 62-type mod_ret() :: {'ok', module()} 63 | {'ok', module(), cerl:c_module()} %% with option 'to_core' 64 | {'ok', %% with option 'to_pp' 65 module() | [], %% module() if 'to_exp' 66 abstract_code()} 67 | {'ok', module(), warnings()}. 68-type bin_ret() :: {'ok', module(), binary()} 69 | {'ok', module(), binary(), warnings()}. 70-type err_ret() :: 'error' | {'error', errors(), warnings()}. 71-type comp_ret() :: mod_ret() | bin_ret() | err_ret(). 72 73 74%%---------------------------------------------------------------------- 75 76%% 77%% Exported functions 78%% 79 80 81%% file(FileName) 82%% file(FileName, Options) 83%% Compile the module in file FileName. 84 85-define(DEFAULT_OPTIONS, [verbose,report_errors,report_warnings]). 86 87-spec file(module() | file:filename()) -> comp_ret(). 88 89file(File) -> file(File, ?DEFAULT_OPTIONS). 90 91-spec file(module() | file:filename(), [option()] | option()) -> comp_ret(). 92 93file(File, Opts) when is_list(Opts) -> 94 do_compile({file,File}, Opts++env_default_opts()); 95file(File, Opt) -> 96 file(File, [Opt|?DEFAULT_OPTIONS]). 97 98-spec forms(abstract_code()) -> comp_ret(). 99 100forms(Forms) -> forms(Forms, ?DEFAULT_OPTIONS). 101 102-spec forms(forms(), [option()] | option()) -> comp_ret(). 103 104forms(Forms, Opts) when is_list(Opts) -> 105 do_compile({forms,Forms}, [binary|Opts++env_default_opts()]); 106forms(Forms, Opt) when is_atom(Opt) -> 107 forms(Forms, [Opt|?DEFAULT_OPTIONS]). 108 109%% Given a list of compilation options, returns true if compile:file/2 110%% would have generated a Beam file, false otherwise (if only a binary or a 111%% listing file would have been generated). 112 113-spec output_generated([option()]) -> boolean(). 114 115output_generated(Opts) -> 116 noenv_output_generated(Opts++env_default_opts()). 117 118%% 119%% Variants of the same function that don't consult ERL_COMPILER_OPTIONS 120%% for default options. 121%% 122 123-spec noenv_file(module() | file:filename(), [option()] | option()) -> comp_ret(). 124 125noenv_file(File, Opts) when is_list(Opts) -> 126 do_compile({file,File}, Opts); 127noenv_file(File, Opt) -> 128 noenv_file(File, [Opt|?DEFAULT_OPTIONS]). 129 130-spec noenv_forms(forms(), [option()] | option()) -> comp_ret(). 131 132noenv_forms(Forms, Opts) when is_list(Opts) -> 133 do_compile({forms,Forms}, [binary|Opts]); 134noenv_forms(Forms, Opt) when is_atom(Opt) -> 135 noenv_forms(Forms, [Opt|?DEFAULT_OPTIONS]). 136 137-spec noenv_output_generated([option()]) -> boolean(). 138 139noenv_output_generated(Opts) -> 140 {_,Passes} = passes(file, expand_opts(Opts)), 141 any(fun ({save_binary,_T,_F}) -> true; 142 (_Other) -> false 143 end, Passes). 144 145%% 146%% Retrieve ERL_COMPILER_OPTIONS as a list of terms 147%% 148 149-spec env_compiler_options() -> [term()]. 150 151env_compiler_options() -> env_default_opts(). 152 153 154%%% 155%%% Run sub passes from a compiler pass. 156%%% 157 158-spec run_sub_passes([term()], term()) -> term(). 159 160run_sub_passes(Ps, St) -> 161 case get(?SUB_PASS_TIMES) of 162 undefined -> 163 Runner = fun(_Name, Run, S) -> Run(S) end, 164 run_sub_passes_1(Ps, Runner, St); 165 Times when is_list(Times) -> 166 Runner = fun(Name, Run, S0) -> 167 T1 = erlang:monotonic_time(), 168 S = Run(S0), 169 T2 = erlang:monotonic_time(), 170 put(?SUB_PASS_TIMES, 171 [{Name,T2-T1}|get(?SUB_PASS_TIMES)]), 172 S 173 end, 174 run_sub_passes_1(Ps, Runner, St) 175 end. 176 177%% 178%% Local functions 179%% 180 181-define(pass(P), {P,fun P/2}). 182-define(pass(P,T), {P,fun T/1,fun P/2}). 183 184env_default_opts() -> 185 Key = "ERL_COMPILER_OPTIONS", 186 case os:getenv(Key) of 187 false -> []; 188 Str when is_list(Str) -> 189 case erl_scan:string(Str) of 190 {ok,Tokens,_} -> 191 Dot = {dot, erl_anno:new(1)}, 192 case erl_parse:parse_term(Tokens ++ [Dot]) of 193 {ok,List} when is_list(List) -> List; 194 {ok,Term} -> [Term]; 195 {error,_Reason} -> 196 io:format("Ignoring bad term in ~s\n", [Key]), 197 [] 198 end; 199 {error, {_,_,_Reason}, _} -> 200 io:format("Ignoring bad term in ~s\n", [Key]), 201 [] 202 end 203 end. 204 205do_compile(Input, Opts0) -> 206 Opts = expand_opts(Opts0), 207 IntFun = internal_fun(Input, Opts), 208 209 %% Some tools, like Dialyzer, has already spawned workers 210 %% and spawning extra workers actually slow the compilation 211 %% down instead of speeding it up, so we provide a mechanism 212 %% to bypass the compiler process. 213 case lists:member(no_spawn_compiler_process, Opts) of 214 true -> 215 IntFun(); 216 false -> 217 {Pid,Ref} = 218 spawn_monitor(fun() -> 219 exit(IntFun()) 220 end), 221 receive 222 {'DOWN',Ref,process,Pid,Rep} -> Rep 223 end 224 end. 225 226internal_fun(Input, Opts) -> 227 fun() -> 228 try 229 internal(Input, Opts) 230 catch 231 Class:Reason:Stk -> 232 internal_error(Class, Reason, Stk) 233 end 234 end. 235 236internal_error(Class, Reason, Stk) -> 237 Error = ["\n*** Internal compiler error ***\n", 238 format_error_reason(Class, Reason, Stk), 239 "\n"], 240 io:put_chars(Error), 241 error. 242 243expand_opts(Opts0) -> 244 %% {debug_info_key,Key} implies debug_info. 245 Opts = case {proplists:get_value(debug_info_key, Opts0), 246 proplists:get_value(encrypt_debug_info, Opts0), 247 proplists:get_value(debug_info, Opts0)} of 248 {undefined,undefined,_} -> Opts0; 249 {_,_,undefined} -> [debug_info|Opts0]; 250 {_,_,_} -> Opts0 251 end, 252 %% iff,unless processing is to complex... 253 Opts1 = case proplists:is_defined(makedep_side_effect,Opts) of 254 true -> proplists:delete(makedep,Opts); 255 false -> Opts 256 end, 257 foldr(fun expand_opt/2, [], Opts1). 258 259expand_opt(basic_validation, Os) -> 260 [no_code_generation,to_pp,binary|Os]; 261expand_opt(strong_validation, Os) -> 262 [no_code_generation,to_kernel,binary|Os]; 263expand_opt(report, Os) -> 264 [report_errors,report_warnings|Os]; 265expand_opt(return, Os) -> 266 [return_errors,return_warnings|Os]; 267expand_opt(no_bsm3, Os) -> 268 %% The new bsm pass requires bsm3 instructions. 269 [no_bsm3,no_bsm_opt|expand_opt(no_bsm4, Os)]; 270expand_opt(no_bsm4, Os) -> 271 %% bsm4 instructions are only used when type optimization has determined 272 %% that a match instruction won't fail. 273 expand_opt(no_type_opt, Os); 274expand_opt(r18, Os) -> 275 expand_opt_before_21(Os); 276expand_opt(r19, Os) -> 277 expand_opt_before_21(Os); 278expand_opt(r20, Os) -> 279 expand_opt_before_21(Os); 280expand_opt(r21, Os) -> 281 expand_opt(r22, [no_put_tuple2 | expand_opt(no_bsm3, Os)]); 282expand_opt(r22, Os) -> 283 expand_opt(r23, [no_shared_fun_wrappers, no_swap | expand_opt(no_bsm4, Os)]); 284expand_opt(r23, Os) -> 285 expand_opt(no_make_fun3, [no_ssa_opt_float, no_recv_opt, no_init_yregs | Os]); 286expand_opt(no_make_fun3, Os) -> 287 [no_make_fun3, no_fun_opt | Os]; 288expand_opt({debug_info_key,_}=O, Os) -> 289 [encrypt_debug_info,O|Os]; 290expand_opt(no_type_opt=O, Os) -> 291 %% Be sure to keep the no_type_opt option so that it will 292 %% be recorded in the BEAM file, allowing the test suites 293 %% to recompile the file with this option. 294 [O,no_ssa_opt_type_start, 295 no_ssa_opt_type_continue, 296 no_ssa_opt_type_finish | Os]; 297expand_opt(no_module_opt=O, Os) -> 298 [O,no_recv_opt | Os]; 299expand_opt(O, Os) -> [O|Os]. 300 301expand_opt_before_21(Os) -> 302 [no_init_yregs, no_make_fun3, no_fun_opt, 303 no_shared_fun_wrappers, no_swap, 304 no_put_tuple2, no_get_hd_tl, no_ssa_opt_record, 305 no_utf8_atoms, no_recv_opt | expand_opt(no_bsm3, Os)]. 306 307 308-spec format_error(error_description()) -> iolist(). 309 310format_error(no_crypto) -> 311 "this system is not configured with crypto support."; 312format_error(bad_crypto_key) -> 313 "invalid crypto key."; 314format_error(no_crypto_key) -> 315 "no crypto key supplied."; 316format_error({open,E}) -> 317 io_lib:format("open error '~ts'", [file:format_error(E)]); 318format_error({epp,E}) -> 319 epp:format_error(E); 320format_error(write_error) -> 321 "error writing file"; 322format_error({write_error, Error}) -> 323 io_lib:format("error writing file: ~ts", [file:format_error(Error)]); 324format_error({rename,From,To,Error}) -> 325 io_lib:format("failed to rename ~ts to ~ts: ~ts", 326 [From,To,file:format_error(Error)]); 327format_error({parse_transform,M,{C,R,Stk}}) -> 328 E = format_error_reason(C, R, Stk), 329 io_lib:format("error in parse transform '~ts':\n~ts", [M, E]); 330format_error({undef_parse_transform,M}) -> 331 io_lib:format("undefined parse transform '~ts'", [M]); 332format_error({core_transform,M,{C,R,Stk}}) -> 333 E = format_error_reason(C, R, Stk), 334 io_lib:format("error in core transform '~s':\n~ts", [M, E]); 335format_error({crash,Pass,Reason,Stk}) -> 336 io_lib:format("internal error in pass ~p:\n~ts", [Pass,format_error_reason({Reason, Stk})]); 337format_error({bad_return,Pass,Reason}) -> 338 io_lib:format("internal error in pass ~p: bad return value:\n~tP", [Pass,Reason,20]); 339format_error({module_name,Mod,Filename}) -> 340 io_lib:format("Module name '~s' does not match file name '~ts'", [Mod,Filename]). 341 342format_error_reason({Reason, Stack}) when is_list(Stack) -> 343 format_error_reason(error, Reason, Stack). 344 345format_error_reason(Class, Reason, Stack) -> 346 StackFun = fun 347 (escript, run, 2) -> true; 348 (escript, start, 1) -> true; 349 (init, start_it, 1) -> true; 350 (init, start_em, 1) -> true; 351 (_Mod, _Fun, _Arity) -> false 352 end, 353 FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end, 354 Opts = #{stack_trim_fun => StackFun, 355 format_fun => FormatFun}, 356 erl_error:format_exception(Class, Reason, Stack, Opts). 357 358%% The compile state record. 359-record(compile, {filename="" :: file:filename(), 360 dir="" :: file:filename(), 361 base="" :: file:filename(), 362 ifile="" :: file:filename(), 363 ofile="" :: file:filename(), 364 module=[] :: module() | [], 365 abstract_code=[] :: abstract_code(), %Abstract code for debugger. 366 options=[] :: [option()], %Options for compilation 367 mod_options=[] :: [option()], %Options for module_info 368 encoding=none :: none | epp:source_encoding(), 369 errors=[] :: errors(), 370 warnings=[] :: warnings(), 371 extra_chunks=[] :: [{binary(), binary()}]}). 372 373internal({forms,Forms}, Opts0) -> 374 {_,Ps} = passes(forms, Opts0), 375 Source = proplists:get_value(source, Opts0, ""), 376 Opts1 = proplists:delete(source, Opts0), 377 Compile = build_compile(Opts1), 378 NewForms = case with_columns(Opts0) of 379 true -> 380 Forms; 381 false -> 382 strip_columns(Forms) 383 end, 384 internal_comp(Ps, NewForms, Source, "", Compile); 385internal({file,File}, Opts) -> 386 {Ext,Ps} = passes(file, Opts), 387 Compile = build_compile(Opts), 388 internal_comp(Ps, none, File, Ext, Compile). 389 390build_compile(Opts0) -> 391 ExtraChunks = proplists:get_value(extra_chunks, Opts0, []), 392 Opts1 = proplists:delete(extra_chunks, Opts0), 393 #compile{options=Opts1,mod_options=Opts1,extra_chunks=ExtraChunks}. 394 395internal_comp(Passes, Code0, File, Suffix, St0) -> 396 Dir = filename:dirname(File), 397 Base = filename:basename(File, Suffix), 398 St1 = St0#compile{filename=File, dir=Dir, base=Base, 399 ifile=erlfile(Dir, Base, Suffix), 400 ofile=objfile(Base, St0)}, 401 Run = runner(File, St1), 402 case fold_comp(Passes, Run, Code0, St1) of 403 {ok,Code,St2} -> comp_ret_ok(Code, St2); 404 {error,St2} -> comp_ret_err(St2) 405 end. 406 407fold_comp([{delay,Ps0}|Passes], Run, Code, #compile{options=Opts}=St) -> 408 Ps = select_passes(Ps0, Opts) ++ Passes, 409 fold_comp(Ps, Run, Code, St); 410fold_comp([{Name,Test,Pass}|Ps], Run, Code, St) -> 411 case Test(St) of 412 false -> %Pass is not needed. 413 fold_comp(Ps, Run, Code, St); 414 true -> %Run pass in the usual way. 415 fold_comp([{Name,Pass}|Ps], Run, Code, St) 416 end; 417fold_comp([{Name,Pass}|Ps], Run, Code0, St0) -> 418 try Run({Name,Pass}, Code0, St0) of 419 {ok,Code,St1} -> 420 fold_comp(Ps, Run, Code, St1); 421 {error,_St1}=Error -> 422 Error 423 catch 424 error:Reason:Stk -> 425 Es = [{St0#compile.ifile,[{none,?MODULE,{crash,Name,Reason,Stk}}]}], 426 {error,St0#compile{errors=St0#compile.errors ++ Es}} 427 end; 428fold_comp([], _Run, Code, St) -> {ok,Code,St}. 429 430run_sub_passes_1([{Name,Run}|Ps], Runner, St0) 431 when is_atom(Name), is_function(Run, 1) -> 432 try Runner(Name, Run, St0) of 433 St -> 434 run_sub_passes_1(Ps, Runner, St) 435 catch 436 C:E:Stk -> 437 io:format("Sub pass ~s\n", [Name]), 438 erlang:raise(C, E, Stk) 439 end; 440run_sub_passes_1([], _, St) -> St. 441 442runner(File, #compile{options=Opts}) -> 443 Run0 = fun({_Name,Fun}, Code, St) -> 444 Fun(Code, St) 445 end, 446 Run1 = case member(time, Opts) of 447 true -> 448 case File of 449 none -> ok; 450 _ -> io:format("Compiling ~ts\n", [File]) 451 end, 452 fun run_tc/3; 453 false -> 454 Run0 455 end, 456 case keyfind(eprof, 1, Opts) of 457 {eprof,EprofPass} -> 458 fun(P, Code, St) -> 459 run_eprof(P, Code, EprofPass, St) 460 end; 461 false -> 462 Run1 463 end. 464 465run_tc({Name,Fun}, Code, St) -> 466 OldTimes = put(?SUB_PASS_TIMES, []), 467 T1 = erlang:monotonic_time(), 468 Val = Fun(Code, St), 469 T2 = erlang:monotonic_time(), 470 Times = get(?SUB_PASS_TIMES), 471 case OldTimes of 472 undefined -> erase(?SUB_PASS_TIMES); 473 _ -> put(?SUB_PASS_TIMES, OldTimes) 474 end, 475 Elapsed = erlang:convert_time_unit(T2 - T1, native, microsecond), 476 Mem0 = erts_debug:flat_size(Val)*erlang:system_info(wordsize), 477 Mem = lists:flatten(io_lib:format("~.1f kB", [Mem0/1024])), 478 io:format(" ~-30s: ~10.3f s ~12s\n", 479 [Name,Elapsed/1000000,Mem]), 480 print_times(Times, Name), 481 Val. 482 483print_times(Times0, Name) -> 484 Fam0 = rel2fam(Times0), 485 Fam1 = [{W,lists:sum(Times)} || {W,Times} <- Fam0], 486 Fam = reverse(lists:keysort(2, Fam1)), 487 Total = case lists:sum([T || {_,T} <- Fam]) of 488 0 -> 1; 489 Total0 -> Total0 490 end, 491 case Fam of 492 [] -> 493 ok; 494 [_|_] -> 495 io:format(" %% Sub passes of ~s from slowest to fastest:\n", [Name]), 496 print_times_1(Fam, Total) 497 end. 498 499print_times_1([{Name,T}|Ts], Total) -> 500 Elapsed = erlang:convert_time_unit(T, native, microsecond), 501 io:format(" ~-27s: ~10.3f s ~3w %\n", 502 [Name,Elapsed/1000000,round(100*T/Total)]), 503 print_times_1(Ts, Total); 504print_times_1([], _Total) -> ok. 505 506run_eprof({Name,Fun}, Code, Name, St) -> 507 io:format("~p: Running eprof\n", [Name]), 508 c:appcall(tools, eprof, start_profiling, [[self()]]), 509 try 510 Fun(Code, St) 511 after 512 c:appcall(tools, eprof, stop_profiling, []), 513 c:appcall(tools, eprof, analyze, []) 514 end; 515run_eprof({_,Fun}, Code, _, St) -> 516 Fun(Code, St). 517 518comp_ret_ok(Code, #compile{warnings=Warn0,module=Mod,options=Opts}=St) -> 519 Warn1 = filter_warnings(Warn0, Opts), 520 case werror(St) of 521 true -> 522 case member(report_warnings, Opts) of 523 true -> 524 io:format("~p: warnings being treated as errors\n", 525 [?MODULE]); 526 false -> 527 ok 528 end, 529 comp_ret_err(St); 530 false -> 531 Warn = messages_per_file(Warn1), 532 report_warnings(St#compile{warnings = Warn}), 533 Ret1 = case member(binary, Opts) andalso 534 not member(no_code_generation, Opts) of 535 true -> [Code]; 536 false -> [] 537 end, 538 Ret2 = case member(return_warnings, Opts) of 539 true -> Ret1 ++ [Warn]; 540 false -> Ret1 541 end, 542 list_to_tuple([ok,Mod|Ret2]) 543 end. 544 545comp_ret_err(#compile{warnings=Warn0,errors=Err0,options=Opts}=St) -> 546 Warn = messages_per_file(Warn0), 547 Err = messages_per_file(Err0), 548 report_errors(St#compile{errors=Err}), 549 report_warnings(St#compile{warnings=Warn}), 550 case member(return_errors, Opts) of 551 true -> {error,Err,Warn}; 552 false -> error 553 end. 554 555not_werror(St) -> not werror(St). 556 557werror(#compile{options=Opts,warnings=Ws}) -> 558 Ws =/= [] andalso member(warnings_as_errors, Opts). 559 560%% messages_per_file([{File,[Message]}]) -> [{File,[Message]}] 561messages_per_file(Ms) -> 562 T = lists:sort([{File,M} || {File,Messages} <- Ms, M <- Messages]), 563 PrioMs = [erl_scan, epp, erl_parse], 564 {Prio0, Rest} = 565 lists:mapfoldl(fun(M, A) -> 566 lists:partition(fun({_,{_,Mod,_}}) -> Mod =:= M; 567 (_) -> false 568 end, A) 569 end, T, PrioMs), 570 Prio = lists:sort(fun({_,{L1,_,_}}, {_,{L2,_,_}}) -> L1 =< L2 end, 571 lists:append(Prio0)), 572 flatmap(fun mpf/1, [Prio, Rest]). 573 574mpf(Ms) -> 575 [{File,[M || {F,M} <- Ms, F =:= File]} || 576 File <- lists:usort([F || {F,_} <- Ms])]. 577 578%% passes(forms|file, [Option]) -> {Extension,[{Name,PassFun}]} 579%% Figure out the extension of the input file and which passes 580%% that need to be run. 581 582passes(Type, Opts) -> 583 {Ext,Passes0} = passes_1(Opts), 584 585 Passes1 = case Type of 586 file -> 587 Passes0; 588 forms -> 589 fix_first_pass(Passes0) 590 end, 591 592 Passes2 = select_passes(Passes1, Opts), 593 594 %% If the last pass saves the resulting binary to a file, 595 %% insert a first pass to remove the file. 596 Passes = case last(Passes2) of 597 {save_binary, _TestFun, _Fun} -> 598 [?pass(remove_file) | Passes2]; 599 _ -> 600 Passes2 601 end, 602 603 {Ext, Passes}. 604 605passes_1([Opt|Opts]) -> 606 case pass(Opt) of 607 {_,_}=Res -> Res; 608 none -> passes_1(Opts) 609 end; 610passes_1([]) -> 611 {".erl",[?pass(parse_module)|standard_passes()]}. 612 613pass(from_abstr) -> 614 {".abstr", [?pass(consult_abstr) | abstr_passes(non_verified_abstr)]}; 615pass(from_core) -> 616 {".core",[?pass(parse_core)|core_passes(non_verified_core)]}; 617pass(from_asm) -> 618 {".S",[?pass(beam_consult_asm)|asm_passes()]}; 619pass(_) -> none. 620 621%% For compilation from forms, replace the first pass with a pass 622%% that retrieves the module name. The module name is needed for 623%% proper diagnostics. 624 625fix_first_pass([{consult_abstr, _} | Passes]) -> 626 %% Simply remove this pass. The module name will be set after 627 %% running the v3_core pass. 628 Passes; 629fix_first_pass([{parse_core,_}|Passes]) -> 630 [?pass(get_module_name_from_core)|Passes]; 631fix_first_pass([{beam_consult_asm,_}|Passes]) -> 632 [?pass(get_module_name_from_asm)|Passes]; 633fix_first_pass([_|Passes]) -> 634 %% When compiling from abstract code, the module name 635 %% will be set after running the v3_core pass. 636 Passes. 637 638 639%% select_passes([Command], Opts) -> [{Name,Function}] 640%% Interpret the lists of commands to return a pure list of passes. 641%% 642%% Command can be one of: 643%% 644%% {pass,Mod} Will be expanded to a call to the external 645%% function Mod:module(Code, Options). This 646%% function must transform the code and return 647%% {ok,NewCode} or {ok,NewCode,Warnings}. 648%% Example: {pass,beam_ssa_codegen} 649%% 650%% {Name,Fun} Name is an atom giving the name of the pass. 651%% Fun is an 'fun' taking one argument: a #compile{} record. 652%% The fun should return {ok,NewCompileRecord} or 653%% {error,NewCompileRecord}. 654%% Note: ?pass(Name) is equvivalent to {Name,fun Name/1}. 655%% Example: ?pass(parse_module) 656%% 657%% {Name,Test,Fun} Like {Name,Fun} above, but the pass will be run 658%% (and listed by the `time' option) only if Test(St) 659%% returns true. 660%% 661%% {src_listing,Ext} Produces an Erlang source listing with the 662%% the file extension Ext. (Ext should not contain 663%% a period.) No more passes will be run. 664%% 665%% {listing,Ext} Produce an listing of the terms in the internal 666%% representation. The extension of the listing 667%% file will be Ext. (Ext should not contain 668%% a period.) No more passes will be run. 669%% 670%% done End compilation at this point. 671%% 672%% {done,Ext} End compilation at this point. Produce a listing 673%% as with {listing,Ext}, unless 'binary' is 674%% specified, in which case the current 675%% representation of the code is returned without 676%% creating an output file. 677%% 678%% {iff,Flag,Cmd} If the given Flag is given in the option list, 679%% Cmd will be interpreted as a command. 680%% Otherwise, Cmd will be ignored. 681%% Example: {iff,dcg,{listing,"codegen}} 682%% 683%% {unless,Flag,Cmd} If the given Flag is NOT given in the option list, 684%% Cmd will be interpreted as a command. 685%% Otherwise, Cmd will be ignored. 686%% Example: {unless,no_kernopt,{pass,sys_kernopt}} 687%% 688 689select_passes([{pass,Mod}|Ps], Opts) -> 690 F = fun(Code0, St) -> 691 case Mod:module(Code0, St#compile.options) of 692 {ok,Code} -> 693 {ok,Code,St}; 694 {ok,Code,Ws} -> 695 {ok,Code,St#compile{warnings=St#compile.warnings++Ws}}; 696 Other -> 697 Es = [{St#compile.ifile,[{none,?MODULE,{bad_return,Mod,Other}}]}], 698 {error,St#compile{errors=St#compile.errors ++ Es}} 699 end 700 end, 701 [{Mod,F}|select_passes(Ps, Opts)]; 702select_passes([{_,Fun}=P|Ps], Opts) when is_function(Fun) -> 703 [P|select_passes(Ps, Opts)]; 704select_passes([{_,Test,Fun}=P|Ps], Opts) when is_function(Test), 705 is_function(Fun) -> 706 [P|select_passes(Ps, Opts)]; 707select_passes([{src_listing,Ext}|_], _Opts) -> 708 [{listing,fun (Code, St) -> src_listing(Ext, Code, St) end}]; 709select_passes([{listing,Ext}|_], _Opts) -> 710 [{listing,fun (Code, St) -> listing(Ext, Code, St) end}]; 711select_passes([done|_], _Opts) -> 712 []; 713select_passes([{done,Ext}|_], Opts) -> 714 select_passes([{unless,binary,{listing,Ext}}], Opts); 715select_passes([{iff,Flag,Pass}|Ps], Opts) -> 716 select_cond(Flag, true, Pass, Ps, Opts); 717select_passes([{unless,Flag,Pass}|Ps], Opts) -> 718 select_cond(Flag, false, Pass, Ps, Opts); 719select_passes([{delay,Passes0}|Ps], Opts) when is_list(Passes0) -> 720 %% Delay evaluation of compiler options and which compiler passes to run. 721 %% Since we must know beforehand whether a listing will be produced, we 722 %% will go through the list of passes and evaluate all conditions that 723 %% select a list pass. 724 case select_list_passes(Passes0, Opts) of 725 {done,Passes} -> 726 [{delay,Passes}]; 727 {not_done,Passes} -> 728 [{delay,Passes}|select_passes(Ps, Opts)] 729 end; 730select_passes([], _Opts) -> 731 []; 732select_passes([List|Ps], Opts) when is_list(List) -> 733 case select_passes(List, Opts) of 734 [] -> select_passes(Ps, Opts); 735 Nested -> 736 case last(Nested) of 737 {listing,_Fun} -> Nested; 738 _Other -> Nested ++ select_passes(Ps, Opts) 739 end 740 end. 741 742select_cond(Flag, ShouldBe, Pass, Ps, Opts) -> 743 ShouldNotBe = not ShouldBe, 744 case member(Flag, Opts) of 745 ShouldBe -> select_passes([Pass|Ps], Opts); 746 ShouldNotBe -> select_passes(Ps, Opts) 747 end. 748 749%% select_list_passes([Pass], Opts) -> {done,[Pass]} | {not_done,[Pass]} 750%% Evaluate all conditions having to do with listings in the list of 751%% passes. 752 753select_list_passes(Ps, Opts) -> 754 select_list_passes_1(Ps, Opts, []). 755 756select_list_passes_1([{iff,Flag,{listing,_}=Listing}|Ps], Opts, Acc) -> 757 case member(Flag, Opts) of 758 true -> {done,reverse(Acc, [Listing])}; 759 false -> select_list_passes_1(Ps, Opts, Acc) 760 end; 761select_list_passes_1([{iff,Flag,{done,Ext}}|Ps], Opts, Acc) -> 762 case member(Flag, Opts) of 763 false -> 764 select_list_passes_1(Ps, Opts, Acc); 765 true -> 766 {done,case member(binary, Opts) of 767 false -> reverse(Acc, [{listing,Ext}]); 768 true -> reverse(Acc) 769 end} 770 end; 771select_list_passes_1([{iff=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) -> 772 case select_list_passes(List0, Opts) of 773 {done,List} -> {done,reverse(Acc) ++ List}; 774 {not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc]) 775 end; 776select_list_passes_1([{unless=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) -> 777 case select_list_passes(List0, Opts) of 778 {done,List} -> {done,reverse(Acc) ++ List}; 779 {not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc]) 780 end; 781select_list_passes_1([P|Ps], Opts, Acc) -> 782 select_list_passes_1(Ps, Opts, [P|Acc]); 783select_list_passes_1([], _, Acc) -> 784 {not_done,reverse(Acc)}. 785 786%% The standard passes (almost) always run. 787 788standard_passes() -> 789 [?pass(transform_module), 790 791 {iff,makedep_side_effect,?pass(makedep_and_output)}, 792 {iff,makedep,[ 793 ?pass(makedep), 794 {unless,binary,?pass(makedep_output)} 795 ]}, 796 {iff,makedep,done}, 797 798 {iff,'dpp',{listing,"pp"}}, 799 ?pass(lint_module), 800 801 {iff,'P',{src_listing,"P"}}, 802 {iff,'to_pp',{done,"P"}}, 803 804 {iff,'dabstr',{listing,"abstr"}} 805 | abstr_passes(verified_abstr)]. 806 807abstr_passes(AbstrStatus) -> 808 case AbstrStatus of 809 non_verified_abstr -> [{unless, no_lint, ?pass(lint_module)}]; 810 verified_abstr -> [] 811 end ++ 812 [ 813 %% Add all -compile() directives to #compile.options 814 ?pass(compile_directives), 815 816 {delay,[{iff,debug_info,?pass(save_abstract_code)}]}, 817 818 ?pass(expand_records), 819 {iff,'dexp',{listing,"expand"}}, 820 {iff,'E',{src_listing,"E"}}, 821 {iff,'to_exp',{done,"E"}}, 822 823 %% Conversion to Core Erlang. 824 ?pass(core), 825 {iff,'dcore',{listing,"core"}}, 826 {iff,'to_core0',{done,"core"}} 827 | core_passes(verified_core)]. 828 829core_passes(CoreStatus) -> 830 %% Optimization and transforms of Core Erlang code. 831 case CoreStatus of 832 non_verified_core -> 833 [?pass(core_lint_module), 834 {unless,no_core_prepare,{pass,sys_core_prepare}}, 835 {iff,dprep,{listing,"prepare"}}]; 836 verified_core -> 837 [{iff,clint0,?pass(core_lint_module)}] 838 end ++ 839 [ 840 {delay, 841 [{unless,no_copt, 842 [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/2}, 843 {iff,doldinline,{listing,"oldinline"}}, 844 {unless,no_fold,{pass,sys_core_fold}}, 845 {iff,dcorefold,{listing,"corefold"}}, 846 {core_inline_module,fun test_core_inliner/1,fun core_inline_module/2}, 847 {iff,dinline,{listing,"inline"}}, 848 {core_fold_after_inlining,fun test_any_inliner/1, 849 fun core_fold_module_after_inlining/2}, 850 {iff,dcopt,{listing,"copt"}}, 851 {unless,no_alias,{pass,sys_core_alias}}, 852 {iff,dalias,{listing,"core_alias"}}, 853 ?pass(core_transforms)]}, 854 {iff,'to_core',{done,"core"}}]} 855 | kernel_passes()]. 856 857kernel_passes() -> 858 %% Optimizations that must be done after all other optimizations. 859 [{pass,sys_core_bsm}, 860 {iff,dcbsm,{listing,"core_bsm"}}, 861 862 {iff,clint,?pass(core_lint_module)}, 863 864 %% Kernel Erlang and code generation. 865 ?pass(v3_kernel), 866 {iff,dkern,{listing,"kernel"}}, 867 {iff,'to_kernel',{done,"kernel"}}, 868 {pass,beam_kernel_to_ssa}, 869 {iff,dssa,{listing,"ssa"}}, 870 {iff,ssalint,{pass,beam_ssa_lint}}, 871 {delay, 872 [{unless,no_bool_opt,{pass,beam_ssa_bool}}, 873 {iff,dbool,{listing,"bool"}}, 874 {unless,no_bool_opt,{iff,ssalint,{pass,beam_ssa_lint}}}, 875 876 {unless,no_share_opt,{pass,beam_ssa_share}}, 877 {iff,dssashare,{listing,"ssashare"}}, 878 {unless,no_share_opt,{iff,ssalint,{pass,beam_ssa_lint}}}, 879 880 {unless,no_recv_opt,{pass,beam_ssa_recv}}, 881 {iff,drecv,{listing,"recv"}}, 882 {unless,no_recv_opt,{iff,ssalint,{pass,beam_ssa_lint}}}, 883 884 {unless,no_bsm_opt,{pass,beam_ssa_bsm}}, 885 {iff,dssabsm,{listing,"ssabsm"}}, 886 {unless,no_bsm_opt,{iff,ssalint,{pass,beam_ssa_lint}}}, 887 888 {unless,no_fun_opt,{pass,beam_ssa_funs}}, 889 {iff,dssafuns,{listing,"ssafuns"}}, 890 {unless,no_fun_opt,{iff,ssalint,{pass,beam_ssa_lint}}}, 891 892 {unless,no_ssa_opt,{pass,beam_ssa_opt}}, 893 {iff,dssaopt,{listing,"ssaopt"}}, 894 {unless,no_ssa_opt,{iff,ssalint,{pass,beam_ssa_lint}}}, 895 896 {unless,no_throw_opt,{pass,beam_ssa_throw}}, 897 {iff,dthrow,{listing,"throw"}}, 898 {unless,no_throw_opt,{iff,ssalint,{pass,beam_ssa_lint}}}]}, 899 900 {pass,beam_ssa_pre_codegen}, 901 {iff,dprecg,{listing,"precodegen"}}, 902 {iff,ssalint,{pass,beam_ssa_lint}}, 903 {pass,beam_ssa_codegen}, 904 {iff,dcg,{listing,"codegen"}}, 905 {iff,doldcg,{listing,"codegen"}}, 906 ?pass(beam_validator_strong) 907 | asm_passes()]. 908 909asm_passes() -> 910 %% Assembly level optimisations. 911 [{delay, 912 [{pass,beam_a}, 913 {iff,da,{listing,"a"}}, 914 {unless,no_postopt, 915 [{pass,beam_block}, 916 {iff,dblk,{listing,"block"}}, 917 {unless,no_jopt,{pass,beam_jump}}, 918 {iff,djmp,{listing,"jump"}}, 919 {unless,no_peep_opt,{pass,beam_peep}}, 920 {iff,dpeep,{listing,"peep"}}, 921 {pass,beam_clean}, 922 {iff,dclean,{listing,"clean"}}, 923 {unless,no_stack_trimming,{pass,beam_trim}}, 924 {iff,dtrim,{listing,"trim"}}, 925 {pass,beam_flatten}]}, 926 927 %% If post optimizations are turned off, we still 928 %% need to do a few clean-ups to code. 929 {iff,no_postopt,[{pass,beam_clean}]}, 930 931 {iff,diffable,?pass(diffable)}, 932 {pass,beam_z}, 933 {iff,diffable,{listing,"S"}}, 934 {iff,dz,{listing,"z"}}, 935 {iff,dopt,{listing,"optimize"}}, 936 {iff,'S',{listing,"S"}}, 937 {iff,'to_asm',{done,"S"}}]}, 938 ?pass(beam_validator_weak), 939 ?pass(beam_asm) 940 | binary_passes()]. 941 942binary_passes() -> 943 [{iff,'to_dis',?pass(to_dis)}, 944 {unless,binary,?pass(save_binary,not_werror)} 945 ]. 946 947%%% 948%%% Compiler passes. 949%%% 950 951%% Remove the target file so we don't have an old one if the compilation fail. 952remove_file(Code, St) -> 953 _ = file:delete(St#compile.ofile), 954 {ok,Code,St}. 955 956-record(asm_module, {module, 957 exports, 958 labels, 959 functions=[], 960 attributes=[]}). 961 962preprocess_asm_forms(Forms) -> 963 R = #asm_module{}, 964 R1 = collect_asm(Forms, R), 965 {R1#asm_module.module, 966 {R1#asm_module.module, 967 R1#asm_module.exports, 968 R1#asm_module.attributes, 969 reverse(R1#asm_module.functions), 970 R1#asm_module.labels}}. 971 972collect_asm([{module,M} | Rest], R) -> 973 collect_asm(Rest, R#asm_module{module=M}); 974collect_asm([{exports,M} | Rest], R) -> 975 collect_asm(Rest, R#asm_module{exports=M}); 976collect_asm([{labels,M} | Rest], R) -> 977 collect_asm(Rest, R#asm_module{labels=M}); 978collect_asm([{function,A,B,C} | Rest0], R0) -> 979 {Code,Rest} = collect_asm_function(Rest0, []), 980 Func = {function,A,B,C,Code}, 981 R = R0#asm_module{functions=[Func | R0#asm_module.functions]}, 982 collect_asm(Rest, R); 983collect_asm([{attributes, Attr} | Rest], R) -> 984 collect_asm(Rest, R#asm_module{attributes=Attr}); 985collect_asm([], R) -> R. 986 987collect_asm_function([{function,_,_,_}|_]=Is, Acc) -> 988 {reverse(Acc),Is}; 989collect_asm_function([I|Is], Acc) -> 990 collect_asm_function(Is, [I|Acc]); 991collect_asm_function([], Acc) -> 992 {reverse(Acc),[]}. 993 994beam_consult_asm(_Code, St) -> 995 case file:consult(St#compile.ifile) of 996 {ok,Forms0} -> 997 Encoding = epp:read_encoding(St#compile.ifile), 998 {Module,Forms} = preprocess_asm_forms(Forms0), 999 {ok,Forms,St#compile{module=Module,encoding=Encoding}}; 1000 {error,E} -> 1001 Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}], 1002 {error,St#compile{errors=St#compile.errors ++ Es}} 1003 end. 1004 1005get_module_name_from_asm({Mod,_,_,_,_}=Asm, St) -> 1006 {ok,Asm,St#compile{module=Mod}}; 1007get_module_name_from_asm(Asm, St) -> 1008 %% Invalid Beam assembly code. Let it crash in a later pass. 1009 {ok,Asm,St}. 1010 1011parse_module(_Code, St) -> 1012 case do_parse_module(utf8, St) of 1013 {ok,_,_}=Ret -> 1014 Ret; 1015 {error,_}=Ret -> 1016 Ret 1017 end. 1018 1019do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) -> 1020 SourceName0 = proplists:get_value(source, Opts, File), 1021 SourceName = case member(deterministic, Opts) of 1022 true -> filename:basename(SourceName0); 1023 false -> SourceName0 1024 end, 1025 StartLocation = case with_columns(Opts) of 1026 true -> 1027 {1,1}; 1028 false -> 1029 1 1030 end, 1031 R = epp:parse_file(File, 1032 [{includes,[".",Dir|inc_paths(Opts)]}, 1033 {source_name, SourceName}, 1034 {macros,pre_defs(Opts)}, 1035 {default_encoding,DefEncoding}, 1036 {location,StartLocation}, 1037 extra]), 1038 case R of 1039 {ok,Forms0,Extra} -> 1040 Encoding = proplists:get_value(encoding, Extra), 1041 Forms = case with_columns(Opts ++ compile_options(Forms0)) of 1042 true -> 1043 Forms0; 1044 false -> 1045 strip_columns(Forms0) 1046 end, 1047 {ok,Forms,St#compile{encoding=Encoding}}; 1048 {error,E} -> 1049 Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}], 1050 {error,St#compile{errors=St#compile.errors ++ Es}} 1051 end. 1052 1053with_columns(Opts) -> 1054 case proplists:get_value(error_location, Opts, column) of 1055 column -> true; 1056 line -> false 1057 end. 1058 1059consult_abstr(_Code, St) -> 1060 case file:consult(St#compile.ifile) of 1061 {ok,Forms} -> 1062 Encoding = epp:read_encoding(St#compile.ifile), 1063 {ok,Forms,St#compile{encoding=Encoding}}; 1064 {error,E} -> 1065 Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}], 1066 {error,St#compile{errors=St#compile.errors ++ Es}} 1067 end. 1068 1069parse_core(_Code, St) -> 1070 case file:read_file(St#compile.ifile) of 1071 {ok,Bin} -> 1072 case core_scan:string(binary_to_list(Bin)) of 1073 {ok,Toks,_} -> 1074 case core_parse:parse(Toks) of 1075 {ok,Mod} -> 1076 Name = (Mod#c_module.name)#c_literal.val, 1077 {ok,Mod,St#compile{module=Name}}; 1078 {error,E} -> 1079 Es = [{St#compile.ifile,[E]}], 1080 {error,St#compile{errors=St#compile.errors ++ Es}} 1081 end; 1082 {error,E,_} -> 1083 Es = [{St#compile.ifile,[E]}], 1084 {error,St#compile{errors=St#compile.errors ++ Es}} 1085 end; 1086 {error,E} -> 1087 Es = [{St#compile.ifile,[{none,compile,{open,E}}]}], 1088 {error,St#compile{errors=St#compile.errors ++ Es}} 1089 end. 1090 1091get_module_name_from_core(Core, St) -> 1092 try 1093 Mod = cerl:concrete(cerl:module_name(Core)), 1094 {ok,Core,St#compile{module=Mod}} 1095 catch 1096 _:_ -> 1097 %% Invalid Core Erlang code. Let it crash in a later pass. 1098 {ok,Core,St} 1099 end. 1100 1101compile_options([{attribute,_L,compile,C}|Fs]) when is_list(C) -> 1102 C ++ compile_options(Fs); 1103compile_options([{attribute,_L,compile,C}|Fs]) -> 1104 [C|compile_options(Fs)]; 1105compile_options([_F|Fs]) -> compile_options(Fs); 1106compile_options([]) -> []. 1107 1108clean_parse_transforms(Fs) -> 1109 clean_parse_transforms_1(Fs, []). 1110 1111clean_parse_transforms_1([{attribute,L,compile,C0}|Fs], Acc) when is_list(C0) -> 1112 C = lists:filter(fun({parse_transform,_}) -> false; 1113 (_) -> true 1114 end, C0), 1115 clean_parse_transforms_1(Fs, [{attribute,L,compile,C}|Acc]); 1116clean_parse_transforms_1([{attribute,_,compile,{parse_transform,_}}|Fs], Acc) -> 1117 clean_parse_transforms_1(Fs, Acc); 1118clean_parse_transforms_1([F|Fs], Acc) -> 1119 clean_parse_transforms_1(Fs, [F|Acc]); 1120clean_parse_transforms_1([], Acc) -> reverse(Acc). 1121 1122transforms(Os) -> [ M || {parse_transform,M} <- Os ]. 1123 1124transform_module(Code0, #compile{options=Opt}=St) -> 1125 %% Extract compile options from code into options field. 1126 case transforms(Opt ++ compile_options(Code0)) of 1127 [] -> 1128 %% No parse transforms. 1129 {ok,Code0,St}; 1130 Ts -> 1131 %% Remove parse_transform attributes from the abstract code to 1132 %% prevent parse transforms to be run more than once. 1133 Code = clean_parse_transforms(Code0), 1134 foldl_transform(Ts, Code, St) 1135 end. 1136 1137foldl_transform([T|Ts], Code0, St) -> 1138 Name = "transform " ++ atom_to_list(T), 1139 case code:ensure_loaded(T) =:= {module,T} andalso 1140 erlang:function_exported(T, parse_transform, 2) of 1141 true -> 1142 Fun = fun(Code, S) -> 1143 T:parse_transform(Code, S#compile.options) 1144 end, 1145 Run = runner(none, St), 1146 StrippedCode = maybe_strip_columns(Code0, T, St), 1147 try Run({Name, Fun}, StrippedCode, St) of 1148 {error,Es,Ws} -> 1149 {error,St#compile{warnings=St#compile.warnings ++ Ws, 1150 errors=St#compile.errors ++ Es}}; 1151 {warning, Forms, Ws} -> 1152 foldl_transform(Ts, Forms, 1153 St#compile{warnings=St#compile.warnings ++ Ws}); 1154 Forms -> 1155 foldl_transform(Ts, Forms, St) 1156 catch 1157 Class:Reason:Stk -> 1158 Es = [{St#compile.ifile,[{none,compile, 1159 {parse_transform,T,{Class,Reason,Stk}}}]}], 1160 {error,St#compile{errors=St#compile.errors ++ Es}} 1161 end; 1162 false -> 1163 Es = [{St#compile.ifile,[{none,compile, 1164 {undef_parse_transform,T}}]}], 1165 {error,St#compile{errors=St#compile.errors ++ Es}} 1166 end; 1167foldl_transform([], Code, St) -> 1168 %% We may need to strip columns added by parse transforms before returning 1169 %% them back to the compiler. We pass ?MODULE as a bit of a hack to get the 1170 %% correct default. 1171 {ok, maybe_strip_columns(Code, ?MODULE, St), St}. 1172 1173%%% If a parse transform does not support column numbers it can say so using 1174%%% the parse_transform_info callback. The error_location is taken from both 1175%%% compiler options and from the parse transform and if either of them want 1176%%% to only use lines, we strip columns. 1177maybe_strip_columns(Code, T, St) -> 1178 PTErrorLocation = 1179 case erlang:function_exported(T, parse_transform_info, 0) of 1180 true -> 1181 maps:get(error_location, T:parse_transform_info(), column); 1182 false -> 1183 column 1184 end, 1185 ConfigErrorLocation = proplists:get_value(error_location, St#compile.options, column), 1186 if 1187 PTErrorLocation =:= line; ConfigErrorLocation =:= line -> 1188 strip_columns(Code); 1189 true -> Code 1190 end. 1191 1192strip_columns(Code) -> 1193 F = fun(A) -> erl_anno:set_location(erl_anno:line(A), A) end, 1194 [case Form of 1195 {eof,{Line,_Col}} -> 1196 {eof,Line}; 1197 {ErrorOrWarning,{{Line,_Col},Module,Reason}} 1198 when ErrorOrWarning =:= error; 1199 ErrorOrWarning =:= warning -> 1200 {ErrorOrWarning,{Line,Module,Reason}}; 1201 Form -> 1202 erl_parse:map_anno(F, Form) 1203 end || Form <- Code]. 1204 1205get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts]. 1206 1207core_transforms(Code, St) -> 1208 %% The options field holds the complete list of options at this 1209 Ts = get_core_transforms(St#compile.options), 1210 foldl_core_transforms(Ts, Code, St). 1211 1212foldl_core_transforms([T|Ts], Code0, St) -> 1213 Name = "core transform " ++ atom_to_list(T), 1214 Fun = fun(Code, S) -> T:core_transform(Code, S#compile.options) end, 1215 Run = runner(none, St), 1216 try Run({Name, Fun}, Code0, St) of 1217 Forms -> 1218 foldl_core_transforms(Ts, Forms, St) 1219 catch 1220 Class:Reason:Stk -> 1221 Es = [{St#compile.ifile,[{none,compile, 1222 {core_transform,T,{Class,Reason,Stk}}}]}], 1223 {error,St#compile{errors=St#compile.errors ++ Es}} 1224 end; 1225foldl_core_transforms([], Code, St) -> {ok,Code,St}. 1226 1227%%% Fetches the module name from a list of forms. The module attribute must 1228%%% be present. 1229get_module([{attribute,_,module,M} | _]) -> M; 1230get_module([_ | Rest]) -> 1231 get_module(Rest). 1232 1233%%% A #compile state is returned, where St.base has been filled in 1234%%% with the module name from Forms, as a string, in case it wasn't 1235%%% set in St (i.e., it was ""). 1236add_default_base(St, Forms) -> 1237 F = St#compile.filename, 1238 case F of 1239 "" -> 1240 M = get_module(Forms), 1241 St#compile{base=atom_to_list(M)}; 1242 _ -> 1243 St 1244 end. 1245 1246lint_module(Code, St) -> 1247 case erl_lint:module(Code, St#compile.ifile, St#compile.options) of 1248 {ok,Ws} -> 1249 %% Insert name of module as base name, if needed. This is 1250 %% for compile:forms to work with listing files. 1251 St1 = add_default_base(St, Code), 1252 {ok,Code,St1#compile{warnings=St1#compile.warnings ++ Ws}}; 1253 {error,Es,Ws} -> 1254 {error,St#compile{warnings=St#compile.warnings ++ Ws, 1255 errors=St#compile.errors ++ Es}} 1256 end. 1257 1258core_lint_module(Code, St) -> 1259 case core_lint:module(Code, St#compile.options) of 1260 {ok,Ws} -> 1261 {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}}; 1262 {error,Es,Ws} -> 1263 {error,St#compile{warnings=St#compile.warnings ++ Ws, 1264 errors=St#compile.errors ++ Es}} 1265 end. 1266 1267%% makedep + output and continue 1268makedep_and_output(Code0, St) -> 1269 {ok,DepCode,St1} = makedep(Code0,St), 1270 case makedep_output(DepCode, St1) of 1271 {ok,_IgnoreCode,St2} -> 1272 {ok,Code0,St2}; 1273 {error,St2} -> 1274 {error,St2} 1275 end. 1276 1277makedep(Code0, #compile{ifile=Ifile,ofile=Ofile,options=Opts}=St) -> 1278 1279 %% Get the target of the Makefile rule. 1280 Target0 = 1281 case proplists:get_value(makedep_target, Opts) of 1282 undefined -> 1283 %% The target is derived from the output filename: possibly 1284 %% remove the current working directory to obtain a relative 1285 %% path. 1286 shorten_filename(Ofile); 1287 T -> 1288 %% The caller specified one. 1289 T 1290 end, 1291 1292 %% Quote the target is the called asked for this. 1293 Target1 = case proplists:get_value(makedep_quote_target, Opts) of 1294 true -> 1295 %% For now, only "$" is replaced by "$$". 1296 Fun = fun 1297 ($$) -> "$$"; 1298 (C) -> C 1299 end, 1300 map(Fun, Target0); 1301 _ -> 1302 Target0 1303 end, 1304 Target = Target1 ++ ":", 1305 1306 %% List the dependencies (includes) for this target. 1307 {MainRule,PhonyRules} = makedep_add_headers( 1308 Ifile, % The input file name. 1309 Code0, % The parsed source. 1310 [], % The list of dependencies already added. 1311 length(Target), % The current line length. 1312 Target, % The target. 1313 "", % Phony targets. 1314 Opts), 1315 1316 %% Prepare the content of the Makefile. For instance: 1317 %% hello.erl: hello.hrl common.hrl 1318 %% 1319 %% Or if phony targets are enabled: 1320 %% hello.erl: hello.hrl common.hrl 1321 %% 1322 %% hello.hrl: 1323 %% 1324 %% common.hrl: 1325 Makefile = case proplists:get_value(makedep_phony, Opts) of 1326 true -> MainRule ++ PhonyRules; 1327 _ -> MainRule 1328 end, 1329 Code = unicode:characters_to_binary([Makefile,"\n"]), 1330 {ok,Code,St}. 1331 1332makedep_add_headers(Ifile, [{attribute,_,file,{File,_}}|Rest], 1333 Included, LineLen, MainTarget, Phony, Opts) -> 1334 %% The header "File" exists, add it to the dependencies. 1335 {Included1,LineLen1,MainTarget1,Phony1} = 1336 makedep_add_header(Ifile, Included, LineLen, MainTarget, Phony, File), 1337 makedep_add_headers(Ifile, Rest, Included1, LineLen1, 1338 MainTarget1, Phony1, Opts); 1339makedep_add_headers(Ifile, [{error,{_,epp,{include,file,File}}}|Rest], 1340 Included, LineLen, MainTarget, Phony, Opts) -> 1341 %% The header "File" doesn't exist, do we add it to the dependencies? 1342 case proplists:get_value(makedep_add_missing, Opts) of 1343 true -> 1344 {Included1,LineLen1,MainTarget1,Phony1} = 1345 makedep_add_header(Ifile, Included, LineLen, MainTarget, 1346 Phony, File), 1347 makedep_add_headers(Ifile, Rest, Included1, LineLen1, 1348 MainTarget1, Phony1, Opts); 1349 _ -> 1350 makedep_add_headers(Ifile, Rest, Included, LineLen, 1351 MainTarget, Phony, Opts) 1352 end; 1353makedep_add_headers(Ifile, [_|Rest], Included, LineLen, 1354 MainTarget, Phony, Opts) -> 1355 makedep_add_headers(Ifile, Rest, Included, 1356 LineLen, MainTarget, Phony, Opts); 1357makedep_add_headers(_Ifile, [], _Included, _LineLen, 1358 MainTarget, Phony, _Opts) -> 1359 {MainTarget,Phony}. 1360 1361makedep_add_header(Ifile, Included, LineLen, MainTarget, Phony, File) -> 1362 case member(File, Included) of 1363 true -> 1364 %% This file was already listed in the dependencies, skip it. 1365 {Included,LineLen,MainTarget,Phony}; 1366 false -> 1367 Included1 = [File|Included], 1368 1369 %% Remove "./" in front of the dependency filename. 1370 File1 = case File of 1371 "./" ++ File0 -> File0; 1372 _ -> File 1373 end, 1374 1375 %% Prepare the phony target name. 1376 Phony1 = case File of 1377 Ifile -> Phony; 1378 _ -> Phony ++ "\n\n" ++ File1 ++ ":" 1379 end, 1380 1381 %% Add the file to the dependencies. Lines longer than 76 columns 1382 %% are split. 1383 if 1384 LineLen + 1 + length(File1) > 76 -> 1385 LineLen1 = 2 + length(File1), 1386 MainTarget1 = MainTarget ++ " \\\n " ++ File1, 1387 {Included1,LineLen1,MainTarget1,Phony1}; 1388 true -> 1389 LineLen1 = LineLen + 1 + length(File1), 1390 MainTarget1 = MainTarget ++ " " ++ File1, 1391 {Included1,LineLen1,MainTarget1,Phony1} 1392 end 1393 end. 1394 1395makedep_output(Code, #compile{options=Opts,ofile=Ofile}=St) -> 1396 %% Write this Makefile (Code) to the selected output. 1397 %% If no output is specified, the default is to write to a file named after 1398 %% the output file. 1399 Output = case proplists:get_value(makedep_output, Opts) of 1400 undefined -> 1401 %% Prepare the default filename. 1402 outfile(filename:basename(Ofile, ".beam"), "Pbeam", Opts); 1403 Other -> 1404 Other 1405 end, 1406 1407 if 1408 is_list(Output) -> 1409 %% Write the depedencies to a file. 1410 case file:write_file(Output, Code) of 1411 ok -> 1412 {ok,Code,St}; 1413 {error,Reason} -> 1414 Err = {St#compile.ifile,[{none,?MODULE,{write_error,Reason}}]}, 1415 {error,St#compile{errors=St#compile.errors++[Err]}} 1416 end; 1417 true -> 1418 %% Write the depedencies to a device. 1419 try io:fwrite(Output, "~ts", [Code]) of 1420 ok -> 1421 {ok,Code,St} 1422 catch 1423 error:_ -> 1424 Err = {St#compile.ifile,[{none,?MODULE,write_error}]}, 1425 {error,St#compile{errors=St#compile.errors++[Err]}} 1426 end 1427 end. 1428 1429expand_records(Code0, #compile{options=Opts}=St) -> 1430 Code = erl_expand_records:module(Code0, Opts), 1431 {ok,Code,St}. 1432 1433compile_directives(Forms, #compile{options=Opts0}=St) -> 1434 Opts = expand_opts(flatten([C || {attribute,_,compile,C} <- Forms])), 1435 {ok, Forms, St#compile{options=Opts ++ Opts0}}. 1436 1437core(Forms, #compile{options=Opts}=St) -> 1438 {ok,Core,Ws} = v3_core:module(Forms, Opts), 1439 Mod = cerl:concrete(cerl:module_name(Core)), 1440 {ok,Core,St#compile{module=Mod,options=Opts, 1441 warnings=St#compile.warnings++Ws}}. 1442 1443core_fold_module_after_inlining(Code0, #compile{options=Opts}=St) -> 1444 %% Inlining may produce code that generates spurious warnings. 1445 %% Ignore all warnings. 1446 {ok,Code,_Ws} = sys_core_fold:module(Code0, Opts), 1447 {ok,Code,St}. 1448 1449v3_kernel(Code0, #compile{options=Opts,warnings=Ws0}=St) -> 1450 {ok,Code,Ws} = v3_kernel:module(Code0, Opts), 1451 case Ws =:= [] orelse test_core_inliner(St) of 1452 false -> 1453 {ok,Code,St#compile{warnings=Ws0++Ws}}; 1454 true -> 1455 %% cerl_inline may produce code that generates spurious 1456 %% warnings. Ignore any such warnings. 1457 {ok,Code,St} 1458 end. 1459 1460test_old_inliner(#compile{options=Opts}) -> 1461 %% The point of this test is to avoid loading the old inliner 1462 %% if we know that it will not be used. 1463 any(fun({inline,_}) -> true; 1464 (_) -> false 1465 end, Opts). 1466 1467test_core_inliner(#compile{options=Opts}) -> 1468 case any(fun(no_inline) -> true; 1469 (_) -> false 1470 end, Opts) of 1471 true -> false; 1472 false -> 1473 any(fun(inline) -> true; 1474 (_) -> false 1475 end, Opts) 1476 end. 1477 1478test_any_inliner(St) -> 1479 test_old_inliner(St) orelse test_core_inliner(St). 1480 1481core_old_inliner(Code0, #compile{options=Opts}=St) -> 1482 {ok,Code} = sys_core_inline:module(Code0, Opts), 1483 {ok,Code,St}. 1484 1485core_inline_module(Code0, #compile{options=Opts}=St) -> 1486 Code = cerl_inline:core_transform(Code0, Opts), 1487 {ok,Code,St}. 1488 1489save_abstract_code(Code, St) -> 1490 {ok,Code,St#compile{abstract_code=erl_parse:anno_to_term(Code)}}. 1491 1492debug_info(#compile{module=Module,ofile=OFile}=St) -> 1493 {DebugInfo,Opts2} = debug_info_chunk(St), 1494 case member(encrypt_debug_info, Opts2) of 1495 true -> 1496 case lists:keytake(debug_info_key, 1, Opts2) of 1497 {value,{_, Key},Opts3} -> 1498 encrypt_debug_info(DebugInfo, Key, [{debug_info_key,'********'} | Opts3]); 1499 false -> 1500 Mode = proplists:get_value(crypto_mode, Opts2, des3_cbc), 1501 case beam_lib:get_crypto_key({debug_info, Mode, Module, OFile}) of 1502 error -> 1503 {error, [{none,?MODULE,no_crypto_key}]}; 1504 Key -> 1505 encrypt_debug_info(DebugInfo, {Mode, Key}, Opts2) 1506 end 1507 end; 1508 false -> 1509 {ok,DebugInfo,Opts2} 1510 end. 1511 1512debug_info_chunk(#compile{mod_options=ModOpts0, 1513 options=CompOpts, 1514 abstract_code=Abst}) -> 1515 AbstOpts = cleanup_compile_options(ModOpts0), 1516 {Backend,Metadata,ModOpts} = 1517 case proplists:get_value(debug_info, CompOpts, false) of 1518 {OptBackend,OptMetadata} when is_atom(OptBackend) -> 1519 ModOpts1 = proplists:delete(debug_info, ModOpts0), 1520 {OptBackend,OptMetadata,ModOpts1}; 1521 true -> 1522 ModOpts1 = proplists:delete(debug_info, ModOpts0), 1523 {erl_abstract_code,{Abst,AbstOpts},[debug_info | ModOpts1]}; 1524 false -> 1525 {erl_abstract_code,{none,AbstOpts},ModOpts0} 1526 end, 1527 DebugInfo = erlang:term_to_binary({debug_info_v1,Backend,Metadata}, 1528 [compressed]), 1529 {DebugInfo, ModOpts}. 1530 1531encrypt_debug_info(DebugInfo, Key, Opts) -> 1532 try 1533 RealKey = generate_key(Key), 1534 case start_crypto() of 1535 ok -> {ok,encrypt(RealKey, DebugInfo),Opts}; 1536 {error,_}=E -> E 1537 end 1538 catch 1539 error:_ -> 1540 {error,[{none,?MODULE,bad_crypto_key}]} 1541 end. 1542 1543cleanup_compile_options(Opts) -> 1544 IsDeterministic = lists:member(deterministic, Opts), 1545 lists:filter(fun(Opt) -> 1546 keep_compile_option(Opt, IsDeterministic) 1547 end, Opts). 1548 1549%% Include paths and current directory don't affect compilation, but they might 1550%% be helpful so we include them unless we're doing a deterministic build. 1551keep_compile_option({i, _}, Deterministic) -> 1552 not Deterministic; 1553keep_compile_option({cwd, _}, Deterministic) -> 1554 not Deterministic; 1555%% We are storing abstract, not asm or core. 1556keep_compile_option(from_asm, _Deterministic) -> 1557 false; 1558keep_compile_option(from_core, _Deterministic) -> 1559 false; 1560keep_compile_option(from_abstr, _Deterministic) -> 1561 false; 1562%% Parse transform and macros have already been applied. 1563keep_compile_option({parse_transform, _}, _Deterministic) -> 1564 false; 1565keep_compile_option({d, _, _}, _Deterministic) -> 1566 false; 1567%% Do not affect compilation result on future calls. 1568keep_compile_option(Option, _Deterministic) -> 1569 effects_code_generation(Option). 1570 1571start_crypto() -> 1572 try crypto:start() of 1573 {error,{already_started,crypto}} -> ok; 1574 ok -> ok 1575 catch 1576 error:_ -> 1577 {error,[{none,?MODULE,no_crypto}]} 1578 end. 1579 1580generate_key({Type,String}) when is_atom(Type), is_list(String) -> 1581 beam_lib:make_crypto_key(Type, String); 1582generate_key(String) when is_list(String) -> 1583 generate_key({des3_cbc,String}). 1584 1585encrypt({des3_cbc=Type,Key,IVec,BlockSize}, Bin0) -> 1586 Bin1 = case byte_size(Bin0) rem BlockSize of 1587 0 -> Bin0; 1588 N -> list_to_binary([Bin0,crypto:strong_rand_bytes(BlockSize-N)]) 1589 end, 1590 Bin = crypto:crypto_one_time(des_ede3_cbc, Key, IVec, Bin1, true), 1591 TypeString = atom_to_list(Type), 1592 list_to_binary([0,length(TypeString),TypeString,Bin]). 1593 1594beam_validator_strong(Code, St) -> 1595 beam_validator_1(Code, St, strong). 1596 1597beam_validator_weak(Code, St) -> 1598 beam_validator_1(Code, St, weak). 1599 1600beam_validator_1(Code, #compile{errors=Errors0}=St, Level) -> 1601 case beam_validator:validate(Code, Level) of 1602 ok -> 1603 {ok, Code, St}; 1604 {error, Es} -> 1605 {error, St#compile{errors=Errors0 ++ Es}} 1606 end. 1607 1608beam_asm(Code0, #compile{ifile=File,extra_chunks=ExtraChunks,options=CompilerOpts}=St) -> 1609 case debug_info(St) of 1610 {ok,DebugInfo,Opts0} -> 1611 Opts1 = [O || O <- Opts0, effects_code_generation(O)], 1612 Chunks = [{<<"Dbgi">>, DebugInfo} | ExtraChunks], 1613 CompileInfo = compile_info(File, CompilerOpts, Opts1), 1614 {ok,Code} = beam_asm:module(Code0, Chunks, CompileInfo, CompilerOpts), 1615 {ok,Code,St#compile{abstract_code=[]}}; 1616 {error,Es} -> 1617 {error,St#compile{errors=St#compile.errors ++ [{File,Es}]}} 1618 end. 1619 1620compile_info(File, CompilerOpts, Opts) -> 1621 IsSlim = member(slim, CompilerOpts), 1622 IsDeterministic = member(deterministic, CompilerOpts), 1623 Info0 = proplists:get_value(compile_info, Opts, []), 1624 Info1 = 1625 case paranoid_absname(File) of 1626 [_|_] = Source when not IsSlim, not IsDeterministic -> 1627 [{source,Source} | Info0]; 1628 _ -> 1629 Info0 1630 end, 1631 Info2 = 1632 case IsDeterministic of 1633 false -> [{options,proplists:delete(compile_info, Opts)} | Info1]; 1634 true -> Info1 1635 end, 1636 Info2. 1637 1638paranoid_absname(""=File) -> 1639 File; 1640paranoid_absname(File) -> 1641 case file:get_cwd() of 1642 {ok,Cwd} -> 1643 filename:absname(File, Cwd); 1644 _ -> 1645 File 1646 end. 1647 1648%% effects_code_generation(Option) -> true|false. 1649%% Determine whether the option could have any effect on the 1650%% generated code in the BEAM file (as opposed to how 1651%% errors will be reported). 1652 1653effects_code_generation(Option) -> 1654 case Option of 1655 beam -> false; 1656 report_warnings -> false; 1657 report_errors -> false; 1658 return_errors-> false; 1659 return_warnings-> false; 1660 warnings_as_errors -> false; 1661 binary -> false; 1662 verbose -> false; 1663 {cwd,_} -> false; 1664 {outdir, _} -> false; 1665 _ -> true 1666 end. 1667 1668save_binary(Code, #compile{module=Mod,ofile=Outfile,options=Opts}=St) -> 1669 %% Test that the module name and output file name match. 1670 case member(no_error_module_mismatch, Opts) of 1671 true -> 1672 save_binary_1(Code, St); 1673 false -> 1674 Base = filename:rootname(filename:basename(Outfile)), 1675 case atom_to_list(Mod) of 1676 Base -> 1677 save_binary_1(Code, St); 1678 _ -> 1679 Es = [{St#compile.ofile, 1680 [{none,?MODULE,{module_name,Mod,Base}}]}], 1681 {error,St#compile{errors=St#compile.errors ++ Es}} 1682 end 1683 end. 1684 1685save_binary_1(Code, St) -> 1686 Ofile = St#compile.ofile, 1687 Tfile = tmpfile(Ofile), %Temp working file 1688 case write_binary(Tfile, Code, St) of 1689 ok -> 1690 case file:rename(Tfile, Ofile) of 1691 ok -> 1692 {ok,none,St}; 1693 {error,RenameError} -> 1694 Es = [{Ofile,[{none,?MODULE,{rename,Tfile,Ofile, 1695 RenameError}}]}], 1696 _ = file:delete(Tfile), 1697 {error,St#compile{errors=St#compile.errors ++ Es}} 1698 end; 1699 {error,Error} -> 1700 Es = [{Tfile,[{none,compile,{write_error,Error}}]}], 1701 {error,St#compile{errors=St#compile.errors ++ Es}} 1702 end. 1703 1704write_binary(Name, Bin, St) -> 1705 Opts = case member(compressed, St#compile.options) of 1706 true -> [compressed]; 1707 false -> [] 1708 end, 1709 case file:write_file(Name, Bin, Opts) of 1710 ok -> ok; 1711 {error,_}=Error -> Error 1712 end. 1713 1714%% report_errors(State) -> ok 1715%% report_warnings(State) -> ok 1716 1717report_errors(#compile{options=Opts,errors=Errors}) -> 1718 case member(report_errors, Opts) of 1719 true -> 1720 foreach(fun ({{F,_L},Eds}) -> sys_messages:list_errors(F, Eds, Opts); 1721 ({F,Eds}) -> sys_messages:list_errors(F, Eds, Opts) end, 1722 Errors); 1723 false -> ok 1724 end. 1725 1726report_warnings(#compile{options=Opts,warnings=Ws0}) -> 1727 Werror = member(warnings_as_errors, Opts), 1728 P = case Werror of 1729 true -> ""; 1730 false -> "Warning: " 1731 end, 1732 ReportWerror = Werror andalso member(report_errors, Opts), 1733 case member(report_warnings, Opts) orelse ReportWerror of 1734 true -> 1735 Ws1 = flatmap(fun({{F,_L},Eds}) -> sys_messages:format_messages(F, P, Eds, Opts); 1736 ({F,Eds}) -> sys_messages:format_messages(F, P, Eds, Opts) end, 1737 Ws0), 1738 Ws = lists:sort(Ws1), 1739 foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws); 1740 false -> ok 1741 end. 1742 1743%%% 1744%%% Filter warnings. 1745%%% 1746 1747filter_warnings(Ws, Opts) -> 1748 Ignore = ignore_tags(Opts, sets:new([{version,2}])), 1749 filter_warnings_1(Ws, Ignore). 1750 1751filter_warnings_1([{Source,Ws0}|T], Ignore) -> 1752 Ws = [W || W <- Ws0, not ignore_warning(W, Ignore)], 1753 [{Source,Ws}|filter_warnings_1(T, Ignore)]; 1754filter_warnings_1([], _Ignore) -> []. 1755 1756ignore_warning({_Location,Pass,{Category,_}}, Ignore) -> 1757 IgnoreMod = case Pass of 1758 v3_core -> true; 1759 sys_core_fold -> true; 1760 v3_kernel -> true; 1761 _ -> false 1762 end, 1763 IgnoreMod andalso sets:is_element(Category, Ignore); 1764ignore_warning(_, _) -> false. 1765 1766ignore_tags([nowarn_opportunistic|_], _Ignore) -> 1767 sets:from_list([failed,ignored,nomatch], [{version,2}]); 1768ignore_tags([nowarn_failed|Opts], Ignore) -> 1769 ignore_tags(Opts, sets:add_element(failed, Ignore)); 1770ignore_tags([nowarn_ignored|Opts], Ignore) -> 1771 ignore_tags(Opts, sets:add_element(ignored, Ignore)); 1772ignore_tags([nowarn_nomatch|Opts], Ignore) -> 1773 ignore_tags(Opts, sets:add_element(nomatch, Ignore)); 1774ignore_tags([_|Opts], Ignore) -> 1775 ignore_tags(Opts, Ignore); 1776ignore_tags([], Ignore) -> Ignore. 1777 1778%% erlfile(Dir, Base) -> ErlFile 1779%% outfile(Base, Extension, Options) -> OutputFile 1780%% objfile(Base, Target, Options) -> ObjFile 1781%% tmpfile(ObjFile) -> TmpFile 1782%% Work out the correct input and output file names. 1783 1784erlfile(".", Base, Suffix) -> 1785 Base ++ Suffix; 1786erlfile(Dir, Base, Suffix) -> 1787 filename:join(Dir, Base ++ Suffix). 1788 1789outfile(Base, Ext, Opts) when is_list(Ext) -> 1790 Obase = case keyfind(outdir, 1, Opts) of 1791 {outdir, Odir} -> filename:join(Odir, Base); 1792 _Other -> Base % Not found or bad format 1793 end, 1794 Obase ++ "." ++ Ext. 1795 1796objfile(Base, St) -> 1797 outfile(Base, "beam", St#compile.options). 1798 1799tmpfile(Ofile) -> 1800 reverse([$#|tl(reverse(Ofile))]). 1801 1802%% pre_defs(Options) 1803%% inc_paths(Options) 1804%% Extract the predefined macros and include paths from the option list. 1805 1806pre_defs([{d,M,V}|Opts]) -> 1807 [{M,V}|pre_defs(Opts)]; 1808pre_defs([{d,M}|Opts]) -> 1809 [M|pre_defs(Opts)]; 1810pre_defs([_|Opts]) -> 1811 pre_defs(Opts); 1812pre_defs([]) -> []. 1813 1814inc_paths(Opts) -> 1815 [ P || {i,P} <- Opts, is_list(P) ]. 1816 1817src_listing(Ext, Code, St) -> 1818 listing(fun (Lf, {_Mod,_Exp,Fs}) -> do_src_listing(Lf, Fs); 1819 (Lf, Fs) -> do_src_listing(Lf, Fs) end, 1820 Ext, Code, St). 1821 1822do_src_listing(Lf, Fs) -> 1823 Opts = [lists:keyfind(encoding, 1, io:getopts(Lf))], 1824 foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F, Opts),"\n"]) end, 1825 Fs). 1826 1827listing(Ext, Code, St0) -> 1828 St = St0#compile{encoding = none}, 1829 listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, Code, St). 1830 1831listing(LFun, Ext, Code, St) -> 1832 Lfile = outfile(St#compile.base, Ext, St#compile.options), 1833 case file:open(Lfile, [write,delayed_write]) of 1834 {ok,Lf} -> 1835 output_encoding(Lf, St), 1836 LFun(Lf, Code), 1837 ok = file:close(Lf), 1838 {ok,Code,St}; 1839 {error,Error} -> 1840 Es = [{Lfile,[{none,compile,{write_error,Error}}]}], 1841 {error,St#compile{errors=St#compile.errors ++ Es}} 1842 end. 1843 1844to_dis(Code, #compile{module=Module,ofile=Outfile}=St) -> 1845 Loaded = code:is_loaded(Module), 1846 Sticky = code:is_sticky(Module), 1847 _ = [code:unstick_mod(Module) || Sticky], 1848 1849 {module,Module} = code:load_binary(Module, "", Code), 1850 DestDir = filename:dirname(Outfile), 1851 DisFile = filename:join(DestDir, atom_to_list(Module) ++ ".dis"), 1852 ok = erts_debug:dis_to_file(Module, DisFile), 1853 1854 %% Restore loaded module 1855 _ = [{module, Module} = code:load_file(Module) || Loaded =/= false], 1856 [code:stick_mod(Module) || Sticky], 1857 {ok,Code,St}. 1858 1859output_encoding(F, #compile{encoding = none}) -> 1860 ok = io:setopts(F, [{encoding, epp:default_encoding()}]); 1861output_encoding(F, #compile{encoding = Encoding}) -> 1862 ok = io:setopts(F, [{encoding, Encoding}]), 1863 ok = io:fwrite(F, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]). 1864 1865%%% 1866%%% Transform the BEAM code to make it more friendly for 1867%%% diffing: using function names instead of labels for 1868%%% local calls and number labels relative to each function. 1869%%% 1870 1871diffable(Code0, St) -> 1872 {Mod,Exp,Attr,Fs0,NumLabels} = Code0, 1873 EntryLabels0 = [{Entry,{Name,Arity}} || 1874 {function,Name,Arity,Entry,_} <- Fs0], 1875 EntryLabels = maps:from_list(EntryLabels0), 1876 Fs = [diffable_fix_function(F, EntryLabels) || F <- Fs0], 1877 Code = {Mod,Exp,Attr,Fs,NumLabels}, 1878 {ok,Code,St}. 1879 1880diffable_fix_function({function,Name,Arity,Entry0,Is0}, LabelMap0) -> 1881 Entry = maps:get(Entry0, LabelMap0), 1882 {Is1,LabelMap} = diffable_label_map(Is0, 1, LabelMap0, []), 1883 Fb = fun(Old) -> error({no_fb,Old}) end, 1884 Is = beam_utils:replace_labels(Is1, [], LabelMap, Fb), 1885 {function,Name,Arity,Entry,Is}. 1886 1887diffable_label_map([{label,Old}|Is], New, Map, Acc) -> 1888 case Map of 1889 #{Old:=NewLabel} -> 1890 diffable_label_map(Is, New, Map, [{label,NewLabel}|Acc]); 1891 #{} -> 1892 diffable_label_map(Is, New+1, Map#{Old=>New}, [{label,New}|Acc]) 1893 end; 1894diffable_label_map([I|Is], New, Map, Acc) -> 1895 diffable_label_map(Is, New, Map, [I|Acc]); 1896diffable_label_map([], _New, Map, Acc) -> 1897 {Acc,Map}. 1898 1899-spec options() -> 'ok'. 1900 1901options() -> 1902 help(standard_passes()). 1903 1904help([{delay,Ps}|T]) -> 1905 help(Ps), 1906 help(T); 1907help([{iff,Flag,{src_listing,Ext}}|T]) -> 1908 io:fwrite("~p - Generate .~s source listing file\n", [Flag,Ext]), 1909 help(T); 1910help([{iff,Flag,{listing,Ext}}|T]) -> 1911 io:fwrite("~p - Generate .~s file\n", [Flag,Ext]), 1912 help(T); 1913help([{iff,Flag,{Name,Fun}}|T]) when is_function(Fun) -> 1914 io:fwrite("~p - Run ~s\n", [Flag,Name]), 1915 help(T); 1916help([{iff,_Flag,Action}|T]) -> 1917 help(Action), 1918 help(T); 1919help([{unless,Flag,{pass,Pass}}|T]) -> 1920 io:fwrite("~p - Skip the ~s pass\n", [Flag,Pass]), 1921 help(T); 1922help([{unless,no_postopt=Flag,List}|T]) when is_list(List) -> 1923 %% Hard-coded knowledge here. 1924 io:fwrite("~p - Skip all post optimisation\n", [Flag]), 1925 help(List), 1926 help(T); 1927help([{unless,_Flag,Action}|T]) -> 1928 help(Action), 1929 help(T); 1930help([_|T]) -> 1931 help(T); 1932help(_) -> 1933 ok. 1934 1935rel2fam(S0) -> 1936 S1 = sofs:relation(S0), 1937 S = sofs:rel2fam(S1), 1938 sofs:to_external(S). 1939 1940%% compile(AbsFileName, Outfilename, Options) 1941%% Compile entry point for erl_compile. 1942 1943-spec compile(file:filename(), _, #options{}) -> 'ok' | 'error'. 1944 1945compile(File0, _OutFile, Options) -> 1946 pre_load(), 1947 File = shorten_filename(File0), 1948 case file(File, make_erl_options(Options)) of 1949 {ok,_Mod} -> ok; 1950 Other -> Other 1951 end. 1952 1953-spec compile_asm(file:filename(), _, #options{}) -> 'ok' | 'error'. 1954 1955compile_asm(File0, _OutFile, Opts) -> 1956 File = shorten_filename(File0), 1957 case file(File, [from_asm|make_erl_options(Opts)]) of 1958 {ok,_Mod} -> ok; 1959 Other -> Other 1960 end. 1961 1962-spec compile_core(file:filename(), _, #options{}) -> 'ok' | 'error'. 1963 1964compile_core(File0, _OutFile, Opts) -> 1965 File = shorten_filename(File0), 1966 case file(File, [from_core|make_erl_options(Opts)]) of 1967 {ok,_Mod} -> ok; 1968 Other -> Other 1969 end. 1970 1971-spec compile_abstr(file:filename(), _, #options{}) -> 'ok' | 'error'. 1972 1973compile_abstr(File0, _OutFile, Opts) -> 1974 File = shorten_filename(File0), 1975 case file(File, [from_abstr|make_erl_options(Opts)]) of 1976 {ok,_Mod} -> ok; 1977 Other -> Other 1978 end. 1979 1980shorten_filename(Name0) -> 1981 {ok,Cwd} = file:get_cwd(), 1982 case lists:prefix(Cwd, Name0) of 1983 false -> Name0; 1984 true -> 1985 case lists:nthtail(length(Cwd), Name0) of 1986 "/"++N -> N; 1987 N -> N 1988 end 1989 end. 1990 1991%% Converts generic compiler options to specific options. 1992 1993make_erl_options(Opts) -> 1994 #options{includes=Includes, 1995 defines=Defines, 1996 outdir=Outdir, 1997 warning=Warning, 1998 verbose=Verbose, 1999 specific=Specific, 2000 cwd=Cwd} = Opts, 2001 Options = [verbose || Verbose] ++ 2002 [report_warnings || Warning =/= 0] ++ 2003 map(fun ({Name,Value}) -> 2004 {d,Name,Value}; 2005 (Name) -> 2006 {d,Name} 2007 end, Defines), 2008 Options ++ [report_errors, {cwd, Cwd}, {outdir, Outdir} | 2009 [{i, Dir} || Dir <- Includes]] ++ Specific. 2010 2011pre_load() -> 2012 L = [beam_a, 2013 beam_asm, 2014 beam_block, 2015 beam_call_types, 2016 beam_clean, 2017 beam_dict, 2018 beam_digraph, 2019 beam_flatten, 2020 beam_jump, 2021 beam_kernel_to_ssa, 2022 beam_opcodes, 2023 beam_peep, 2024 beam_ssa, 2025 beam_ssa_bc_size, 2026 beam_ssa_bool, 2027 beam_ssa_bsm, 2028 beam_ssa_codegen, 2029 beam_ssa_dead, 2030 beam_ssa_funs, 2031 beam_ssa_opt, 2032 beam_ssa_pre_codegen, 2033 beam_ssa_recv, 2034 beam_ssa_share, 2035 beam_ssa_throw, 2036 beam_ssa_type, 2037 beam_trim, 2038 beam_types, 2039 beam_utils, 2040 beam_validator, 2041 beam_z, 2042 cerl, 2043 cerl_clauses, 2044 cerl_trees, 2045 core_lib, 2046 epp, 2047 erl_bifs, 2048 erl_expand_records, 2049 erl_lint, 2050 erl_parse, 2051 erl_scan, 2052 sys_core_alias, 2053 sys_core_bsm, 2054 sys_core_fold, 2055 v3_core, 2056 v3_kernel], 2057 _ = code:ensure_modules_loaded(L), 2058 ok. 2059