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.

131 line
4.8 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. DepsPaths = rebar_state:code_paths(State, all_deps),
  27. code:add_pathsa(DepsPaths),
  28. ProjectApps = rebar_state:project_apps(State),
  29. Providers = rebar_state:providers(State),
  30. Deps = rebar_state:deps_to_build(State),
  31. Cwd = rebar_dir:get_cwd(),
  32. %% Need to allow global config vars used on deps
  33. %% Right now no way to differeniate and just give deps a new state
  34. EmptyState = rebar_state:new(),
  35. build_apps(EmptyState, Providers, Deps),
  36. {ok, ProjectApps1} = rebar_digraph:compile_order(ProjectApps),
  37. %% Run top level hooks *before* project apps compiled but *after* deps are
  38. rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
  39. ProjectApps2 = build_apps(State, Providers, ProjectApps1),
  40. State2 = rebar_state:project_apps(State, ProjectApps2),
  41. ProjAppsPaths = [filename:join(rebar_app_info:out_dir(X), "ebin") || X <- ProjectApps2],
  42. State3 = rebar_state:code_paths(State2, all_deps, DepsPaths ++ ProjAppsPaths),
  43. rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State2),
  44. rebar_utils:cleanup_code_path(rebar_state:code_paths(State3, default)),
  45. {ok, State3}.
  46. -spec format_error(any()) -> iolist().
  47. format_error(Reason) ->
  48. io_lib:format("~p", [Reason]).
  49. build_apps(State, Providers, Apps) ->
  50. [build_app(State, Providers, AppInfo) || AppInfo <- Apps].
  51. build_app(State, Providers, AppInfo) ->
  52. AppDir = rebar_app_info:dir(AppInfo),
  53. OutDir = rebar_app_info:out_dir(AppInfo),
  54. copy_app_dirs(State, AppDir, OutDir),
  55. S = case rebar_app_info:state(AppInfo) of
  56. undefined ->
  57. C = rebar_config:consult(AppDir),
  58. rebar_state:new(State, C, AppDir);
  59. AppState ->
  60. AppState
  61. end,
  62. %% Legacy hook support
  63. rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, S),
  64. AppInfo1 = compile(S, AppInfo),
  65. rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S),
  66. AppInfo1.
  67. compile(State, AppInfo) ->
  68. ?INFO("Compiling ~s", [rebar_app_info:name(AppInfo)]),
  69. rebar_erlc_compiler:compile(State, ec_cnv:to_list(rebar_app_info:out_dir(AppInfo))),
  70. case rebar_otp_app:compile(State, AppInfo) of
  71. {ok, AppInfo1} ->
  72. AppInfo1;
  73. Error ->
  74. throw(Error)
  75. end.
  76. %% ===================================================================
  77. %% Internal functions
  78. %% ===================================================================
  79. copy_app_dirs(State, OldAppDir, AppDir) ->
  80. case ec_cnv:to_binary(filename:absname(OldAppDir)) =/=
  81. ec_cnv:to_binary(filename:absname(AppDir)) of
  82. true ->
  83. EbinDir = filename:join([OldAppDir, "ebin"]),
  84. %% copy all files from ebin if it exists
  85. case filelib:is_dir(EbinDir) of
  86. true ->
  87. OutEbin = filename:join(AppDir, "ebin"),
  88. filelib:ensure_dir(filename:join(OutEbin, "dummy.beam")),
  89. rebar_file_utils:cp_r(filelib:wildcard(filename:join(EbinDir, "*")), OutEbin);
  90. false ->
  91. ok
  92. end,
  93. filelib:ensure_dir(filename:join(AppDir, "dummy")),
  94. %% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
  95. SrcDirs = rebar_dir:all_src_dirs(State, ["src"], ["test"]),
  96. [symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"] ++ SrcDirs];
  97. false ->
  98. ok
  99. end.
  100. symlink_or_copy(OldAppDir, AppDir, Dir) ->
  101. Source = filename:join(OldAppDir, Dir),
  102. Target = filename:join(AppDir, Dir),
  103. rebar_file_utils:symlink_or_copy(Source, Target).