If you take a look at mix.exs
file you can notice the:
use Mix.Project
Now this file contains:
@doc false
defmacro __using__(_) do
quote do
@after_compile Mix.Project
end
end
# Invoked after each Mix.Project is compiled.
@doc false
def __after_compile__(env, _binary) do
push(env.module, env.file)
end
@after_compile
is a macro defined in elixir/kernel.ex even if it is in a strange form and it is invoked by __using__
from mix.exs
. Since you cannot invoke macros outside of modules you need to have a module in your mix.exs
file.
To illustrate this more clearly, let's try to delete the module in mix.exs
and run the project:
* (ArgumentError) cannot invoke @/1 outside module
(elixir) lib/kernel.ex:5230: Kernel.assert_module_scope/3
(elixir) expanding macro: Kernel.@/1
mix.exs:2: (file)
(mix) expanding macro: Mix.Project.__using__/1
mix.exs:2: (file)
(elixir) expanding macro: Kernel.use/1
mix.exs:2: (file)
So the answer to your question is that the hook @after_compile
cannot be called without a module since hooks by themselves are macros. The hook most probably is used to load the project automatically after all the files were compiled.
PS: push/3
function calls an interesting module function:
Mix.ProjectStack.push(atom, config, file)
If you look at the source of ProjectStack module you can observe that it is a state machine based on Agent. So basically all mix projects are pushed into the stack and they can be checked whether there are duplicates in names.