檢視原始碼 編譯與程式碼載入

程式碼如何編譯和載入並非語言本身的問題,而是與系統相關。本節描述 Erlang/OTP 中的編譯和程式碼載入,並參考相關的文件部分。

編譯

Erlang 程式必須編譯為目的碼。編譯器可以產生一個包含目的碼的新檔案。目前執行目的碼的抽象機器稱為 BEAM,因此目的碼檔案的副檔名為 .beam。編譯器也可以產生可以直接載入的二進位檔。

編譯器位於 Compiler 應用程式中的 compile 模組中。

compile:file(Module)
compile:file(Module, Options)

Erlang shell 可以理解 c(Module) 指令,它會同時編譯並載入 Module

還有一個 make 模組,它提供類似於 UNIX 系統 Make 函數的一組函數,請參閱 Tools 應用程式中的 make 模組。

也可以使用 ERTS 中的 erl 執行檔從作業系統提示符號存取編譯器。

% erl -compile Module1...ModuleN
% erl -make

erlc 程式提供從作業系統 shell 編譯模組的方式,請參閱 ERTS 中的 erlc 執行檔。它可以理解許多 flag,可用於定義巨集、為 include 檔案新增搜尋路徑等等。

% erlc <flags> File1.erl...FileN.erl

程式碼載入

目的碼必須載入到 Erlang 執行期系統中。這由程式碼伺服器處理,請參閱 Kernel 應用程式中的 code 模組。

程式碼伺服器根據程式碼載入策略載入程式碼,該策略可以是互動式(預設)或嵌入式。在互動模式中,程式碼會在程式碼路徑中搜尋,並在首次被引用時載入。在嵌入式模式中,程式碼會在啟動時根據啟動腳本載入。這在 系統原理 中有描述。

程式碼替換

Erlang 支援在執行中的系統中變更程式碼。程式碼替換在模組層級完成。

一個模組的程式碼在系統中可以存在兩種變體:currentold。當一個模組第一次載入系統時,該程式碼會變成 'current'。如果之後載入該模組的新執行個體,則前一個執行個體的程式碼會變成 'old',而新的執行個體會變成 'current'。

old 和 current 程式碼都有效,並且可以同時評估。完全限定的函數呼叫總是參考 current 程式碼。由於處理程序可能停留在 old 程式碼中,因此 old 程式碼仍然可以被評估。

如果載入模組的第三個執行個體,程式碼伺服器會移除 (清除) old 程式碼,並且任何停留在其中的處理程序都會終止。然後第三個執行個體會變成 'current',而先前 current 的程式碼會變成 'old'。

若要從 old 程式碼變更為 current 程式碼,處理程序必須進行完全限定的函數呼叫。

範例

-module(m).
-export([loop/0]).

loop() ->
    receive
        code_switch ->
            m:loop();
        Msg ->
            ...
            loop()
    end.

若要使處理程序變更程式碼,請將訊息 code_switch 傳送給它。然後處理程序會對 m:loop() 進行完全限定的呼叫,並變更為 current 程式碼。請注意,m:loop/0 必須被匯出。

若要使 fun 的程式碼替換生效,請使用語法 fun Module:FunctionName/Arity

模組載入時執行函數

-on_load() 指令會指定在模組載入時自動執行的函數。

其語法如下

-on_load(Name/0).

不需要匯出該函數。它會在新產生的處理程序中呼叫(該處理程序會在函數返回後立即終止)。

如果模組要成為模組新的 current 程式碼並可被呼叫,則函數必須返回 ok

返回任何其他值或產生例外狀況都會導致新程式碼被卸載。如果傳回值不是原子,則會將警告錯誤報告傳送到錯誤記錄器。

如果該模組已存在 current 程式碼,則該程式碼將保持 current,並且可以呼叫,直到 on_load 函數返回。如果 on_load 函數失敗,則 current 程式碼(如果有的話)將保持 current。如果模組沒有 current 程式碼,則任何在 on_load 函數完成之前對模組進行外部呼叫的處理程序都將被暫停,直到 on_load 函數完成。

變更

在 Erlang/OTP 19 之前,如果 on_load 函數失敗,任何先前的 current 程式碼都會變成 old,這實際上會使系統沒有模組的任何可用的且可存取的執行個體。

在嵌入式模式中,首先會載入所有模組。然後會呼叫所有 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 失敗,則會卸載模組,並將警告報告傳送到錯誤載入器。