You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
4.7 KiB

  1. -module(rebar_prv_compile).
  2. -behaviour(provider).
  3. -export([init/1,
  4. do/1,
  5. format_error/1]).
  6. -export([compile/2]).
  7. -include("rebar.hrl").
  8. -define(PROVIDER, compile).
  9. -define(DEPS, [lock]).
  10. %% ===================================================================
  11. %% Public API
  12. %% ===================================================================
  13. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  14. init(State) ->
  15. State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
  16. {module, ?MODULE},
  17. {bare, false},
  18. {deps, ?DEPS},
  19. {example, "rebar3 compile"},
  20. {short_desc, "Compile apps .app.src and .erl files."},
  21. {desc, "Compile apps .app.src and .erl files."},
  22. {opts, []}])),
  23. {ok, State1}.
  24. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  25. do(State) ->
  26. ProjectApps = rebar_state:project_apps(State),
  27. Providers = rebar_state:providers(State),
  28. Deps = rebar_state:deps_to_build(State),
  29. Cwd = rebar_dir:get_cwd(),
  30. rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
  31. %% Need to allow global config vars used on deps
  32. %% Right now no way to differeniate and just give deps a new state
  33. EmptyState = rebar_state:new(),
  34. build_apps(EmptyState, Providers, Deps),
  35. %% Use the project State for building project apps
  36. %% Set hooks to empty so top-level hooks aren't run for each project app
  37. State2 = rebar_state:set(rebar_state:set(State, post_hooks, []), pre_hooks, []),
  38. ProjectApps1 = build_apps(State2, Providers, ProjectApps),
  39. rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
  40. {ok, rebar_state:project_apps(State, ProjectApps1)}.
  41. -spec format_error(any()) -> iolist().
  42. format_error(Reason) ->
  43. io_lib:format("~p", [Reason]).
  44. build_apps(State, Providers, Apps) ->
  45. [build_app(State, Providers, AppInfo) || AppInfo <- Apps].
  46. build_app(State, Providers, AppInfo) ->
  47. AppDir = rebar_app_info:dir(AppInfo),
  48. OutDir = rebar_app_info:out_dir(AppInfo),
  49. copy_app_dirs(State, AppDir, OutDir),
  50. S = case rebar_app_info:state(AppInfo) of
  51. undefined ->
  52. C = rebar_config:consult(AppDir),
  53. rebar_state:new(State, C, AppDir);
  54. AppState ->
  55. AppState
  56. end,
  57. %% Legacy hook support
  58. rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, S),
  59. AppInfo1 = compile(S, AppInfo),
  60. rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S),
  61. true = code:add_patha(rebar_app_info:ebin_dir(AppInfo1)),
  62. AppInfo1.
  63. compile(State, AppInfo) ->
  64. ?INFO("Compiling ~s", [rebar_app_info:name(AppInfo)]),
  65. rebar_erlc_compiler:compile(State, ec_cnv:to_list(rebar_app_info:out_dir(AppInfo))),
  66. case rebar_otp_app:compile(State, AppInfo) of
  67. {ok, AppInfo1} ->
  68. AppInfo1;
  69. Error ->
  70. throw(Error)
  71. end.
  72. %% ===================================================================
  73. %% Internal functions
  74. %% ===================================================================
  75. copy_app_dirs(State, OldAppDir, AppDir) ->
  76. case ec_cnv:to_binary(filename:absname(OldAppDir)) =/=
  77. ec_cnv:to_binary(filename:absname(AppDir)) of
  78. true ->
  79. EbinDir = filename:join([OldAppDir, "ebin"]),
  80. %% copy all files from ebin if it exists
  81. case filelib:is_dir(EbinDir) of
  82. true ->
  83. OutEbin = filename:join(AppDir, "ebin"),
  84. filelib:ensure_dir(filename:join(OutEbin, "dummy.beam")),
  85. rebar_file_utils:cp_r(filelib:wildcard(filename:join(EbinDir, "*")), OutEbin);
  86. false ->
  87. ok
  88. end,
  89. filelib:ensure_dir(filename:join(AppDir, "dummy")),
  90. %% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
  91. ErlOpts = rebar_utils:erl_opts(State),
  92. SrcDirs = proplists:get_value(src_dirs, ErlOpts, ["src"]),
  93. [symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include", "test"] ++ SrcDirs];
  94. false ->
  95. ok
  96. end.
  97. symlink_or_copy(OldAppDir, AppDir, Dir) ->
  98. Source = filename:join(OldAppDir, Dir),
  99. Target = filename:join(AppDir, Dir),
  100. rebar_file_utils:symlink_or_copy(Source, Target).