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

153 行
5.9 KiB

  1. -module(rebar_prv_compile).
  2. -behaviour(provider).
  3. -export([init/1,
  4. do/1,
  5. format_error/1]).
  6. -export([compile/3]).
  7. -include_lib("providers/include/providers.hrl").
  8. -include("rebar.hrl").
  9. -define(PROVIDER, compile).
  10. -define(DEPS, [lock]).
  11. %% ===================================================================
  12. %% Public API
  13. %% ===================================================================
  14. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  15. init(State) ->
  16. State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
  17. {module, ?MODULE},
  18. {bare, true},
  19. {deps, ?DEPS},
  20. {example, "rebar3 compile"},
  21. {short_desc, "Compile apps .app.src and .erl files."},
  22. {desc, "Compile apps .app.src and .erl files."},
  23. {opts, []}])),
  24. {ok, State1}.
  25. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  26. do(State) ->
  27. DepsPaths = rebar_state:code_paths(State, all_deps),
  28. PluginDepsPaths = rebar_state:code_paths(State, all_plugin_deps),
  29. rebar_utils:remove_from_code_path(PluginDepsPaths),
  30. code:add_pathsa(DepsPaths),
  31. ProjectApps = rebar_state:project_apps(State),
  32. Providers = rebar_state:providers(State),
  33. Deps = rebar_state:deps_to_build(State),
  34. Cwd = rebar_state:dir(State),
  35. %% Need to allow global config vars used on deps.
  36. %% Right now no way to differeniate and just give deps a new state.
  37. %% But need an account of "all deps" for some hooks to use.
  38. EmptyState = rebar_state:new(),
  39. build_apps(rebar_state:all_deps(EmptyState,
  40. rebar_state:all_deps(State)), Providers, Deps),
  41. {ok, ProjectApps1} = rebar_digraph:compile_order(ProjectApps),
  42. %% Run top level hooks *before* project apps compiled but *after* deps are
  43. rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
  44. ProjectApps2 = build_apps(State, Providers, ProjectApps1),
  45. State2 = rebar_state:project_apps(State, ProjectApps2),
  46. ProjAppsPaths = [filename:join(rebar_app_info:out_dir(X), "ebin") || X <- ProjectApps2],
  47. State3 = rebar_state:code_paths(State2, all_deps, DepsPaths ++ ProjAppsPaths),
  48. rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State2),
  49. has_all_artifacts(State3),
  50. rebar_utils:cleanup_code_path(rebar_state:code_paths(State3, default)),
  51. {ok, State3}.
  52. -spec format_error(any()) -> iolist().
  53. format_error({missing_artifact, File}) ->
  54. io_lib:format("Missing artifact ~s", [File]);
  55. format_error(Reason) ->
  56. io_lib:format("~p", [Reason]).
  57. build_apps(State, Providers, Apps) ->
  58. [build_app(State, Providers, AppInfo) || AppInfo <- Apps].
  59. build_app(State, Providers, AppInfo) ->
  60. AppDir = rebar_app_info:dir(AppInfo),
  61. OutDir = rebar_app_info:out_dir(AppInfo),
  62. copy_app_dirs(State, AppDir, OutDir),
  63. S = rebar_app_info:state_or_new(State, AppInfo),
  64. S1 = rebar_state:all_deps(S, rebar_state:all_deps(State)),
  65. compile(S1, Providers, AppInfo).
  66. compile(State, Providers, AppInfo) ->
  67. ?INFO("Compiling ~s", [rebar_app_info:name(AppInfo)]),
  68. AppDir = rebar_app_info:dir(AppInfo),
  69. rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, State),
  70. rebar_erlc_compiler:compile(State, ec_cnv:to_list(rebar_app_info:out_dir(AppInfo))),
  71. case rebar_otp_app:compile(State, AppInfo) of
  72. {ok, AppInfo1} ->
  73. rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, State),
  74. has_all_artifacts(State),
  75. AppInfo1;
  76. Error ->
  77. throw(Error)
  78. end.
  79. %% ===================================================================
  80. %% Internal functions
  81. %% ===================================================================
  82. has_all_artifacts(State) ->
  83. case rebar_state:has_all_artifacts(State) of
  84. {false, File} ->
  85. throw(?PRV_ERROR({missing_artifact, File}));
  86. true ->
  87. true
  88. end.
  89. copy_app_dirs(State, OldAppDir, AppDir) ->
  90. case ec_cnv:to_binary(filename:absname(OldAppDir)) =/=
  91. ec_cnv:to_binary(filename:absname(AppDir)) of
  92. true ->
  93. EbinDir = filename:join([OldAppDir, "ebin"]),
  94. %% copy all files from ebin if it exists
  95. case filelib:is_dir(EbinDir) of
  96. true ->
  97. OutEbin = filename:join(AppDir, "ebin"),
  98. filelib:ensure_dir(filename:join(OutEbin, "dummy.beam")),
  99. rebar_file_utils:cp_r(filelib:wildcard(filename:join(EbinDir, "*")), OutEbin);
  100. false ->
  101. ok
  102. end,
  103. filelib:ensure_dir(filename:join(AppDir, "dummy")),
  104. %% link or copy mibs if it exists
  105. case filelib:is_dir(filename:join(OldAppDir, "mibs")) of
  106. true ->
  107. %% If mibs exist it means we must ensure priv exists.
  108. %% mibs files are compiled to priv/mibs/
  109. filelib:ensure_dir(filename:join([OldAppDir, "priv", "dummy"])),
  110. symlink_or_copy(OldAppDir, AppDir, "mibs");
  111. false ->
  112. ok
  113. end,
  114. %% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
  115. SrcDirs = rebar_dir:all_src_dirs(State, ["src"], ["test"]),
  116. [symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"] ++ SrcDirs];
  117. false ->
  118. ok
  119. end.
  120. symlink_or_copy(OldAppDir, AppDir, Dir) ->
  121. Source = filename:join(OldAppDir, Dir),
  122. Target = filename:join(AppDir, Dir),
  123. rebar_file_utils:symlink_or_copy(Source, Target).