1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id: compile.erl,v 1.1 2008/12/17 09:53:42 mikpe Exp $ 18%% Purpose: Run the Erlang compiler. 19 20-module(compile). 21-include("erl_compile.hrl"). 22-include("core_parse.hrl"). 23 24%% High-level interface. 25-export([file/1,file/2,format_error/1,iofile/1]). 26-export([forms/1,forms/2]). 27-export([output_generated/1]). 28-export([options/0]). 29 30%% Erlc interface. 31-export([compile/3,compile_beam/3,compile_asm/3,compile_core/3]). 32 33 34-import(lists, [member/2,reverse/1,keysearch/3,last/1, 35 map/2,flatmap/2,foreach/2,foldr/3,any/2,filter/2]). 36 37%% file(FileName) 38%% file(FileName, Options) 39%% Compile the module in file FileName. 40 41-define(DEFAULT_OPTIONS, [verbose,report_errors,report_warnings]). 42 43-define(pass(P), {P,fun P/1}). 44 45file(File) -> file(File, ?DEFAULT_OPTIONS). 46 47file(File, Opts) when list(Opts) -> 48 do_compile({file,File}, Opts++env_default_opts()); 49file(File, Opt) -> 50 file(File, [Opt|?DEFAULT_OPTIONS]). 51 52forms(File) -> forms(File, ?DEFAULT_OPTIONS). 53 54forms(Forms, Opts) when list(Opts) -> 55 do_compile({forms,Forms}, [binary|Opts++env_default_opts()]); 56forms(Forms, Opts) when atom(Opts) -> 57 forms(Forms, [Opts|?DEFAULT_OPTIONS]). 58 59env_default_opts() -> 60 Key = "ERL_COMPILER_OPTIONS", 61 case os:getenv(Key) of 62 false -> []; 63 Str when list(Str) -> 64 case erl_scan:string(Str) of 65 {ok,Tokens,_} -> 66 case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of 67 {ok,List} when list(List) -> List; 68 {ok,Term} -> [Term]; 69 {error,_Reason} -> 70 io:format("Ignoring bad term in ~s\n", [Key]), 71 [] 72 end; 73 {error, {_,_,_Reason}, _} -> 74 io:format("Ignoring bad term in ~s\n", [Key]), 75 [] 76 end 77 end. 78 79do_compile(Input, Opts0) -> 80 Opts = expand_opts(Opts0), 81 Self = self(), 82 Serv = spawn_link(fun() -> internal(Self, Input, Opts) end), 83 receive 84 {Serv,Rep} -> Rep 85 end. 86 87%% Given a list of compilation options, returns true if compile:file/2 88%% would have generated a Beam file, false otherwise (if only a binary or a 89%% listing file would have been generated). 90 91output_generated(Opts) -> 92 any(fun ({save_binary,_F}) -> true; 93 (_Other) -> false 94 end, passes(file, expand_opts(Opts))). 95 96expand_opts(Opts) -> 97 foldr(fun expand_opt/2, [], Opts). 98 99expand_opt(basic_validation, Os) -> 100 [no_code_generation,to_pp,binary|Os]; 101expand_opt(strong_validation, Os) -> 102 [no_code_generation,to_kernel,binary|Os]; 103expand_opt(report, Os) -> 104 [report_errors,report_warnings|Os]; 105expand_opt(return, Os) -> 106 [return_errors,return_warnings|Os]; 107expand_opt(r7, Os) -> 108 [no_float_opt,no_new_funs,no_new_binaries,no_new_apply|Os]; 109expand_opt(O, Os) -> [O|Os]. 110 111filter_opts(Opts0) -> 112 %% Native code generation is not supported if no_new_funs is given. 113 case member(no_new_funs, Opts0) of 114 false -> Opts0; 115 true -> Opts0 -- [native] 116 end. 117 118%% format_error(ErrorDescriptor) -> string() 119 120format_error(no_native_support) -> 121 "this system is not configured for native-code compilation."; 122format_error({native, E}) -> 123 io_lib:fwrite("native-code compilation failed with reason: ~P.", 124 [E, 25]); 125format_error({native_crash, E}) -> 126 io_lib:fwrite("native-code compilation crashed with reason: ~P.", 127 [E, 25]); 128format_error({open,E}) -> 129 io_lib:format("open error '~s'", [file:format_error(E)]); 130format_error({epp,E}) -> 131 epp:format_error(E); 132format_error(write_error) -> 133 "error writing file"; 134format_error({rename,S}) -> 135 io_lib:format("error renaming ~s", [S]); 136format_error({parse_transform,M,R}) -> 137 io_lib:format("error in parse transform '~s': ~p", [M, R]); 138format_error({core_transform,M,R}) -> 139 io_lib:format("error in core transform '~s': ~p", [M, R]); 140format_error({crash,Pass,Reason}) -> 141 io_lib:format("internal error in ~p;\ncrash reason: ~p", [Pass,Reason]); 142format_error({bad_return,Pass,Reason}) -> 143 io_lib:format("internal error in ~p;\nbad return value: ~p", [Pass,Reason]). 144 145%% The compile state record. 146-record(compile, {filename="", 147 dir="", 148 base="", 149 ifile="", 150 ofile="", 151 module=[], 152 code=[], 153 core_code=[], 154 abstract_code=[], %Abstract code for debugger. 155 options=[], 156 errors=[], 157 warnings=[]}). 158 159internal(Master, Input, Opts) -> 160 Master ! {self(), 161 case catch internal(Input, Opts) of 162 {'EXIT', Reason} -> 163 {error, Reason}; 164 Other -> 165 Other 166 end}. 167 168internal({forms,Forms}, Opts) -> 169 Ps = passes(forms, Opts), 170 internal_comp(Ps, "", "", #compile{code=Forms,options=Opts}); 171internal({file,File}, Opts) -> 172 Ps = passes(file, Opts), 173 Compile = #compile{options=Opts}, 174 case member(from_core, Opts) of 175 true -> internal_comp(Ps, File, ".core", Compile); 176 false -> 177 case member(from_beam, Opts) of 178 true -> 179 internal_comp(Ps, File, ".beam", Compile); 180 false -> 181 case member(from_asm, Opts) orelse member(asm, Opts) of 182 true -> 183 internal_comp(Ps, File, ".S", Compile); 184 false -> 185 internal_comp(Ps, File, ".erl", Compile) 186 end 187 end 188 end. 189 190internal_comp(Passes, File, Suffix, St0) -> 191 Dir = filename:dirname(File), 192 Base = filename:basename(File, Suffix), 193 St1 = St0#compile{filename=File, dir=Dir, base=Base, 194 ifile=erlfile(Dir, Base, Suffix), 195 ofile=objfile(Base, St0)}, 196 Run = case member(time, St1#compile.options) of 197 true -> 198 io:format("Compiling ~p\n", [File]), 199 fun run_tc/2; 200 false -> fun({_Name,Fun}, St) -> catch Fun(St) end 201 end, 202 case fold_comp(Passes, Run, St1) of 203 {ok,St2} -> comp_ret_ok(St2); 204 {error,St2} -> comp_ret_err(St2) 205 end. 206 207fold_comp([{Name,Test,Pass}|Ps], Run, St) -> 208 case Test(St) of 209 false -> %Pass is not needed. 210 fold_comp(Ps, Run, St); 211 true -> %Run pass in the usual way. 212 fold_comp([{Name,Pass}|Ps], Run, St) 213 end; 214fold_comp([{Name,Pass}|Ps], Run, St0) -> 215 case Run({Name,Pass}, St0) of 216 {ok,St1} -> fold_comp(Ps, Run, St1); 217 {error,St1} -> {error,St1}; 218 {'EXIT',Reason} -> 219 Es = [{St0#compile.ifile,[{none,?MODULE,{crash,Name,Reason}}]}], 220 {error,St0#compile{errors=St0#compile.errors ++ Es}}; 221 Other -> 222 Es = [{St0#compile.ifile,[{none,?MODULE,{bad_return,Name,Other}}]}], 223 {error,St0#compile{errors=St0#compile.errors ++ Es}} 224 end; 225fold_comp([], _Run, St) -> {ok,St}. 226 227os_process_size() -> 228 case os:type() of 229 {unix, sunos} -> 230 Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"), 231 list_to_integer(nonl(Size)); 232 _ -> 233 0 234 end. 235 236nonl([$\n]) -> []; 237nonl([]) -> []; 238nonl([H|T]) -> [H|nonl(T)]. 239 240run_tc({Name,Fun}, St) -> 241 Before0 = statistics(runtime), 242 Val = (catch Fun(St)), 243 After0 = statistics(runtime), 244 {Before_c, _} = Before0, 245 {After_c, _} = After0, 246 io:format(" ~-30s: ~10.3f s (~w k)\n", 247 [Name, (After_c-Before_c) / 1000, os_process_size()]), 248 Val. 249 250comp_ret_ok(#compile{code=Code,warnings=Warn,module=Mod,options=Opts}=St) -> 251 report_warnings(St), 252 Ret1 = case member(binary, Opts) andalso not member(no_code_generation, Opts) of 253 true -> [Code]; 254 false -> [] 255 end, 256 Ret2 = case member(return_warnings, Opts) of 257 true -> Ret1 ++ [Warn]; 258 false -> Ret1 259 end, 260 list_to_tuple([ok,Mod|Ret2]). 261 262comp_ret_err(St) -> 263 report_errors(St), 264 report_warnings(St), 265 case member(return_errors, St#compile.options) of 266 true -> {error,St#compile.errors,St#compile.warnings}; 267 false -> error 268 end. 269 270%% passes(form|file, [Option]) -> [{Name,PassFun}] 271%% Figure out which passes that need to be run. 272 273passes(forms, Opts) -> 274 select_passes(standard_passes(), Opts); 275passes(file, Opts) -> 276 case member(from_beam, Opts) of 277 true -> 278 Ps = [?pass(read_beam_file)|binary_passes()], 279 select_passes(Ps, Opts); 280 false -> 281 Ps = case member(from_asm, Opts) orelse member(asm, Opts) of 282 true -> 283 [?pass(beam_consult_asm)|asm_passes()]; 284 false -> 285 case member(from_core, Opts) of 286 true -> 287 [?pass(parse_core)|core_passes()]; 288 false -> 289 [?pass(parse_module)|standard_passes()] 290 end 291 end, 292 Fs = select_passes(Ps, Opts), 293 294 %% If the last pass saves the resulting binary to a file, 295 %% insert a first pass to remove the file. 296 case last(Fs) of 297 {save_binary,_Fun} -> [?pass(remove_file)|Fs]; 298 _Other -> Fs 299 end 300 end. 301 302%% select_passes([Command], Opts) -> [{Name,Function}] 303%% Interpret the lists of commands to return a pure list of passes. 304%% 305%% Command can be one of: 306%% 307%% {pass,Mod} Will be expanded to a call to the external 308%% function Mod:module(Code, Options). This 309%% function must transform the code and return 310%% {ok,NewCode} or {error,Term}. 311%% Example: {pass,beam_codegen} 312%% 313%% {Name,Fun} Name is an atom giving the name of the pass. 314%% Fun is an 'fun' taking one argument: a compile record. 315%% The fun should return {ok,NewCompileRecord} or 316%% {error,NewCompileRecord}. 317%% Note: ?pass(Name) is equvivalent to {Name,fun Name/1}. 318%% Example: ?pass(parse_module) 319%% 320%% {Name,Test,Fun} Like {Name,Fun} above, but the pass will be run 321%% (and listed by the `time' option) only if Test(St) 322%% returns true. 323%% 324%% {src_listing,Ext} Produces an Erlang source listing with the 325%% the file extension Ext. (Ext should not contain 326%% a period.) No more passes will be run. 327%% 328%% {listing,Ext} Produce an listing of the terms in the internal 329%% representation. The extension of the listing 330%% file will be Ext. (Ext should not contain 331%% a period.) No more passes will be run. 332%% 333%% {done,Ext} End compilation at this point. Produce a listing 334%% as with {listing,Ext}, unless 'binary' is 335%% specified, in which case the current 336%% representation of the code is returned without 337%% creating an output file. 338%% 339%% {iff,Flag,Cmd} If the given Flag is given in the option list, 340%% Cmd will be interpreted as a command. 341%% Otherwise, Cmd will be ignored. 342%% Example: {iff,dcg,{listing,"codegen}} 343%% 344%% {unless,Flag,Cmd} If the given Flag is NOT given in the option list, 345%% Cmd will be interpreted as a command. 346%% Otherwise, Cmd will be ignored. 347%% Example: {unless,no_kernopt,{pass,sys_kernopt}} 348%% 349 350select_passes([{pass,Mod}|Ps], Opts) -> 351 F = fun(St) -> 352 case catch Mod:module(St#compile.code, St#compile.options) of 353 {ok,Code} -> 354 {ok,St#compile{code=Code}}; 355 {error,Es} -> 356 {error,St#compile{errors=St#compile.errors ++ Es}} 357 end 358 end, 359 [{Mod,F}|select_passes(Ps, Opts)]; 360select_passes([{src_listing,Ext}|_], _Opts) -> 361 [{listing,fun (St) -> src_listing(Ext, St) end}]; 362select_passes([{listing,Ext}|_], _Opts) -> 363 [{listing,fun (St) -> listing(Ext, St) end}]; 364select_passes([{done,Ext}|_], Opts) -> 365 select_passes([{unless,binary,{listing,Ext}}], Opts); 366select_passes([{iff,Flag,Pass}|Ps], Opts) -> 367 select_cond(Flag, true, Pass, Ps, Opts); 368select_passes([{unless,Flag,Pass}|Ps], Opts) -> 369 select_cond(Flag, false, Pass, Ps, Opts); 370select_passes([{_,Fun}=P|Ps], Opts) when is_function(Fun) -> 371 [P|select_passes(Ps, Opts)]; 372select_passes([{_,Test,Fun}=P|Ps], Opts) when is_function(Test), 373 is_function(Fun) -> 374 [P|select_passes(Ps, Opts)]; 375select_passes([], _Opts) -> 376 []; 377select_passes([List|Ps], Opts) when is_list(List) -> 378 case select_passes(List, Opts) of 379 [] -> select_passes(Ps, Opts); 380 Nested -> 381 case last(Nested) of 382 {listing,_Fun} -> Nested; 383 _Other -> Nested ++ select_passes(Ps, Opts) 384 end 385 end. 386 387select_cond(Flag, ShouldBe, Pass, Ps, Opts) -> 388 ShouldNotBe = not ShouldBe, 389 case member(Flag, Opts) of 390 ShouldBe -> select_passes([Pass|Ps], Opts); 391 ShouldNotBe -> select_passes(Ps, Opts) 392 end. 393 394%% The standard passes (almost) always run. 395 396standard_passes() -> 397 [?pass(transform_module), 398 {iff,'dpp',{listing,"pp"}}, 399 ?pass(lint_module), 400 {iff,'P',{src_listing,"P"}}, 401 {iff,'to_pp',{done,"P"}}, 402 403 {iff,'dabstr',{listing,"abstr"}}, 404 {iff,debug_info,?pass(save_abstract_code)}, 405 406 ?pass(expand_module), 407 {iff,'dexp',{listing,"expand"}}, 408 {iff,'E',{src_listing,"E"}}, 409 {iff,'to_exp',{done,"E"}}, 410 411 %% Conversion to Core Erlang. 412 ?pass(core_module), 413 {iff,'dcore',{listing,"core"}}, 414 {iff,'to_core0',{done,"core"}} 415 | core_passes()]. 416 417core_passes() -> 418 %% Optimization and transforms of Core Erlang code. 419 [{unless,no_copt, 420 [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/1}, 421 ?pass(core_fold_module), 422 {core_inline_module,fun test_core_inliner/1,fun core_inline_module/1}, 423 {core_fold_after_inline,fun test_core_inliner/1,fun core_fold_module/1}, 424 ?pass(core_transforms)]}, 425 {iff,dcopt,{listing,"copt"}}, 426 {iff,'to_core',{done,"core"}} 427 | kernel_passes()]. 428 429kernel_passes() -> 430 %% Destructive setelement/3 optimization and core lint. 431 [?pass(core_dsetel_module), 432 {iff,clint,?pass(core_lint_module)}, 433 {iff,core,?pass(save_core_code)}, 434 435 %% Kernel Erlang and code generation. 436 ?pass(kernel_module), 437 {iff,dkern,{listing,"kernel"}}, 438 {iff,'to_kernel',{done,"kernel"}}, 439 {pass,v3_life}, 440 {iff,dlife,{listing,"life"}}, 441 {pass,v3_codegen}, 442 {iff,dcg,{listing,"codegen"}} 443 | asm_passes()]. 444 445asm_passes() -> 446 %% Assembly level optimisations. 447 [{unless,no_postopt, 448 [{pass,beam_block}, 449 {iff,dblk,{listing,"block"}}, 450 {unless,no_bopt,{pass,beam_bool}}, 451 {iff,dbool,{listing,"bool"}}, 452 {unless,no_topt,{pass,beam_type}}, 453 {iff,dtype,{listing,"type"}}, 454 {pass,beam_dead}, %Must always run since it splits blocks. 455 {iff,ddead,{listing,"dead"}}, 456 {unless,no_jopt,{pass,beam_jump}}, 457 {iff,djmp,{listing,"jump"}}, 458 {pass,beam_clean}, 459 {iff,dclean,{listing,"clean"}}, 460 {pass,beam_flatten}]}, 461 462 %% If post optimizations are turned off, we still coalesce 463 %% adjacent labels and remove unused labels to keep the 464 %% HiPE compiler happy. 465 {iff,no_postopt, 466 [?pass(beam_unused_labels), 467 {pass,beam_clean}]}, 468 469 {iff,dopt,{listing,"optimize"}}, 470 {iff,'S',{listing,"S"}}, 471 {iff,'to_asm',{done,"S"}}, 472 473 {pass,beam_validator}, 474 ?pass(beam_asm) 475 | binary_passes()]. 476 477binary_passes() -> 478 [{native_compile,fun test_native/1,fun native_compile/1}, 479 {unless,binary,?pass(save_binary)}]. 480 481%%% 482%%% Compiler passes. 483%%% 484 485%% Remove the target file so we don't have an old one if the compilation fail. 486remove_file(St) -> 487 file:delete(St#compile.ofile), 488 {ok,St}. 489 490-record(asm_module, {module, 491 exports, 492 labels, 493 functions=[], 494 cfun, 495 code, 496 attributes=[]}). 497 498preprocess_asm_forms(Forms) -> 499 R = #asm_module{}, 500 R1 = collect_asm(Forms, R), 501 {R1#asm_module.module, 502 {R1#asm_module.module, 503 R1#asm_module.exports, 504 R1#asm_module.attributes, 505 R1#asm_module.functions, 506 R1#asm_module.labels}}. 507 508collect_asm([], R) -> 509 case R#asm_module.cfun of 510 undefined -> 511 R; 512 {A,B,C} -> 513 R#asm_module{functions=R#asm_module.functions++ 514 [{function,A,B,C,R#asm_module.code}]} 515 end; 516collect_asm([{module,M} | Rest], R) -> 517 collect_asm(Rest, R#asm_module{module=M}); 518collect_asm([{exports,M} | Rest], R) -> 519 collect_asm(Rest, R#asm_module{exports=M}); 520collect_asm([{labels,M} | Rest], R) -> 521 collect_asm(Rest, R#asm_module{labels=M}); 522collect_asm([{function,A,B,C} | Rest], R) -> 523 R1 = case R#asm_module.cfun of 524 undefined -> 525 R; 526 {A0,B0,C0} -> 527 R#asm_module{functions=R#asm_module.functions++ 528 [{function,A0,B0,C0,R#asm_module.code}]} 529 end, 530 collect_asm(Rest, R1#asm_module{cfun={A,B,C}, code=[]}); 531collect_asm([{attributes, Attr} | Rest], R) -> 532 collect_asm(Rest, R#asm_module{attributes=Attr}); 533collect_asm([X | Rest], R) -> 534 collect_asm(Rest, R#asm_module{code=R#asm_module.code++[X]}). 535 536beam_consult_asm(St) -> 537 case file:consult(St#compile.ifile) of 538 {ok, Forms0} -> 539 {Module, Forms} = preprocess_asm_forms(Forms0), 540 {ok,St#compile{module=Module, code=Forms}}; 541 {error,E} -> 542 Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}], 543 {error,St#compile{errors=St#compile.errors ++ Es}} 544 end. 545 546read_beam_file(St) -> 547 case file:read_file(St#compile.ifile) of 548 {ok,Beam} -> 549 Infile = St#compile.ifile, 550 case is_too_old(Infile) of 551 true -> 552 {ok,St#compile{module=none,code=none}}; 553 false -> 554 Mod0 = filename:rootname(filename:basename(Infile)), 555 Mod = list_to_atom(Mod0), 556 {ok,St#compile{module=Mod,code=Beam,ofile=Infile}} 557 end; 558 {error,E} -> 559 Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}], 560 {error,St#compile{errors=St#compile.errors ++ Es}} 561 end. 562 563is_too_old(BeamFile) -> 564 case beam_lib:chunks(BeamFile, ["CInf"]) of 565 {ok,{_,[{"CInf",Term0}]}} -> 566 Term = binary_to_term(Term0), 567 Opts = proplists:get_value(options, Term, []), 568 lists:member(no_new_funs, Opts); 569 _ -> false 570 end. 571 572parse_module(St) -> 573 Opts = St#compile.options, 574 Cwd = ".", 575 IncludePath = [Cwd, St#compile.dir|inc_paths(Opts)], 576 Tab = ets:new(compiler__tab, [protected,named_table]), 577 ets:insert(Tab, {compiler_options,Opts}), 578 R = epp:parse_file(St#compile.ifile, IncludePath, pre_defs(Opts)), 579 ets:delete(Tab), 580 case R of 581 {ok,Forms} -> 582 {ok,St#compile{code=Forms}}; 583 {error,E} -> 584 Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}], 585 {error,St#compile{errors=St#compile.errors ++ Es}} 586 end. 587 588parse_core(St) -> 589 case file:read_file(St#compile.ifile) of 590 {ok,Bin} -> 591 case core_scan:string(binary_to_list(Bin)) of 592 {ok,Toks,_} -> 593 case core_parse:parse(Toks) of 594 {ok,Mod} -> 595 Name = (Mod#c_module.name)#c_atom.val, 596 {ok,St#compile{module=Name,code=Mod}}; 597 {error,E} -> 598 Es = [{St#compile.ifile,[E]}], 599 {error,St#compile{errors=St#compile.errors ++ Es}} 600 end; 601 {error,E,_} -> 602 Es = [{St#compile.ifile,[E]}], 603 {error,St#compile{errors=St#compile.errors ++ Es}} 604 end; 605 {error,E} -> 606 Es = [{St#compile.ifile,[{none,compile,{open,E}}]}], 607 {error,St#compile{errors=St#compile.errors ++ Es}} 608 end. 609 610compile_options([{attribute,_L,compile,C}|Fs]) when is_list(C) -> 611 C ++ compile_options(Fs); 612compile_options([{attribute,_L,compile,C}|Fs]) -> 613 [C|compile_options(Fs)]; 614compile_options([_F|Fs]) -> compile_options(Fs); 615compile_options([]) -> []. 616 617transforms(Os) -> [ M || {parse_transform,M} <- Os ]. 618 619transform_module(St) -> 620 %% Extract compile options from code into options field. 621 Ts = transforms(St#compile.options ++ compile_options(St#compile.code)), 622 foldl_transform(St, Ts). 623 624foldl_transform(St, [T|Ts]) -> 625 Name = "transform " ++ atom_to_list(T), 626 Fun = fun(S) -> T:parse_transform(S#compile.code, S#compile.options) end, 627 Run = case member(time, St#compile.options) of 628 true -> fun run_tc/2; 629 false -> fun({_Name,F}, S) -> catch F(S) end 630 end, 631 case Run({Name, Fun}, St) of 632 {error,Es,Ws} -> 633 {error,St#compile{warnings=St#compile.warnings ++ Ws, 634 errors=St#compile.errors ++ Es}}; 635 {'EXIT',R} -> 636 Es = [{St#compile.ifile,[{none,compile,{parse_transform,T,R}}]}], 637 {error,St#compile{errors=St#compile.errors ++ Es}}; 638 Forms -> 639 foldl_transform(St#compile{code=Forms}, Ts) 640 end; 641foldl_transform(St, []) -> {ok,St}. 642 643get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts]. 644 645core_transforms(St) -> 646 %% The options field holds the complete list of options at this 647 648 Ts = get_core_transforms(St#compile.options), 649 foldl_core_transforms(St, Ts). 650 651foldl_core_transforms(St, [T|Ts]) -> 652 Name = "core transform " ++ atom_to_list(T), 653 Fun = fun(S) -> T:core_transform(S#compile.code, S#compile.options) end, 654 Run = case member(time, St#compile.options) of 655 true -> fun run_tc/2; 656 false -> fun({_Name,F}, S) -> catch F(S) end 657 end, 658 case Run({Name, Fun}, St) of 659 {'EXIT',R} -> 660 Es = [{St#compile.ifile,[{none,compile,{core_transform,T,R}}]}], 661 {error,St#compile{errors=St#compile.errors ++ Es}}; 662 Forms -> 663 foldl_core_transforms(St#compile{code=Forms}, Ts) 664 end; 665foldl_core_transforms(St, []) -> {ok,St}. 666 667%%% Fetches the module name from a list of forms. The module attribute must 668%%% be present. 669get_module([{attribute,_,module,{M,_As}} | _]) -> M; 670get_module([{attribute,_,module,M} | _]) -> M; 671get_module([_ | Rest]) -> 672 get_module(Rest). 673 674%%% A #compile state is returned, where St.base has been filled in 675%%% with the module name from Forms, as a string, in case it wasn't 676%%% set in St (i.e., it was ""). 677add_default_base(St, Forms) -> 678 F = St#compile.filename, 679 case F of 680 "" -> 681 M = get_module(Forms), 682 St#compile{base = atom_to_list(M)}; 683 _ -> 684 St 685 end. 686 687lint_module(St) -> 688 case erl_lint:module(St#compile.code, 689 St#compile.ifile, St#compile.options) of 690 {ok,Ws} -> 691 %% Insert name of module as base name, if needed. This is 692 %% for compile:forms to work with listing files. 693 St1 = add_default_base(St, St#compile.code), 694 {ok,St1#compile{warnings=St1#compile.warnings ++ Ws}}; 695 {error,Es,Ws} -> 696 {error,St#compile{warnings=St#compile.warnings ++ Ws, 697 errors=St#compile.errors ++ Es}} 698 end. 699 700core_lint_module(St) -> 701 case core_lint:module(St#compile.code, St#compile.options) of 702 {ok,Ws} -> 703 {ok,St#compile{warnings=St#compile.warnings ++ Ws}}; 704 {error,Es,Ws} -> 705 {error,St#compile{warnings=St#compile.warnings ++ Ws, 706 errors=St#compile.errors ++ Es}} 707 end. 708 709%% expand_module(State) -> State' 710%% Do the common preprocessing of the input forms. 711 712expand_module(#compile{code=Code,options=Opts0}=St0) -> 713 {Mod,Exp,Forms,Opts1} = sys_pre_expand:module(Code, Opts0), 714 Opts2 = expand_opts(Opts1), 715 Opts = filter_opts(Opts2), 716 {ok,St0#compile{module=Mod,options=Opts,code={Mod,Exp,Forms}}}. 717 718core_module(#compile{code=Code0,options=Opts,ifile=File}=St) -> 719 {ok,Code,Ws} = v3_core:module(Code0, Opts), 720 {ok,St#compile{code=Code,warnings=St#compile.warnings ++ [{File,Ws}]}}. 721 722core_fold_module(#compile{code=Code0,options=Opts,ifile=File}=St) -> 723 {ok,Code,Ws} = sys_core_fold:module(Code0, Opts), 724 {ok,St#compile{code=Code,warnings=St#compile.warnings ++ [{File,Ws}]}}. 725 726test_old_inliner(#compile{options=Opts}) -> 727 %% The point of this test is to avoid loading the old inliner 728 %% if we know that it will not be used. 729 case any(fun(no_inline) -> true; 730 (_) -> false 731 end, Opts) of 732 true -> false; 733 false -> 734 any(fun({inline,_}) -> true; 735 (_) -> false 736 end, Opts) 737 end. 738 739test_core_inliner(#compile{options=Opts}) -> 740 case any(fun(no_inline) -> true; 741 (_) -> false 742 end, Opts) of 743 true -> false; 744 false -> 745 any(fun(inline) -> true; 746 (_) -> false 747 end, Opts) 748 end. 749 750core_old_inliner(#compile{code=Code0,options=Opts}=St) -> 751 case catch sys_core_inline:module(Code0, Opts) of 752 {ok,Code} -> 753 {ok,St#compile{code=Code}}; 754 {error,Es} -> 755 {error,St#compile{errors=St#compile.errors ++ Es}} 756 end. 757 758core_inline_module(#compile{code=Code0,options=Opts}=St) -> 759 Code = cerl_inline:core_transform(Code0, Opts), 760 {ok,St#compile{code=Code}}. 761 762core_dsetel_module(#compile{code=Code0,options=Opts}=St) -> 763 {ok,Code} = sys_core_dsetel:module(Code0, Opts), 764 {ok,St#compile{code=Code}}. 765 766kernel_module(#compile{code=Code0,options=Opts,ifile=File}=St) -> 767 {ok,Code,Ws} = v3_kernel:module(Code0, Opts), 768 {ok,St#compile{code=Code,warnings=St#compile.warnings ++ [{File,Ws}]}}. 769 770save_abstract_code(St) -> 771 {ok,St#compile{abstract_code=abstract_code(St)}}. 772 773abstract_code(#compile{code=Code}) -> 774 Abstr = {raw_abstract_v1,Code}, 775 case catch erlang:term_to_binary(Abstr, [compressed]) of 776 {'EXIT',_} -> term_to_binary(Abstr); 777 Other -> Other 778 end. 779 780save_core_code(St) -> 781 {ok,St#compile{core_code=cerl:from_records(St#compile.code)}}. 782 783beam_unused_labels(#compile{code=Code0}=St) -> 784 Code = beam_jump:module_labels(Code0), 785 {ok,St#compile{code=Code}}. 786 787beam_asm(#compile{ifile=File,code=Code0,abstract_code=Abst,options=Opts0}=St) -> 788 Source = filename:absname(File), 789 Opts = filter(fun is_informative_option/1, Opts0), 790 case beam_asm:module(Code0, Abst, Source, Opts) of 791 {ok,Code} -> {ok,St#compile{code=Code,abstract_code=[]}}; 792 {error,Es} -> {error,St#compile{errors=St#compile.errors ++ Es}} 793 end. 794 795test_native(#compile{options=Opts}) -> 796 %% This test must be made late, because the r7 or no_new_funs options 797 %% will turn off the native option. 798 member(native, Opts). 799 800native_compile(#compile{code=none}=St) -> {ok,St}; 801native_compile(St) -> 802 case erlang:system_info(hipe_architecture) of 803 undefined -> 804 Ws = [{St#compile.ifile,[{none,compile,no_native_support}]}], 805 {ok,St#compile{warnings=St#compile.warnings ++ Ws}}; 806 _ -> 807 native_compile_1(St) 808 end. 809 810native_compile_1(St) -> 811 Opts0 = [no_new_binaries|St#compile.options], 812 IgnoreErrors = member(ignore_native_errors, Opts0), 813 Opts = case keysearch(hipe, 1, Opts0) of 814 {value,{hipe,L}} when list(L) -> L; 815 {value,{hipe,X}} -> [X]; 816 _ -> [] 817 end, 818 case catch hipe:compile(St#compile.module, 819 St#compile.core_code, 820 St#compile.code, 821 Opts) of 822 {ok, {Type,Bin}} when binary(Bin) -> 823 {ok, embed_native_code(St, {Type,Bin})}; 824 {error, R} -> 825 case IgnoreErrors of 826 true -> 827 Ws = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}], 828 {ok,St#compile{warnings=St#compile.warnings ++ Ws}}; 829 false -> 830 Es = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}], 831 {error,St#compile{errors=St#compile.errors ++ Es}} 832 end; 833 {'EXIT',R} -> 834 case IgnoreErrors of 835 true -> 836 Ws = [{St#compile.ifile,[{none,?MODULE,{native_crash,R}}]}], 837 {ok,St#compile{warnings=St#compile.warnings ++ Ws}}; 838 false -> 839 exit(R) 840 end 841 end. 842 843embed_native_code(St, {Architecture,NativeCode}) -> 844 {ok, _, Chunks0} = beam_lib:all_chunks(St#compile.code), 845 ChunkName = hipe_unified_loader:chunk_name(Architecture), 846 Chunks1 = lists:keydelete(ChunkName, 1, Chunks0), 847 Chunks = Chunks1 ++ [{ChunkName,NativeCode}], 848 {ok, BeamPlusNative} = beam_lib:build_module(Chunks), 849 St#compile{code=BeamPlusNative}. 850 851%% Returns true if the option is informative and therefore should be included 852%% in the option list of the compiled module. 853 854is_informative_option(beam) -> false; 855is_informative_option(report_warnings) -> false; 856is_informative_option(report_errors) -> false; 857is_informative_option(binary) -> false; 858is_informative_option(verbose) -> false; 859is_informative_option(_) -> true. 860 861save_binary(#compile{code=none}=St) -> {ok,St}; 862save_binary(St) -> 863 Tfile = tmpfile(St#compile.ofile), %Temp working file 864 case write_binary(Tfile, St#compile.code, St) of 865 ok -> 866 case file:rename(Tfile, St#compile.ofile) of 867 ok -> 868 {ok,St}; 869 {error,_Error} -> 870 file:delete(Tfile), 871 Es = [{St#compile.ofile,[{none,?MODULE,{rename,Tfile}}]}], 872 {error,St#compile{errors=St#compile.errors ++ Es}} 873 end; 874 {error,_Error} -> 875 Es = [{Tfile,[{compile,write_error}]}], 876 {error,St#compile{errors=St#compile.errors ++ Es}} 877 end. 878 879write_binary(Name, Bin, St) -> 880 Opts = case member(compressed, St#compile.options) of 881 true -> [compressed]; 882 false -> [] 883 end, 884 case file:write_file(Name, Bin, Opts) of 885 ok -> ok; 886 {error,_}=Error -> Error 887 end. 888 889%% report_errors(State) -> ok 890%% report_warnings(State) -> ok 891 892report_errors(St) -> 893 case member(report_errors, St#compile.options) of 894 true -> 895 foreach(fun ({{F,_L},Eds}) -> list_errors(F, Eds); 896 ({F,Eds}) -> list_errors(F, Eds) end, 897 St#compile.errors); 898 false -> ok 899 end. 900 901report_warnings(#compile{options=Opts,warnings=Ws0}) -> 902 case member(report_warnings, Opts) of 903 true -> 904 Ws1 = flatmap(fun({{F,_L},Eds}) -> format_message(F, Eds); 905 ({F,Eds}) -> format_message(F, Eds) end, 906 Ws0), 907 Ws = ordsets:from_list(Ws1), 908 foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws); 909 false -> ok 910 end. 911 912format_message(F, [{Line,Mod,E}|Es]) -> 913 M = {Line,io_lib:format("~s:~w: Warning: ~s\n", [F,Line,Mod:format_error(E)])}, 914 [M|format_message(F, Es)]; 915format_message(F, [{Mod,E}|Es]) -> 916 M = {none,io_lib:format("~s: Warning: ~s\n", [F,Mod:format_error(E)])}, 917 [M|format_message(F, Es)]; 918format_message(_, []) -> []. 919 920%% list_errors(File, ErrorDescriptors) -> ok 921 922list_errors(F, [{Line,Mod,E}|Es]) -> 923 io:fwrite("~s:~w: ~s\n", [F,Line,Mod:format_error(E)]), 924 list_errors(F, Es); 925list_errors(F, [{Mod,E}|Es]) -> 926 io:fwrite("~s: ~s\n", [F,Mod:format_error(E)]), 927 list_errors(F, Es); 928list_errors(_F, []) -> ok. 929 930%% erlfile(Dir, Base) -> ErlFile 931%% outfile(Base, Extension, Options) -> OutputFile 932%% objfile(Base, Target, Options) -> ObjFile 933%% tmpfile(ObjFile) -> TmpFile 934%% Work out the correct input and output file names. 935 936iofile(File) when atom(File) -> 937 iofile(atom_to_list(File)); 938iofile(File) -> 939 {filename:dirname(File), filename:basename(File, ".erl")}. 940 941erlfile(Dir, Base, Suffix) -> 942 filename:join(Dir, Base++Suffix). 943 944outfile(Base, Ext, Opts) when atom(Ext) -> 945 outfile(Base, atom_to_list(Ext), Opts); 946outfile(Base, Ext, Opts) -> 947 Obase = case keysearch(outdir, 1, Opts) of 948 {value, {outdir, Odir}} -> filename:join(Odir, Base); 949 _Other -> Base % Not found or bad format 950 end, 951 Obase++"."++Ext. 952 953objfile(Base, St) -> 954 outfile(Base, "beam", St#compile.options). 955 956tmpfile(Ofile) -> 957 reverse([$#|tl(reverse(Ofile))]). 958 959%% pre_defs(Options) 960%% inc_paths(Options) 961%% Extract the predefined macros and include paths from the option list. 962 963pre_defs([{d,M,V}|Opts]) -> 964 [{M,V}|pre_defs(Opts)]; 965pre_defs([{d,M}|Opts]) -> 966 [M|pre_defs(Opts)]; 967pre_defs([_|Opts]) -> 968 pre_defs(Opts); 969pre_defs([]) -> []. 970 971inc_paths(Opts) -> 972 [ P || {i,P} <- Opts, list(P) ]. 973 974src_listing(Ext, St) -> 975 listing(fun (Lf, {_Mod,_Exp,Fs}) -> do_src_listing(Lf, Fs); 976 (Lf, Fs) -> do_src_listing(Lf, Fs) end, 977 Ext, St). 978 979do_src_listing(Lf, Fs) -> 980 foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F),"\n"]) end, 981 Fs). 982 983listing(Ext, St) -> 984 listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, St). 985 986listing(LFun, Ext, St) -> 987 Lfile = outfile(St#compile.base, Ext, St#compile.options), 988 case file:open(Lfile, [write,delayed_write]) of 989 {ok,Lf} -> 990 LFun(Lf, St#compile.code), 991 ok = file:close(Lf), 992 {ok,St}; 993 {error,_Error} -> 994 Es = [{Lfile,[{none,compile,write_error}]}], 995 {error,St#compile{errors=St#compile.errors ++ Es}} 996 end. 997 998options() -> 999 help(standard_passes()). 1000 1001help([{iff,Flag,{src_listing,Ext}}|T]) -> 1002 io:fwrite("~p - Generate .~s source listing file\n", [Flag,Ext]), 1003 help(T); 1004help([{iff,Flag,{listing,Ext}}|T]) -> 1005 io:fwrite("~p - Generate .~s file\n", [Flag,Ext]), 1006 help(T); 1007help([{iff,Flag,{Name,Fun}}|T]) when function(Fun) -> 1008 io:fwrite("~p - Run ~s\n", [Flag,Name]), 1009 help(T); 1010help([{iff,_Flag,Action}|T]) -> 1011 help(Action), 1012 help(T); 1013help([{unless,Flag,{pass,Pass}}|T]) -> 1014 io:fwrite("~p - Skip the ~s pass\n", [Flag,Pass]), 1015 help(T); 1016help([{unless,no_postopt=Flag,List}|T]) when list(List) -> 1017 %% Hard-coded knowledgde here. 1018 io:fwrite("~p - Skip all post optimisation\n", [Flag]), 1019 help(List), 1020 help(T); 1021help([{unless,_Flag,Action}|T]) -> 1022 help(Action), 1023 help(T); 1024help([_|T]) -> 1025 help(T); 1026help(_) -> 1027 ok. 1028 1029 1030%% compile(AbsFileName, Outfilename, Options) 1031%% Compile entry point for erl_compile. 1032 1033compile(File0, _OutFile, Options) -> 1034 File = shorten_filename(File0), 1035 case file(File, make_erl_options(Options)) of 1036 {ok,_Mod} -> ok; 1037 Other -> Other 1038 end. 1039 1040compile_beam(File0, _OutFile, Opts) -> 1041 File = shorten_filename(File0), 1042 case file(File, [from_beam|make_erl_options(Opts)]) of 1043 {ok,_Mod} -> ok; 1044 Other -> Other 1045 end. 1046 1047compile_asm(File0, _OutFile, Opts) -> 1048 File = shorten_filename(File0), 1049 case file(File, [asm|make_erl_options(Opts)]) of 1050 {ok,_Mod} -> ok; 1051 Other -> Other 1052 end. 1053 1054compile_core(File0, _OutFile, Opts) -> 1055 File = shorten_filename(File0), 1056 case file(File, [from_core|make_erl_options(Opts)]) of 1057 {ok,_Mod} -> ok; 1058 Other -> Other 1059 end. 1060 1061shorten_filename(Name0) -> 1062 {ok,Cwd} = file:get_cwd(), 1063 case lists:prefix(Cwd, Name0) of 1064 false -> Name0; 1065 true -> 1066 Name = case lists:nthtail(length(Cwd), Name0) of 1067 "/"++N -> N; 1068 N -> N 1069 end, 1070 Name 1071 end. 1072 1073%% Converts generic compiler options to specific options. 1074 1075make_erl_options(Opts) -> 1076 1077 %% This way of extracting will work even if the record passed 1078 %% has more fields than known during compilation. 1079 1080 Includes = Opts#options.includes, 1081 Defines = Opts#options.defines, 1082 Outdir = Opts#options.outdir, 1083 Warning = Opts#options.warning, 1084 Verbose = Opts#options.verbose, 1085 Specific = Opts#options.specific, 1086 OutputType = Opts#options.output_type, 1087 Cwd = Opts#options.cwd, 1088 1089 Options = 1090 case Verbose of 1091 true -> [verbose]; 1092 false -> [] 1093 end ++ 1094 case Warning of 1095 0 -> []; 1096 _ -> [report_warnings] 1097 end ++ 1098 map( 1099 fun ({Name, Value}) -> 1100 {d, Name, Value}; 1101 (Name) -> 1102 {d, Name} 1103 end, 1104 Defines) ++ 1105 case OutputType of 1106 undefined -> []; 1107 jam -> [jam]; 1108 beam -> [beam]; 1109 native -> [native] 1110 end, 1111 1112 Options++[report_errors, {cwd, Cwd}, {outdir, Outdir}| 1113 map(fun(Dir) -> {i, Dir} end, Includes)]++Specific. 1114