No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

436 líneas
18 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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
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.
hace 5 años
  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. rebar_paths:set_paths([deps], State),
  141. %% Compile all the apps
  142. [build_app(DAGs, AppInfo, State) || AppInfo <- Apps],
  143. %% Potentially store shared compiler DAGs so next runs can easily
  144. %% share the base information for easy re-scans.
  145. lists:foreach(fun({Mod, G}) ->
  146. rebar_compiler_dag:maybe_store(G, Dir, Mod, DAGLabel, CritMeta),
  147. rebar_compiler_dag:terminate(G)
  148. end, DAGs),
  149. Apps.
  150. finalize_compilers(State, Providers, AppInfo) ->
  151. AppDir = rebar_app_info:dir(AppInfo),
  152. rebar_hooks:run_all_hooks(AppDir, post, ?ERLC_HOOK, Providers, AppInfo, State).
  153. prepare_app_file(State, Providers, AppInfo) ->
  154. AppDir = rebar_app_info:dir(AppInfo),
  155. rebar_hooks:run_all_hooks(AppDir, pre, ?APP_HOOK, Providers, AppInfo, State).
  156. compile_app_files(State, Providers, Apps) ->
  157. %% Load plugins back for make_vsn calls in custom resources.
  158. %% The rebar_otp_app compilation step is safe regarding the
  159. %% overall path management, so we can just load all plugins back
  160. %% in memory.
  161. rebar_paths:set_paths([plugins], State),
  162. NewApps = [compile_app_file(State, Providers, App) || App <- Apps],
  163. %% Clean up after ourselves, leave things as they were with deps first
  164. rebar_paths:set_paths([deps], State),
  165. NewApps.
  166. compile_app_file(State, _Providers, AppInfo) ->
  167. case rebar_otp_app:compile(State, AppInfo) of
  168. {ok, AppInfo2} -> AppInfo2;
  169. Error -> throw(Error)
  170. end.
  171. finalize_app_file(State, Providers, AppInfo) ->
  172. AppDir = rebar_app_info:dir(AppInfo),
  173. rebar_hooks:run_all_hooks(AppDir, post, ?APP_HOOK, Providers, AppInfo, State).
  174. finalize_compile(State, Providers, AppInfo) ->
  175. AppDir = rebar_app_info:dir(AppInfo),
  176. AppInfo2 = rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, AppInfo, State),
  177. has_all_artifacts(AppInfo),
  178. AppInfo2.
  179. build_root_extras(State, Apps) ->
  180. %% The root extra src dirs belong to no specific applications;
  181. %% because the compiler works on OTP apps, we instead build
  182. %% a fake AppInfo record that only contains the root extra_src
  183. %% directories, has access to all the top-level apps' public
  184. %% include files, and builds to a specific extra outdir.
  185. %% TODO: figure out digraph strategy to properly ensure no
  186. %% cross-contamination but proper change detection.
  187. BaseDir = rebar_state:dir(State),
  188. F = fun(App) -> rebar_app_info:dir(App) == BaseDir end,
  189. case lists:any(F, Apps) of
  190. true ->
  191. [];
  192. false ->
  193. ProjOpts = rebar_state:opts(State),
  194. Extras = rebar_dir:extra_src_dirs(ProjOpts, []),
  195. {ok, VirtApp} = rebar_app_info:new("extra", "0.0.0", BaseDir, []),
  196. VirtApps = extra_virtual_apps(State, VirtApp, Extras),
  197. %% re-use the project-apps digraph?
  198. run_compilers(State, [], VirtApps, project_apps)
  199. end.
  200. extra_virtual_apps(_, _, []) ->
  201. [];
  202. extra_virtual_apps(State, VApp0, [Dir|Dirs]) ->
  203. SrcDir = filename:join([rebar_state:dir(State), Dir]),
  204. case ec_file:is_dir(SrcDir) of
  205. false ->
  206. extra_virtual_apps(State, VApp0, Dirs);
  207. true ->
  208. BaseDir = filename:join([rebar_dir:base_dir(State), "extras"]),
  209. OutDir = filename:join([BaseDir, Dir]),
  210. copy(rebar_state:dir(State), BaseDir, Dir),
  211. VApp1 = rebar_app_info:out_dir(VApp0, BaseDir),
  212. VApp2 = rebar_app_info:ebin_dir(VApp1, OutDir),
  213. Opts = rebar_state:opts(State),
  214. VApp3 = rebar_app_info:opts(VApp2, Opts),
  215. [rebar_app_info:set(VApp3, src_dirs, [OutDir])
  216. | extra_virtual_apps(State, VApp0, Dirs)]
  217. end.
  218. %% ===================================================================
  219. %% Internal functions
  220. %% ===================================================================
  221. build_app(DAGs, AppInfo, State) ->
  222. ?INFO("Compiling ~ts", [rebar_app_info:name(AppInfo)]),
  223. case rebar_app_info:project_type(AppInfo) of
  224. Type when Type =:= rebar3 ; Type =:= undefined ->
  225. %% assume the deps paths are already set by the caller (run_compilers/3)
  226. %% and shared for multiple apps to save work.
  227. rebar_compiler:compile_all(DAGs, AppInfo);
  228. Type ->
  229. ProjectBuilders = rebar_state:project_builders(State),
  230. case lists:keyfind(Type, 1, ProjectBuilders) of
  231. {_, Module} ->
  232. %% load plugins since thats where project builders would be,
  233. %% prevents parallelism at this level.
  234. rebar_paths:set_paths([deps, plugins], State),
  235. Res = Module:build(AppInfo),
  236. rebar_paths:set_paths([deps], State),
  237. case Res of
  238. ok -> ok;
  239. {error, Reason} -> throw({error, {Module, Reason}})
  240. end;
  241. _ ->
  242. throw(?PRV_ERROR({unknown_project_type, rebar_app_info:name(AppInfo), Type}))
  243. end
  244. end.
  245. update_code_paths(State, ProjectApps) ->
  246. ProjAppsPaths = paths_for_apps(ProjectApps),
  247. ExtrasPaths = paths_for_extras(State, ProjectApps),
  248. DepsPaths = rebar_state:code_paths(State, all_deps),
  249. rebar_state:code_paths(State, all_deps, DepsPaths ++ ProjAppsPaths ++ ExtrasPaths).
  250. paths_for_apps(Apps) -> paths_for_apps(Apps, []).
  251. paths_for_apps([], Acc) -> Acc;
  252. paths_for_apps([App|Rest], Acc) ->
  253. {_SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_app_info:opts(App)),
  254. Paths = [filename:join([rebar_app_info:out_dir(App), Dir]) || Dir <- ["ebin"|ExtraDirs]],
  255. FilteredPaths = lists:filter(fun ec_file:is_dir/1, Paths),
  256. paths_for_apps(Rest, Acc ++ FilteredPaths).
  257. paths_for_extras(State, Apps) ->
  258. F = fun(App) -> rebar_app_info:dir(App) == rebar_state:dir(State) end,
  259. %% check that this app hasn't already been dealt with
  260. case lists:any(F, Apps) of
  261. false -> paths_for_extras(State);
  262. true -> []
  263. end.
  264. paths_for_extras(State) ->
  265. {_SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_state:opts(State)),
  266. Paths = [filename:join([rebar_dir:base_dir(State), "extras", Dir]) || Dir <- ExtraDirs],
  267. lists:filter(fun ec_file:is_dir/1, Paths).
  268. has_all_artifacts(AppInfo1) ->
  269. case rebar_app_info:has_all_artifacts(AppInfo1) of
  270. {false, File} ->
  271. throw(?PRV_ERROR({missing_artifact, File}));
  272. true ->
  273. rebar_app_utils:lint_app_info(AppInfo1),
  274. true
  275. end.
  276. copy_app_dirs(AppInfo, OldAppDir, AppDir) ->
  277. case rebar_utils:to_binary(filename:absname(OldAppDir)) =/=
  278. rebar_utils:to_binary(filename:absname(AppDir)) of
  279. true ->
  280. EbinDir = filename:join([OldAppDir, "ebin"]),
  281. %% copy all files from ebin if it exists
  282. case filelib:is_dir(EbinDir) of
  283. true ->
  284. OutEbin = filename:join([AppDir, "ebin"]),
  285. filelib:ensure_dir(filename:join([OutEbin, "dummy.beam"])),
  286. rebar_file_utils:cp_r(filelib:wildcard(filename:join([EbinDir, "*"])), OutEbin);
  287. false ->
  288. ok
  289. end,
  290. filelib:ensure_dir(filename:join([AppDir, "dummy"])),
  291. %% link or copy mibs if it exists
  292. case filelib:is_dir(filename:join([OldAppDir, "mibs"])) of
  293. true ->
  294. %% If mibs exist it means we must ensure priv exists.
  295. %% mibs files are compiled to priv/mibs/
  296. filelib:ensure_dir(filename:join([OldAppDir, "priv", "dummy"])),
  297. symlink_or_copy(OldAppDir, AppDir, "mibs");
  298. false ->
  299. ok
  300. end,
  301. {SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_app_info:opts(AppInfo)),
  302. %% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
  303. %% priv/ and include/ are symlinked unconditionally to allow hooks
  304. %% to write to them _after_ compilation has taken place when the
  305. %% initial directory did not, and still work
  306. [symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"]],
  307. [symlink_or_copy_existing(OldAppDir, AppDir, Dir) || Dir <- SrcDirs],
  308. %% copy all extra_src_dirs as they build into themselves and linking means they
  309. %% are shared across profiles
  310. [copy(OldAppDir, AppDir, Dir) || Dir <- ExtraDirs];
  311. false ->
  312. ok
  313. end.
  314. symlink_or_copy(OldAppDir, AppDir, Dir) ->
  315. Source = filename:join([OldAppDir, Dir]),
  316. Target = filename:join([AppDir, Dir]),
  317. rebar_file_utils:symlink_or_copy(Source, Target).
  318. symlink_or_copy_existing(OldAppDir, AppDir, Dir) ->
  319. Source = filename:join([OldAppDir, Dir]),
  320. Target = filename:join([AppDir, Dir]),
  321. case ec_file:is_dir(Source) of
  322. true -> rebar_file_utils:symlink_or_copy(Source, Target);
  323. false -> ok
  324. end.
  325. copy(OldAppDir, AppDir, Dir) ->
  326. Source = filename:join([OldAppDir, Dir]),
  327. Target = filename:join([AppDir, Dir]),
  328. case ec_file:is_dir(Source) of
  329. true -> copy(Source, Target);
  330. false -> ok
  331. end.
  332. %% TODO: use ec_file:copy/2 to do this, it preserves timestamps and
  333. %% may prevent recompilation of files in extra dirs
  334. copy(Source, Source) ->
  335. %% allow users to specify a directory in _build as a directory
  336. %% containing additional source/tests
  337. ok;
  338. copy(Source, Target) ->
  339. %% important to do this so no files are copied onto themselves
  340. %% which truncates them to zero length on some platforms
  341. ok = delete_if_symlink(Target),
  342. ok = filelib:ensure_dir(filename:join([Target, "dummy.beam"])),
  343. {ok, Files} = rebar_utils:list_dir(Source),
  344. case [filename:join([Source, F]) || F <- Files] of
  345. [] -> ok;
  346. Paths -> rebar_file_utils:cp_r(Paths, Target)
  347. end.
  348. delete_if_symlink(Path) ->
  349. case ec_file:is_symlink(Path) of
  350. true -> file:delete(Path);
  351. false -> ok
  352. end.
  353. resolve_src_dirs(Opts) ->
  354. SrcDirs = rebar_dir:src_dirs(Opts, ["src"]),
  355. ExtraDirs = rebar_dir:extra_src_dirs(Opts, []),
  356. normalize_src_dirs(SrcDirs, ExtraDirs).
  357. %% remove duplicates and make sure no directories that exist
  358. %% in src_dirs also exist in extra_src_dirs
  359. normalize_src_dirs(SrcDirs, ExtraDirs) ->
  360. S = lists:usort(SrcDirs),
  361. E = lists:subtract(lists:usort(ExtraDirs), S),
  362. ok = warn_on_problematic_directories(S ++ E),
  363. {S, E}.
  364. %% warn when directories called `eunit' and `ct' are added to compile dirs
  365. warn_on_problematic_directories(AllDirs) ->
  366. F = fun(Dir) ->
  367. case is_a_problem(Dir) of
  368. true -> ?WARN("Possible name clash with directory ~p.", [Dir]);
  369. false -> ok
  370. end
  371. end,
  372. lists:foreach(F, AllDirs).
  373. is_a_problem("eunit") -> true;
  374. is_a_problem("common_test") -> true;
  375. is_a_problem(_) -> false.