14 Compilation and Code Loading
How code is compiled and loaded is not a language issue, but is system-dependent. This section describes compilation and code loading in Erlang/OTP with references to relevant parts of the documentation.
Erlang programs must be compiled to object code. The compiler can generate a new file that contains the object code. The current abstract machine, which runs the object code, is called BEAM, therefore the object files get the suffix .beam. The compiler can also generate a binary which can be loaded directly.
The compiler is located in the module compile (see the compile(3) manual page in Compiler).
compile:file(Module) compile:file(Module, Options)
The Erlang shell understands the command c(Module) which both compiles and loads Module.
There is also a module make, which provides a set of functions similar to the UNIX type Make functions, see the make(3) manual page in Tools.
The compiler can also be accessed from the OS prompt, see the erl(1) manual page in ERTS.
% erl -compile Module1...ModuleN % erl -make
The erlc program provides an even better way to compile modules from the shell, see the erlc(1) manual page in ERTS. It understands a number of flags that can be used to define macros, add search paths for include files, and more.
% erlc <flags> File1.erl...FileN.erl
The object code must be loaded into the Erlang runtime system. This is handled by the code server, see the code(3) manual page in Kernel.
The code server loads code according to a code loading strategy, which is either interactive (default) or embedded. In interactive mode, code is searched for in a code path and loaded when first referenced. In embedded mode, code is loaded at start-up according to a boot script. This is described in System Principles .
Erlang supports change of code in a running system. Code replacement is done on module level.
The code of a module can exist in two variants in a system: current and old. When a module is loaded into the system for the first time, the code becomes 'current'. If then a new instance of the module is loaded, the code of the previous instance becomes 'old' and the new instance becomes 'current'.
Both old and current code is valid, and can be evaluated concurrently. Fully qualified function calls always refer to current code. Old code can still be evaluated because of processes lingering in the old code.
If a third instance of the module is loaded, the code server removes (purges) the old code and any processes lingering in it is terminated. Then the third instance becomes 'current' and the previously current code becomes 'old'.
To change from old code to current code, a process must make a fully qualified function call.
-module(m). -export([loop/0]). loop() -> receive code_switch -> m:loop(); Msg -> ... loop() end.
To make the process change code, send the message code_switch to it. The process then makes a fully qualified call to m:loop() and changes to current code. Notice that m:loop/0 must be exported.
For code replacement of funs to work, use the syntax fun Module:FunctionName/Arity.
The on_load feature is to be considered experimental as there are a number of known weak points in current semantics, which therefore might change in future Erlang/OTP releases:
Doing external call in on_load to the module itself leads to deadlock.
At module upgrade, other processes calling the module get suspended waiting for on_load to finish. This can be very bad for applications with demands on realtime characteristics.
At module upgrade, no rollback is done if the on_load function fails. The system is left in a bad limbo state without any working and reachable instance of the module.
The problems with module upgrade described above can be fixed in future Erlang/OTP releases by changing the behaviour to not make the module reachable until after the on_load function has successfully returned.
The -on_load() directive names a function that is to be run automatically when a module is loaded.
Its syntax is as follows:
It is not necessary to export the function. It is called in a freshly spawned process (which terminates as soon as the function returns). The function must return ok if the module is to remain loaded and become callable, or any other value if the module is to be unloaded. Generating an exception also causes the module to be unloaded. If the return value is not an atom, a warning error report is sent to the error logger.
A process that calls any function in a module whose on_load function has not yet returned, is suspended until the on_load function has returned.
In embedded mode, first all modules are loaded. Then all on_load functions are called. The system is terminated unless all of the on_load functions return ok.
-module(m). -on_load(load_my_nifs/0). load_my_nifs() -> NifPath = ..., %Set up the path to the NIF library. Info = ..., %Initialize the Info term erlang:load_nif(NifPath, Info).
If the call to erlang:load_nif/2 fails, the module is unloaded and a warning report is sent to the error loader.