14.编译和代码加载 | 14. Compilation and Code Loading
14编译和代码加载
如何编译和加载代码不是语言问题,而是系统依赖的问题。本节描述Erlang/OTP中的编译和代码加载,并引用文档的相关部分。
14.1汇编
Erlang程序必须编译
成目标代码。编译
器可以生成一个包含目标代码的新文件。运行目标代码的当前抽象机被称为BEAM,因此目标文件获得后缀.beam
。编译
器也可以生成一个可以直接加载的二进制文件。
编译器位于模块中compile
(请参阅compile(3)
编译器中的手册页)。
compile:file(Module)
compile:file(Module, Options)
Erlang shell理解c(Module)
编译和加载的命令Module
。
还有一个模块make
,它提供了一组类似于UNIX类型Make功能的功能,请参见make(3)
工具中的手册页。
也可以从OS提示符访问编译器,请参阅erl(1)
ERTS中的手册页。
% erl -compile Module1...ModuleN
% erl -make
erlc
程序提供了一种更好的方式来从shell编译模块,请参阅erlc(1)
ERTS中的手册页。它理解许多可用于定义宏的标志,为包含文件添加搜索路径等等。
% erlc <flags> File1.erl...FileN.erl
14.2码加载
目标代码必须加载
到Erlang运行时系统中。这由代码服务器
处理,请参阅code(3)
Kernel中的手册页。
代码服务器根据代码加载策略加载代码,该代码加载策略可以是交互式
(默认)或嵌入式
。在交互模式下,代码在代码路径中
搜索并在首次引用时加载。在嵌入模式下,代码在启动时根据启动脚本
加载。这在描述中System Principles
。
14.3代码替换
Erlang支持更改正在运行的系统中的代码。代码替换在模块级完成。
模块的代码可以在系统中存在两种变体:current
和old
。当模块第一次加载到系统中时,代码变为“current
”。如果接下来加载模块的新实例,则前一个实例的代码变为“old
”,新实例变为“current
”。
旧的和当前的代码都是有效的,并且可以同时进行评估。完全限定的函数调用始终引用当前代码。旧代码仍然可以评估,因为旧代码中存在进程。
如果模块的第三个实例被加载,代码服务器将删除(清除)旧代码,并且其中的任何进程将被终止。然后第三个实例变成'current',并且之前的当前代码变成'old'。
要从旧代码更改为当前代码,进程必须进行完全限定的函数调用。
例子:
-module(m).
-export([loop/0]).
loop() ->
receive
code_switch ->
m:loop(
Msg ->
...
loop()
end.
要使流程更改代码,请将消息发送code_switch
给它。该过程然后进行完全合格的调用m:loop()
并更改当前代码。注意m:loop/0
必须导出。
要使代码更换起作用,请使用语法fun Module:FunctionName/Arity
。
14.4在加载模块时运行函数
-on_load()
指令命名一个函数,当模块被加载时它将自动运行。
其语法如下:
-on_load(Name/0).
不需要导出该函数。它在一个新产生的过程中被调用(只要函数返回就终止)。
ok
如果模块要成为模块的新当前代码并变为可调用,则该函数必须返回。
返回任何其他值或生成异常会导致新代码被卸载。如果返回值不是原子,则会向错误记录器发送警告错误报告。
如果该模块已经有当前代码,那么该代码将保持最新状态,并且可以在该on_load
函数返回之前调用该代码。如果该on_load
功能失败,则当前的代码(如果有的话)将保持最新。如果模块没有当前代码,那么在on_load
函数完成之前对模块进行外部调用的任何进程将被暂停,直到on_load
函数完成。
注
在OTP 19之前,如果该on_load
功能失败,任何先前的当前代码将变旧,实质上使系统离开系统而没有任何工作和模块的可达实例。OTP 19中已经消除了这个问题。
在嵌入式模式下,首先加载所有模块。然后on_load
调用所有函数。系统终止,除非所有的on_load
功能都返回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).
如果调用erlang:load_nif/2
失败,模块将被卸载并向错误加载器发送警告报告。