Erlang 20

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支持更改正在运行的系统中的代码。代码替换在模块级完成。

模块的代码可以在系统中存在两种变体:currentold。当模块第一次加载到系统中时,代码变为“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失败,模块将被卸载并向错误加载器发送警告报告。