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