Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

467 řádky
19 KiB

Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
Split up the compiler DAG This is another tricky commit towards replacing the current module analysis with EPP. The compiler DAG is now being shared across multiple applications being compiled, rather than a per-application basis, which promises to allow better ordering, parallelism, and more thorough invalidation of runtime dependencies when they are modified. This however required changes: - The compiler DAG is no longer private to `rebar_compiler`, and has been extracted to the `rebar_compiler_dag` module - The compiler DAG is now started by the `rebar_prv_compile` module, which oversees the calls to `rebar_compiler` for each OTP application - The compiler DAG has been refactored to use a "dirty flag" to know if it was modified, rather than just tracking modifications in a functional manner, since the scope change (going multi-app) makes it impossible to cleanly use the functional approach without much larger changes - The DAG used to be cached within each OTP application. This is no longer possible since it is shared. Instead the DAG is stored in the state's deps_dir, which allows to cleanly split caches between regular apps for the user's project and plugins - The DAG supported a "label" mode that was used to store distinct DAGs for extra_src_dir runs and regular modules; this label is now used (and extended to `rebar_prv_compile` internals) to distinguish between "compile runs", such as "project_apps", or just "apps" (deps). The label is optional (i.e. not used by plugins which have no such need) - The extra_src_dirs for each app is now compiled using the main app's DAG, but the run takes place later in the compilation process. This may need changing to detect and prevent dependencies from src_dirs into extra_src_dirs, but this should not technically be a problem for runtime anyway. - Reworked the support for extra_src_dirs that are at the root of an umbrella project (and therefore do not belong to any single app) to use the new structure, also as part of the project_apps DAG. All tests keep passing, and this puts us in a better place to use EPP with cross-app support in the near-future.
před 5 roky
  1. -module(rebar_prv_compile).
  2. -behaviour(provider).
  3. -export([init/1,
  4. do/1,
  5. format_error/1]).
  6. -export([compile/2, compile/3]).
  7. -include_lib("providers/include/providers.hrl").
  8. -include("rebar.hrl").
  9. -define(PROVIDER, compile).
  10. -define(ERLC_HOOK, erlc_compile).
  11. -define(APP_HOOK, app_compile).
  12. -define(DEPS, [lock]).
  13. %% ===================================================================
  14. %% Public API
  15. %% ===================================================================
  16. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  17. init(State) ->
  18. State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
  19. {module, ?MODULE},
  20. {bare, true},
  21. {deps, ?DEPS},
  22. {example, "rebar3 compile"},
  23. {short_desc, "Compile apps .app.src and .erl files."},
  24. {desc, "Compile apps .app.src and .erl files."},
  25. {opts, [{deps_only, $d, "deps_only", undefined,
  26. "Only compile dependencies, no project apps will be built."}]}])),
  27. {ok, State1}.
  28. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  29. do(State) ->
  30. IsDepsOnly = is_deps_only(State),
  31. rebar_paths:set_paths([deps], State),
  32. Providers = rebar_state:providers(State),
  33. Deps = rebar_state:deps_to_build(State),
  34. copy_and_build_apps(State, Providers, Deps),
  35. State1 = case IsDepsOnly of
  36. true ->
  37. State;
  38. false ->
  39. handle_project_apps(Providers, State)
  40. end,
  41. rebar_paths:set_paths([plugins], State1),
  42. {ok, State1}.
  43. is_deps_only(State) ->
  44. {Args, _} = rebar_state:command_parsed_args(State),
  45. proplists:get_value(deps_only, Args, false).
  46. handle_project_apps(Providers, State) ->
  47. Cwd = rebar_state:dir(State),
  48. ProjectApps = rebar_state:project_apps(State),
  49. {ok, ProjectApps1} = rebar_digraph:compile_order(ProjectApps),
  50. %% Run top level hooks *before* project apps compiled but *after* deps are
  51. rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
  52. ProjectApps2 = copy_and_build_project_apps(State, Providers, ProjectApps1),
  53. State2 = rebar_state:project_apps(State, ProjectApps2),
  54. %% build extra_src_dirs in the root of multi-app projects
  55. build_root_extras(State, ProjectApps2),
  56. State3 = update_code_paths(State2, ProjectApps2),
  57. rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State2),
  58. case rebar_state:has_all_artifacts(State3) of
  59. {false, File} ->
  60. throw(?PRV_ERROR({missing_artifact, File}));
  61. true ->
  62. true
  63. end,
  64. State3.
  65. -spec format_error(any()) -> iolist().
  66. format_error({missing_artifact, File}) ->
  67. io_lib:format("Missing artifact ~ts", [File]);
  68. format_error({bad_project_builder, Name, Type, Module}) ->
  69. io_lib:format("Error building application ~s:~n Required project builder ~s function "
  70. "~s:build/1 not found", [Name, Type, Module]);
  71. format_error({unknown_project_type, Name, Type}) ->
  72. io_lib:format("Error building application ~s:~n "
  73. "No project builder is configured for type ~s", [Name, Type]);
  74. format_error(Reason) ->
  75. io_lib:format("~p", [Reason]).
  76. copy_and_build_apps(State, Providers, Apps) ->
  77. Apps0 = [prepare_app(State, Providers, App) || App <- Apps],
  78. compile(State, Providers, Apps0, apps).
  79. copy_and_build_project_apps(State, Providers, Apps) ->
  80. Apps0 = [prepare_project_app(State, Providers, App) || App <- Apps],
  81. compile(State, Providers, Apps0, project_apps).
  82. -spec compile(rebar_state:t(), [rebar_app_info:t()]) -> [rebar_app_info:t()]
  83. ; (rebar_state:t(), rebar_app_info:t()) -> rebar_app_info:t().
  84. compile(State, AppInfo) ->
  85. compile(State, rebar_state:providers(State), AppInfo).
  86. -spec compile(rebar_state:t(), [providers:t()],
  87. [rebar_app_info:t()]) -> [rebar_app_info:t()]
  88. ; (rebar_state:t(), [providers:t()],
  89. rebar_app_info:t()) -> rebar_app_info:t().
  90. compile(State, Providers, AppInfo) when not is_list(AppInfo) ->
  91. [Res] = compile(State, Providers, [AppInfo], undefined),
  92. Res;
  93. compile(State, Providers, Apps) ->
  94. compile(State, Providers, Apps, undefined).
  95. -spec compile(rebar_state:t(), [providers:t()],
  96. [rebar_app_info:t()], atom() | undefined) -> [rebar_app_info:t()].
  97. compile(State, Providers, Apps, Tag) ->
  98. ?DEBUG("Compile (~p)", [if Tag =:= undefined -> untagged; true -> Tag end]),
  99. Apps1 = [prepare_compile(State, Providers, App) || App <- Apps],
  100. Apps2 = [prepare_compilers(State, Providers, App) || App <- Apps1],
  101. Apps3 = run_compilers(State, Providers, Apps2, Tag),
  102. Apps4 = [finalize_compilers(State, Providers, App) || App <- Apps3],
  103. Apps5 = [prepare_app_file(State, Providers, App) || App <- Apps4],
  104. Apps6 = compile_app_files(State, Providers, Apps5),
  105. Apps7 = [finalize_app_file(State, Providers, App) || App <- Apps6],
  106. [finalize_compile(State, Providers, App) || App <- Apps7].
  107. prepare_app(_State, _Providers, AppInfo) ->
  108. AppDir = rebar_app_info:dir(AppInfo),
  109. OutDir = rebar_app_info:out_dir(AppInfo),
  110. copy_app_dirs(AppInfo, AppDir, OutDir),
  111. AppInfo.
  112. prepare_project_app(_State, _Providers, AppInfo) ->
  113. copy_app_dirs(AppInfo,
  114. rebar_app_info:dir(AppInfo),
  115. rebar_app_info:out_dir(AppInfo)),
  116. code:add_pathsa([rebar_app_info:ebin_dir(AppInfo)]),
  117. AppInfo.
  118. prepare_compile(State, Providers, AppInfo) ->
  119. AppDir = rebar_app_info:dir(AppInfo),
  120. rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, AppInfo, State).
  121. prepare_compilers(State, Providers, AppInfo) ->
  122. AppDir = rebar_app_info:dir(AppInfo),
  123. rebar_hooks:run_all_hooks(AppDir, pre, ?ERLC_HOOK, Providers, AppInfo, State).
  124. run_compilers(State, _Providers, Apps, Tag) ->
  125. %% Prepare a compiler digraph to be shared by all compiled applications
  126. %% in a given run, providing the ability to combine their dependency
  127. %% ordering and resources.
  128. %% The Tag allows to create a Label when someone cares about a specific
  129. %% run for compilation;
  130. DAGLabel = case Tag of
  131. undefined -> undefined;
  132. _ -> atom_to_list(Tag)
  133. end,
  134. %% The Dir for the DAG is set to deps_dir so builds taking place
  135. %% in different contexts (i.e. plugins) don't risk clobbering regular deps.
  136. Dir = rebar_dir:deps_dir(State),
  137. CritMeta = [], % used to be incldirs per app
  138. DAGs = [{Mod, rebar_compiler_dag:init(Dir, Mod, DAGLabel, CritMeta)}
  139. || Mod <- rebar_state:compilers(State)],
  140. %% Compile all the apps
  141. build_apps(DAGs, Apps, State),
  142. %% Potentially store shared compiler DAGs so next runs can easily
  143. %% share the base information for easy re-scans.
  144. lists:foreach(fun({Mod, G}) ->
  145. rebar_compiler_dag:maybe_store(G, Dir, Mod, DAGLabel, CritMeta),
  146. rebar_compiler_dag:terminate(G)
  147. end, DAGs),
  148. Apps.
  149. finalize_compilers(State, Providers, AppInfo) ->
  150. AppDir = rebar_app_info:dir(AppInfo),
  151. rebar_hooks:run_all_hooks(AppDir, post, ?ERLC_HOOK, Providers, AppInfo, State).
  152. prepare_app_file(State, Providers, AppInfo) ->
  153. AppDir = rebar_app_info:dir(AppInfo),
  154. rebar_hooks:run_all_hooks(AppDir, pre, ?APP_HOOK, Providers, AppInfo, State).
  155. compile_app_files(State, Providers, Apps) ->
  156. %% Load plugins back for make_vsn calls in custom resources.
  157. %% The rebar_otp_app compilation step is safe regarding the
  158. %% overall path management, so we can just load all plugins back
  159. %% in memory.
  160. rebar_paths:set_paths([plugins], State),
  161. NewApps = [compile_app_file(State, Providers, App) || App <- Apps],
  162. %% Clean up after ourselves, leave things as they were with deps first
  163. rebar_paths:set_paths([deps], State),
  164. NewApps.
  165. compile_app_file(State, _Providers, AppInfo) ->
  166. case rebar_otp_app:compile(State, AppInfo) of
  167. {ok, AppInfo2} -> AppInfo2;
  168. Error -> throw(Error)
  169. end.
  170. finalize_app_file(State, Providers, AppInfo) ->
  171. AppDir = rebar_app_info:dir(AppInfo),
  172. rebar_hooks:run_all_hooks(AppDir, post, ?APP_HOOK, Providers, AppInfo, State).
  173. finalize_compile(State, Providers, AppInfo) ->
  174. AppDir = rebar_app_info:dir(AppInfo),
  175. AppInfo2 = rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, AppInfo, State),
  176. has_all_artifacts(AppInfo),
  177. AppInfo2.
  178. build_root_extras(State, Apps) ->
  179. %% The root extra src dirs belong to no specific applications;
  180. %% because the compiler works on OTP apps, we instead build
  181. %% a fake AppInfo record that only contains the root extra_src
  182. %% directories, has access to all the top-level apps' public
  183. %% include files, and builds to a specific extra outdir.
  184. %% TODO: figure out digraph strategy to properly ensure no
  185. %% cross-contamination but proper change detection.
  186. BaseDir = rebar_state:dir(State),
  187. F = fun(App) -> rebar_app_info:dir(App) == BaseDir end,
  188. case lists:any(F, Apps) of
  189. true ->
  190. [];
  191. false ->
  192. ProjOpts = rebar_state:opts(State),
  193. Extras = rebar_dir:extra_src_dirs(ProjOpts, []),
  194. {ok, VirtApp} = rebar_app_info:new("extra", "0.0.0", BaseDir, []),
  195. VirtApps = extra_virtual_apps(State, VirtApp, Extras),
  196. %% re-use the project-apps digraph?
  197. run_compilers(State, [], VirtApps, project_apps)
  198. end.
  199. extra_virtual_apps(_, _, []) ->
  200. [];
  201. extra_virtual_apps(State, VApp0, [Dir|Dirs]) ->
  202. SrcDir = filename:join([rebar_state:dir(State), Dir]),
  203. case ec_file:is_dir(SrcDir) of
  204. false ->
  205. extra_virtual_apps(State, VApp0, Dirs);
  206. true ->
  207. BaseDir = filename:join([rebar_dir:base_dir(State), "extras"]),
  208. OutDir = filename:join([BaseDir, Dir]),
  209. copy(rebar_state:dir(State), BaseDir, Dir),
  210. VApp1 = rebar_app_info:out_dir(VApp0, BaseDir),
  211. VApp2 = rebar_app_info:ebin_dir(VApp1, OutDir),
  212. Opts = rebar_state:opts(State),
  213. VApp3 = rebar_app_info:opts(VApp2, Opts),
  214. [rebar_app_info:set(VApp3, src_dirs, [OutDir])
  215. | extra_virtual_apps(State, VApp0, Dirs)]
  216. end.
  217. %% ===================================================================
  218. %% Internal functions
  219. %% ===================================================================
  220. build_apps(DAGs, Apps, State) ->
  221. {Rebar3, Custom} = lists:partition(
  222. fun(AppInfo) ->
  223. Type = rebar_app_info:project_type(AppInfo),
  224. Type =:= rebar3 orelse Type =:= undefined
  225. end,
  226. Apps
  227. ),
  228. [build_custom_builder_app(AppInfo, State) || AppInfo <- Custom],
  229. build_rebar3_apps(DAGs, Rebar3, State).
  230. build_custom_builder_app(AppInfo, State) ->
  231. ?INFO("Compiling ~ts", [rebar_app_info:name(AppInfo)]),
  232. Type = rebar_app_info:project_type(AppInfo),
  233. ProjectBuilders = rebar_state:project_builders(State),
  234. case lists:keyfind(Type, 1, ProjectBuilders) of
  235. {_, Module} ->
  236. %% load plugins since thats where project builders would be,
  237. %% prevents parallelism at this level.
  238. rebar_paths:set_paths([deps, plugins], State),
  239. Res = Module:build(AppInfo),
  240. rebar_paths:set_paths([deps], State),
  241. case Res of
  242. ok -> ok;
  243. {error, Reason} -> throw({error, {Module, Reason}})
  244. end;
  245. _ ->
  246. throw(?PRV_ERROR({unknown_project_type, rebar_app_info:name(AppInfo), Type}))
  247. end.
  248. build_rebar3_apps(DAGs, Apps, _State) when DAGs =:= []; Apps =:= [] ->
  249. %% No apps to actually build, probably just other compile phases
  250. %% to run for non-rebar3 apps, someone wanting .app files built,
  251. %% or just needing the hooks to run maybe.
  252. ok;
  253. build_rebar3_apps(DAGs, Apps, State) ->
  254. rebar_paths:set_paths([deps], State),
  255. %% To maintain output order, we need to mention each app being compiled
  256. %% in order, even if the order isn't really there anymore due to each
  257. %% compiler being run in broken sequence. The last compiler tends to be
  258. %% the big ERLC one so we use the last compiler for the output.
  259. LastDAG = lists:last(DAGs),
  260. %% we actually need to compile each DAG one after the other to prevent
  261. %% issues where a .yrl file that generates a .erl file gets to be seen.
  262. [begin
  263. {Ctx, ReorderedApps} = rebar_compiler:analyze_all(DAG, Apps),
  264. lists:foreach(
  265. fun(AppInfo) ->
  266. DAG =:= LastDAG andalso
  267. ?INFO("Compiling ~ts", [rebar_app_info:name(AppInfo)]),
  268. rebar_compiler:compile_analyzed(DAG, AppInfo, Ctx)
  269. end,
  270. ReorderedApps
  271. )
  272. end || DAG <- DAGs],
  273. ok.
  274. update_code_paths(State, ProjectApps) ->
  275. ProjAppsPaths = paths_for_apps(ProjectApps),
  276. ExtrasPaths = paths_for_extras(State, ProjectApps),
  277. DepsPaths = rebar_state:code_paths(State, all_deps),
  278. rebar_state:code_paths(State, all_deps, DepsPaths ++ ProjAppsPaths ++ ExtrasPaths).
  279. paths_for_apps(Apps) -> paths_for_apps(Apps, []).
  280. paths_for_apps([], Acc) -> Acc;
  281. paths_for_apps([App|Rest], Acc) ->
  282. {_SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_app_info:opts(App)),
  283. Paths = [filename:join([rebar_app_info:out_dir(App), Dir]) || Dir <- ["ebin"|ExtraDirs]],
  284. FilteredPaths = lists:filter(fun ec_file:is_dir/1, Paths),
  285. paths_for_apps(Rest, Acc ++ FilteredPaths).
  286. paths_for_extras(State, Apps) ->
  287. F = fun(App) -> rebar_app_info:dir(App) == rebar_state:dir(State) end,
  288. %% check that this app hasn't already been dealt with
  289. case lists:any(F, Apps) of
  290. false -> paths_for_extras(State);
  291. true -> []
  292. end.
  293. paths_for_extras(State) ->
  294. {_SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_state:opts(State)),
  295. Paths = [filename:join([rebar_dir:base_dir(State), "extras", Dir]) || Dir <- ExtraDirs],
  296. lists:filter(fun ec_file:is_dir/1, Paths).
  297. has_all_artifacts(AppInfo1) ->
  298. case rebar_app_info:has_all_artifacts(AppInfo1) of
  299. {false, File} ->
  300. throw(?PRV_ERROR({missing_artifact, File}));
  301. true ->
  302. rebar_app_utils:lint_app_info(AppInfo1),
  303. true
  304. end.
  305. copy_app_dirs(AppInfo, OldAppDir, AppDir) ->
  306. case rebar_utils:to_binary(filename:absname(OldAppDir)) =/=
  307. rebar_utils:to_binary(filename:absname(AppDir)) of
  308. true ->
  309. EbinDir = filename:join([OldAppDir, "ebin"]),
  310. %% copy all files from ebin if it exists
  311. case filelib:is_dir(EbinDir) of
  312. true ->
  313. OutEbin = filename:join([AppDir, "ebin"]),
  314. filelib:ensure_dir(filename:join([OutEbin, "dummy.beam"])),
  315. rebar_file_utils:cp_r(filelib:wildcard(filename:join([EbinDir, "*"])), OutEbin);
  316. false ->
  317. ok
  318. end,
  319. filelib:ensure_dir(filename:join([AppDir, "dummy"])),
  320. %% link or copy mibs if it exists
  321. case filelib:is_dir(filename:join([OldAppDir, "mibs"])) of
  322. true ->
  323. %% If mibs exist it means we must ensure priv exists.
  324. %% mibs files are compiled to priv/mibs/
  325. filelib:ensure_dir(filename:join([OldAppDir, "priv", "dummy"])),
  326. symlink_or_copy(OldAppDir, AppDir, "mibs");
  327. false ->
  328. ok
  329. end,
  330. {SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_app_info:opts(AppInfo)),
  331. %% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
  332. %% priv/ and include/ are symlinked unconditionally to allow hooks
  333. %% to write to them _after_ compilation has taken place when the
  334. %% initial directory did not, and still work
  335. [symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"]],
  336. [symlink_or_copy_existing(OldAppDir, AppDir, Dir) || Dir <- SrcDirs],
  337. %% copy all extra_src_dirs as they build into themselves and linking means they
  338. %% are shared across profiles
  339. [copy(OldAppDir, AppDir, Dir) || Dir <- ExtraDirs];
  340. false ->
  341. ok
  342. end.
  343. symlink_or_copy(OldAppDir, AppDir, Dir) ->
  344. Source = filename:join([OldAppDir, Dir]),
  345. Target = filename:join([AppDir, Dir]),
  346. rebar_file_utils:symlink_or_copy(Source, Target).
  347. symlink_or_copy_existing(OldAppDir, AppDir, Dir) ->
  348. Source = filename:join([OldAppDir, Dir]),
  349. Target = filename:join([AppDir, Dir]),
  350. case ec_file:is_dir(Source) of
  351. true -> rebar_file_utils:symlink_or_copy(Source, Target);
  352. false -> ok
  353. end.
  354. copy(OldAppDir, AppDir, Dir) ->
  355. Source = filename:join([OldAppDir, Dir]),
  356. Target = filename:join([AppDir, Dir]),
  357. case ec_file:is_dir(Source) of
  358. true -> copy(Source, Target);
  359. false -> ok
  360. end.
  361. %% TODO: use ec_file:copy/2 to do this, it preserves timestamps and
  362. %% may prevent recompilation of files in extra dirs
  363. copy(Source, Source) ->
  364. %% allow users to specify a directory in _build as a directory
  365. %% containing additional source/tests
  366. ok;
  367. copy(Source, Target) ->
  368. %% important to do this so no files are copied onto themselves
  369. %% which truncates them to zero length on some platforms
  370. ok = delete_if_symlink(Target),
  371. ok = filelib:ensure_dir(filename:join([Target, "dummy.beam"])),
  372. {ok, Files} = rebar_utils:list_dir(Source),
  373. case [filename:join([Source, F]) || F <- Files] of
  374. [] -> ok;
  375. Paths -> rebar_file_utils:cp_r(Paths, Target)
  376. end.
  377. delete_if_symlink(Path) ->
  378. case ec_file:is_symlink(Path) of
  379. true -> file:delete(Path);
  380. false -> ok
  381. end.
  382. resolve_src_dirs(Opts) ->
  383. SrcDirs = rebar_dir:src_dirs(Opts, ["src"]),
  384. ExtraDirs = rebar_dir:extra_src_dirs(Opts, []),
  385. normalize_src_dirs(SrcDirs, ExtraDirs).
  386. %% remove duplicates and make sure no directories that exist
  387. %% in src_dirs also exist in extra_src_dirs
  388. normalize_src_dirs(SrcDirs, ExtraDirs) ->
  389. S = lists:usort(SrcDirs),
  390. E = lists:subtract(lists:usort(ExtraDirs), S),
  391. ok = warn_on_problematic_directories(S ++ E),
  392. {S, E}.
  393. %% warn when directories called `eunit' and `ct' are added to compile dirs
  394. warn_on_problematic_directories(AllDirs) ->
  395. F = fun(Dir) ->
  396. case is_a_problem(Dir) of
  397. true -> ?WARN("Possible name clash with directory ~p.", [Dir]);
  398. false -> ok
  399. end
  400. end,
  401. lists:foreach(F, AllDirs).
  402. is_a_problem("eunit") -> true;
  403. is_a_problem("common_test") -> true;
  404. is_a_problem(_) -> false.