Can Elixir code detect whether it is executing at compile time? I would like to write something like the following macro:
defmacro foo() do
if is_compile_time? do
It’s presumably obvious how the code that the macro expands to can execute at runtime. It can execute at compile time in a scenario such as the following:
defmodule Bar do
def bar() do
foo() # invoke the macro
defmodule Amp do
@attr Bar.bar() # code that 'foo' macro expands to is executed at compile time
I have tried examining __ENV__, but unless I’m missing something, it offers no reliable diagnostic for compile time vs. runtime. I wonder if there is any other way. For anyone familiar with Common Lisp, I suppose I am looking for something that works a bit like eval-when.
By the way, I am asking largely out of curiosity. I’m aware that in general one should not need to perform such a check
compiling? = is_list(Process.get(:elixir_module_binaries)) But as @hauleth pointed out, difference between runtime and compile time is ephemeral. Compilation can happen in runtime, and anything can be called during compilation
That distinction doesn’t change anything he said though, you can still generate a module at runtime and compile it and for it what is happening will be “compile time”. You really should revise what you really want to achieve with this and consider other ways, this can very easily bite you in the rear in the most inopportune moment in the future.
Yes, I’m aware of that and clarified what I meant in the comment that you’re replying to: I’m interested to know if the code is being called during compilation. I assume hissssst’s expression would evaluate to true in the scenario you describe, which is exactly what I want.
To be precise, expression evaluates to true, only if the process is compiling the Elixir module. Some processes can be present during the compilation, but this expression would return false in them, since these processes are not compiling anything.
I use the following code in ex_cldr to detect if Elixir is compiling. The mechanism changed from Elixir 1.11, hence the conditional check:
def compiling? do
# TODO: When we depend on Elixir v1.11+ only, remove function_exported and elixir_compiler_pid
defp process_alive?(:can_await_module_compilation?) do
function_exported?(Code, :can_await_module_compilation?, 0) &&
apply(Code, :can_await_module_compilation?, )
defp process_alive?(name) do
case Process.get(name) do
nil -> false
pid when is_pid(pid) -> true