您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

160 行
6.4 KiB

15 年前
15 年前
  1. %% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. -module(rebar_erlc_compiler).
  28. -export([compile/2,
  29. clean/2]).
  30. -export([doterl_compile/2]).
  31. -include("rebar.hrl").
  32. %% ===================================================================
  33. %% Public API
  34. %% ===================================================================
  35. compile(Config, _AppFile) ->
  36. doterl_compile(Config, "ebin"),
  37. rebar_base_compiler:run(Config, rebar_config:get_list(Config, mib_first_files, []),
  38. "mibs", ".mib", "priv/mibs", ".bin",
  39. fun compile_mib/3).
  40. clean(_Config, _AppFile) ->
  41. %% TODO: This would be more portable if it used Erlang to traverse
  42. %% the dir structure and delete each file; however it would also
  43. %% much slower.
  44. ok = rebar_file_utils:rm_rf("ebin/*.beam priv/mibs/*.bin"),
  45. %% Erlang compilation is recursive, so it's possible that we have a nested
  46. %% directory structure in ebin with .beam files within. As such, we want
  47. %% to scan whatever is left in the ebin/ directory for sub-dirs which
  48. %% satisfy our criteria. TODO: Is there a better way to do this?
  49. BeamFiles = filelib:fold_files("ebin", "^.*\\.beam\$", true,
  50. fun(F, BeamFiles) -> BeamFiles ++ [F] end, []),
  51. rebar_file_utils:delete_each(BeamFiles),
  52. ok.
  53. %% ===================================================================
  54. %% .erl Compilation API (externally used by only eunit)
  55. %% ===================================================================
  56. doterl_compile(Config, Outdir) ->
  57. FirstErls = rebar_config:get_list(Config, erl_first_files, []),
  58. RestErls = [Source || Source <- rebar_utils:find_files("src", ".*.erl"),
  59. lists:member(Source, FirstErls) == false],
  60. rebar_base_compiler:run(Config, FirstErls, RestErls,
  61. fun(S, C) -> internal_erl_compile(S, C, Outdir) end).
  62. %% ===================================================================
  63. %% Internal functions
  64. %% ===================================================================
  65. include_path(Source, Config) ->
  66. ErlOpts = rebar_config:get(Config, erl_opts, []),
  67. [filename:dirname(Source)] ++ proplists:get_all_values(i, ErlOpts).
  68. inspect(Source, IncludePath) ->
  69. ModuleDefault = filename:basename(Source, ".erl"),
  70. case epp:open(Source, IncludePath) of
  71. {ok, Epp} ->
  72. inspect_epp(Epp, ModuleDefault, []);
  73. {error, Reason} ->
  74. ?DEBUG("Failed to inspect ~s: ~p\n", [Source, Reason]),
  75. {ModuleDefault, []}
  76. end.
  77. inspect_epp(Epp, Module, Includes) ->
  78. case epp:parse_erl_form(Epp) of
  79. {ok, {attribute, _, module, ActualModule}} when is_list(ActualModule) ->
  80. %% If the module name includes package info, we get a list of atoms...
  81. case is_list(ActualModule) of
  82. true ->
  83. ActualModuleStr = string:join([atom_to_list(P) || P <- ActualModule], ".");
  84. false ->
  85. ActualModuleStr = atom_to_list(ActualModule)
  86. end,
  87. inspect_epp(Epp, ActualModuleStr, Includes);
  88. {ok, {attribute, 1, file, {Module, 1}}} ->
  89. inspect_epp(Epp, Module, Includes);
  90. {ok, {attribute, 1, file, {IncFile, 1}}} ->
  91. inspect_epp(Epp, Module, [IncFile | Includes]);
  92. {eof, _} ->
  93. epp:close(Epp),
  94. {Module, Includes};
  95. _ ->
  96. inspect_epp(Epp, Module, Includes)
  97. end.
  98. needs_compile(Source, Target, Hrls) ->
  99. TargetLastMod = filelib:last_modified(Target),
  100. lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end,
  101. [Source] ++ Hrls).
  102. internal_erl_compile(Source, Config, Outdir) ->
  103. %% Determine the target name and includes list by inspecting the source file
  104. {Module, Hrls} = inspect(Source, include_path(Source, Config)),
  105. %% Construct the target filename
  106. Target = filename:join([Outdir | string:tokens(Module, ".")]) ++ ".beam",
  107. %% If the file needs compilation, based on last mod date of includes or
  108. %% the target,
  109. case needs_compile(Source, Target, Hrls) of
  110. true ->
  111. Opts = [{i, "include"}, {outdir, filename:dirname(Target)}, report, return] ++
  112. rebar_config:get(Config, erl_opts, []),
  113. case compile:file(Source, Opts) of
  114. {ok, _, []} ->
  115. ok;
  116. {ok, _, _Warnings} ->
  117. %% We got at least one warning -- if fail_on_warning is in options, fail
  118. case lists:member(fail_on_warning, Opts) of
  119. true ->
  120. ?FAIL;
  121. false ->
  122. ok
  123. end;
  124. _ ->
  125. ?FAIL
  126. end;
  127. false ->
  128. skipped
  129. end.
  130. compile_mib(Source, _Target, Config) ->
  131. Opts = [{outdir, "priv/mibs"}, {i, ["priv/mibs"]}] ++
  132. rebar_config:get(Config, mib_opts, []),
  133. case snmpc:compile(Source, Opts) of
  134. {ok, _} ->
  135. ok;
  136. {error, compilation_failed} ->
  137. ?FAIL
  138. end.