PageRenderTime 54ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/compiler/src/compile.erl

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