檢視原始碼 code (kernel v10.2)
Erlang 程式碼伺服器程序的介面。
此模組包含 Erlang *程式碼伺服器* 的介面,該伺服器負責將編譯後的程式碼載入到正在執行的 Erlang 執行時期系統中。
執行時期系統可以以*互動式*或*嵌入式*模式啟動。具體使用哪種模式取決於命令行標誌 -mode
% erl -mode embedded
模式如下:
在*互動式*模式(預設)中,只有執行時期系統需要的模組會在系統啟動期間載入。其他程式碼會在首次被引用時動態載入。當呼叫特定模組中的函式,而該模組尚未載入時,程式碼伺服器會搜尋並嘗試載入該模組。
在*嵌入式*模式中,模組不會自動載入。嘗試使用尚未載入的模組將會導致錯誤。當啟動腳本載入所有模組時(如 OTP 發行版中通常的做法),建議使用此模式。(程式碼仍然可以稍後透過明確指示程式碼伺服器來載入)。
為了防止意外重新載入影響 Erlang 執行時期系統的模組,目錄 kernel
、stdlib
和 compiler
被視為*黏性*。這表示如果使用者嘗試重新載入駐留在其中任何一個目錄中的模組,系統會發出警告並拒絕該請求。可以使用命令行標誌 -nostick
停用此功能。
程式碼路徑
在互動模式下,程式碼伺服器會維護一個*程式碼路徑*,其中包含一個目錄列表,當嘗試載入模組時,它會依序搜尋這些目錄。
最初,程式碼路徑由當前工作目錄和庫目錄 $OTPROOT/lib
下的所有 Erlang 目標程式碼目錄組成,其中 $OTPROOT
是 Erlang/OTP 的安裝目錄,即 code:root_dir()
。目錄可以命名為 Name[-Vsn]
,預設情況下,程式碼伺服器會選擇具有相同 Name
的目錄中版本號最高的目錄。後綴 -Vsn
是可選的。如果 Name[-Vsn]
下存在 ebin
目錄,則此目錄會新增至程式碼路徑。
可以使用環境變數 ERL_LIBS
(在作業系統中定義)來定義更多庫目錄,其處理方式與上述標準 OTP 庫目錄相同,但會忽略沒有 ebin
目錄的目錄。
在其他目錄中找到的所有應用程式目錄都會顯示在標準 OTP 應用程式之前,但 Kernel 和 STDLIB 應用程式除外,它們會放置在任何其他應用程式之前。換句話說,在任何其他庫目錄中找到的模組會覆蓋 OTP 中具有相同名稱的模組,但 Kernel 和 STDLIB 中的模組除外。
環境變數 ERL_LIBS
(如果已定義)應包含一個以冒號分隔(對於類 Unix 系統)或以分號分隔(對於 Windows)的額外庫列表。
範例
在類 Unix 系統上,可以將 ERL_LIBS
設定為以下內容:
/usr/local/jungerl:/home/some_user/my_erlang_lib
由 $OTPROOT
、ERL_LIBS
和啟動腳本指定的程式碼路徑預設會快取其清單("."
除外)。程式碼伺服器會查詢一次其目錄中的內容,並避免未來進行檔案系統遍歷。因此,在 Erlang VM 啟動後新增至此類目錄的模組將不會被選取。可以透過設定 -cache_boot_paths false
或呼叫 code:set_path(code:get_path())
來停用此行為。
變更
對程式碼路徑中的目錄進行快取的支援是在 Erlang/OTP 26 中新增的。
命令行選項 -pa
和 -pz
給定的目錄預設不會快取。許多操作程式碼路徑的函式都接受 cache
atom 作為可選參數,以選擇性啟用快取。
從封存檔案載入程式碼
變更
對封存檔案的現有實驗性支援將在未來版本中變更。自 Erlang/OTP 27 起,函式
code:lib_dir/2
、-code_path_choice
標誌,以及使用erl_prim_loader
從封存檔案讀取檔案已被棄用。使用封存檔案的
escript
腳本應使用escript:extract/2
從其封存讀取資料檔案,而不是使用code:lib_dir/2
和erl_prim_loader
。
Erlang 封存檔案是副檔名為 .ez
的 ZIP
檔案。Erlang 封存檔案也可以封閉在 escript
檔案中,其副檔名是任意的。
Erlang 封存檔案可以包含整個 Erlang 應用程式或應用程式的一部分。封存檔案中的結構與應用程式的目錄結構相同。例如,如果您建立 mnesia-4.4.7
的封存檔,則該封存檔必須命名為 mnesia-4.4.7.ez
,並且必須包含一個名為 mnesia-4.4.7
的頂層目錄。如果省略名稱的版本部分,則也必須在封存檔中省略。也就是說,mnesia.ez
封存檔必須包含一個 mnesia
頂層目錄。
應用程式的封存檔案可以像這樣建立:
zip:create("mnesia-4.4.7.ez",
["mnesia-4.4.7"],
[{cwd, code:lib_dir()},
{compress, all},
{uncompress,[".beam",".app"]}]).
封存檔中的任何檔案都可以壓縮,但是為了加快存取頻繁讀取的檔案,最好將 beam
和 app
檔案以未壓縮的形式儲存在封存檔中。
通常,應用程式的頂層目錄位於庫目錄 $OTPROOT/lib
中,或位於環境變數 ERL_LIBS
引用的目錄中。在啟動時,當計算初始程式碼路徑時,程式碼伺服器也會在這些目錄中尋找封存檔案,並可能會將封存檔中的 ebin
目錄新增到程式碼路徑。然後,程式碼路徑會包含看起來像 $OTPROOT/lib/mnesia.ez/mnesia/ebin
或 $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin
的目錄的路徑。
程式碼伺服器使用 ERTS 中的模組 erl_prim_loader
(可能透過 erl_boot_server
)來從封存檔讀取程式碼檔案。但是,其他應用程式也可以使用 erl_prim_loader
中的函式來從封存檔讀取檔案。例如,呼叫 erl_prim_loader:list_dir( "/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)"
將會列出封存檔內目錄的內容。請參閱 erl_prim_loader
。
應用程式封存檔和常規應用程式目錄可以共存。當需要將應用程式的一部分作為常規檔案時,這很有用。一個典型的案例是 priv
目錄,它必須作為常規目錄駐留才能動態連結驅動程式並啟動埠程式。對於其他不需要此功能的應用程式,目錄 priv
可以駐留在封存檔中,並且可以透過 erl_prim_loader
讀取目錄 priv
下的檔案。
當目錄新增至程式碼路徑時,以及當整個程式碼路徑被(重新)設定時,程式碼伺服器會決定應用程式中的哪些子目錄要從封存檔讀取,哪些要作為常規檔案讀取。如果稍後新增或移除目錄,則如果未更新程式碼路徑(可能與之前的路徑相同,以觸發目錄解析更新),則檔案存取可能會失敗。
對於應用程式封存檔中第二層的每個目錄(ebin
、priv
、src
等),程式碼伺服器首先選擇常規目錄(如果存在),其次從封存檔選擇。函式 code:lib_dir/2
會傳回子目錄的路徑。例如,code:lib_dir(megaco, ebin)
可以傳回 /otp/root/lib/megaco-3.9.1.1.ez/megaco-3.9.1.1/ebin
,而 code:lib_dir(megaco, priv)
可以傳回 /otp/root/lib/megaco-3.9.1.1/priv
。
當 escript
檔案包含封存檔時,對於 escript
的名稱沒有限制,對於可以儲存在嵌入式封存檔中的應用程式數量也沒有限制。單個 Beam 檔案也可以駐留在封存檔的頂層。在啟動時,嵌入式封存檔中的頂層目錄和嵌入式封存檔中的所有(第二層)ebin
目錄都會新增到程式碼路徑。請參閱 escript
。
escript
腳本從封存檔讀取資料檔案的未來防護方式是使用 escript:extract/2
函式。
當程式碼路徑中的目錄選擇為 strict
時(自 Erlang/OTP 27 起的預設值),最終在程式碼路徑中的目錄正是所聲明的目錄。這表示,例如,如果將目錄 $OTPROOT/lib/mnesia-4.4.7/ebin
明確新增到程式碼路徑中,則程式碼伺服器不會從 $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin
載入檔案。
此行為可以透過命令行標誌 -code_path_choice Choice
控制。如果將該標誌設定為 relaxed
,則程式碼伺服器會改為根據實際檔案結構選擇適當的目錄。如果存在常規應用程式 ebin
目錄,則會選擇它。否則,如果存在,則會選擇封存檔中的目錄 ebin
。如果它們都不存在,則會選擇原始目錄。
命令行標誌 -code_path_choice Choice
也會影響模組 init
解譯 boot script
的方式。boot script
中明確程式碼路徑的解譯可以是 strict
或 relaxed
。當在不編輯 boot script
的情況下詳細說明從封存檔載入程式碼時,將該標誌設定為 relaxed
特別有用。預設值在 OTP 27 中已變更為 strict
,並且該選項計劃在 OTP 28 中移除。請參閱 Erts 應用程式中的模組 init
。
目前程式碼和舊程式碼
系統中一個模組的程式碼可以存在兩種變體:*目前程式碼*和*舊程式碼*。當模組第一次載入到系統時,模組程式碼會變成*目前*,並且全域*匯出表*會使用對從模組匯出的所有函式的參考來更新。
當載入模組的新實例時,先前實例的程式碼會變成舊的,並且所有參照先前實例的匯出條目都會被移除。之後,新的實例會像第一次一樣被載入,並成為目前的實例。
模組的舊程式碼和目前程式碼都是有效的,甚至可以同時執行。不同之處在於舊程式碼中的匯出函數是不可用的。因此,無法對舊程式碼中的匯出函數進行全域呼叫,但由於其中仍有程序存在,舊程式碼仍然可以執行。
如果載入了模組的第三個實例,程式碼伺服器會移除(清除)舊程式碼,並且其中任何存在的程序都會被終止。然後,第三個實例會成為目前的實例,而先前目前的程式碼則會變成舊的。
關於舊程式碼和目前程式碼的更多資訊,以及如何使程序從舊程式碼切換到目前程式碼,請參閱Erlang 參考手冊中的「編譯和程式碼載入」章節。
原生涵蓋率支援
在使用 JIT 的執行時系統中,原生涵蓋率是一種輕量級的方式,可以找出哪些函數或程式碼行已被執行,或者每個函數或程式碼行已執行多少次。
變更
對原生涵蓋率的支援是在 Erlang/OTP 27 中加入的。
原生涵蓋率的工作方式是在載入時對程式碼進行檢測。當一個模組已針對原生涵蓋率收集進行檢測時,除非重新載入該模組,否則之後無法停用涵蓋率收集。但是,保持涵蓋率收集運行的開銷通常可以忽略不計,尤其對於僅追蹤哪些函數已執行的涵蓋率模式 function
。
如果執行時系統支援,Tools 應用程式中的 cover
工具會自動使用原生涵蓋率支援。
只有在 cover
不足夠時,才需要使用接下來描述的功能,例如:
如果想要收集執行時系統啟動時運行的程式碼(模組
init
等)的涵蓋率資訊。cover
只能在 Erlang 系統啟動後使用,並且它會重新載入每個要分析的模組。如果需要以對測試系統的絕對最小干擾來收集涵蓋率資訊。
cover
總是會計算每行程式碼被執行的次數(涵蓋率模式line_counters
),但是透過使用原生涵蓋率,可以使用較低開銷的涵蓋率模式,例如function
,它的開銷幾乎可以忽略不計。
使用原生涵蓋率的簡短摘要
如果要使用 line
或 line_counters
涵蓋率模式,則必須使用選項 line_coverage
編譯要測試的程式碼。
使用 set_coverage_mode(Mode) 為之後載入的所有程式碼設定涵蓋率模式,或者使用 erl
的選項 +JPcover 進行設定。
可選地,透過呼叫 reset_coverage(Module) 來重設要測試的所有模組的涵蓋率資訊。
執行要收集其涵蓋率資訊的程式碼。
透過呼叫 get_coverage(Level, Module) 讀取所有感興趣模組的計數器,其中 Level
是 function
或 line
。
其他原生涵蓋率 BIF
以下 BIF 有時很有用,例如,如果執行時系統不支援原生涵蓋率,可以優雅地失敗
coverage_support() - 檢查執行時系統是否支援原生涵蓋率
get_coverage_mode() - 取得目前的涵蓋率模式
get_coverage_mode(Module) - 取得模組
Module
的涵蓋率模式
引數型別和無效引數
模組和應用程式名稱是原子,而檔案和目錄名稱是字串。出於向後相容性的原因,某些函數接受字串和原子,但未來版本可能只允許已記載的引數。
如果將不正確的型別(例如,預期為原子卻傳入整數或元組)傳遞給此模組中的函數,通常會導致例外狀況。如果引數型別正確,但存在其他錯誤(例如,為 set_path/1
指定了不存在的目錄),則會傳回錯誤元組。
程式碼載入函數的錯誤原因
如果載入操作失敗,則載入程式碼的函數(例如 load_file/1
)將傳回 {error,Reason}
。以下是常見原因的描述。
badfile
- 物件程式碼的格式不正確,或物件程式碼中的模組名稱不是預期的模組名稱。nofile
- 未找到具有物件程式碼的檔案。not_purged
- 因為已存在程式碼的舊版本,所以無法載入物件程式碼。on_load_failure
- 模組有一個 -on_load 函數,在呼叫時失敗。sticky_directory
- 物件程式碼位於黏性目錄中。
摘要
型別
一個不透明的術語,保存預備好的程式碼。
函數
將 Dir
加入到程式碼路徑的開頭。
遍歷 Dirs
並將每個 Dir
加入到程式碼路徑的開頭。
將 Dirs
中的目錄加入到程式碼路徑的結尾。
將 Dir
作為程式碼路徑中的最後一個目錄加入。
傳回所有可用模組的元組清單 {Module, Filename, Loaded}
。
傳回所有已載入模組的元組清單 {Module, Loaded}
。
嘗試以原子方式載入清單 Modules
中的所有模組。
在程式碼路徑中的所有目錄中搜尋具有相同名稱的模組名稱,並將報告寫入 stdout
。
清除程式碼路徑快取。
傳回編譯器程式庫目錄。
如果系統支援涵蓋率,則傳回 true
,否則傳回 false
。
從程式碼路徑中刪除目錄。
從程式碼路徑中刪除多個目錄。
移除 Module
的目前程式碼,也就是說,Module
的目前程式碼會變成舊的。
嘗試以與 load_file/1
相同的方式載入模組,除非模組已經載入。
嘗試以與 load_file/1
相同的方式載入清單 Modules
中尚未載入的任何模組。
嘗試載入先前由 prepare_loading/1
準備的所有模組的程式碼。
傳回模組 Module
的 function
或 line
涵蓋率資料。
傳回由 erl
的選項 +JPcover 或 set_coverage_mode/1
設定的涵蓋率模式。
取得指定模組的涵蓋率模式。
如果可用,則傳回 Module
的 EEP 48 風格文件。
傳回描述程式碼伺服器模式的原子:interactive
或 embedded
。
如果在程式碼路徑中找到,則傳回模組 Module
的物件程式碼。
傳回程式碼路徑。
檢查是否已載入 Module
。
如果 Module
是從黏性目錄載入的模組名稱(換句話說:嘗試重新載入該模組將會失敗),則傳回 true
;如果 Module
不是已載入的模組或不是黏性的,則傳回 false
。
傳回程式庫目錄 $OTPROOT/lib
,其中 $OTPROOT
是 Erlang/OTP 的根目錄。
傳回應用程式 Name
的程式庫目錄(頂層目錄)路徑,該應用程式位於 $OTPROOT/lib
下或以環境變數 ERL_LIBS
參照的目錄中。
傳回應用程式頂層目錄下的子目錄路徑。
等同於 load_file(Module)
,不同之處在於 Filename
是絕對或相對檔名。
從二進位資料載入物件程式碼。
嘗試使用程式碼路徑載入 Erlang 模組 Module
。
傳回目前已載入的所有模組的清單,其中 module_status/1
傳回 modified
。
詳細資訊請參閱 module_status/1
和 all_loaded/0
。
傳回 Module
相對於磁碟上物件檔案的狀態。
返回對應於所使用 Erlang 機器的目標碼檔案副檔名。
準備載入列表 Modules
中的模組。
返回應用程式中 priv
目錄的路徑。
清除 Module
的程式碼,也就是移除標記為舊的程式碼。
將程式碼路徑中名為 .../Name[-Vsn][/ebin]
的舊目錄出現位置,取代為 Dir
。
重設模組 Module
的覆蓋率資訊。
返回 Erlang/OTP 的根目錄,也就是其安裝所在的目錄。
設定後續載入模組的覆蓋率模式,類似於 erl
的選項 +JPcover。
將程式碼路徑設定為目錄列表 Path
。
清除 Module
的程式碼,也就是移除標記為舊的程式碼,但僅限於其中沒有持續執行的程序。
將 Dir
標記為黏性的。
取消標記為黏性的目錄。
在程式碼路徑中搜尋 Filename
,這是一個任意類型的檔案。
如果模組尚未載入,此函式會在程式碼路徑中搜尋第一個包含 Module
目標碼的檔案,並返回絕對檔案名稱。
類型
-type add_path_ret() :: true | {error, bad_directory}.
-type cache() :: cache | nocache.
-type coverage_mode() :: none | function | function_counters | line_coverage | line_counters.
-type load_error_rsn() :: badfile | nofile | not_purged | on_load_failure | sticky_directory.
-type load_ret() :: {error, What :: load_error_rsn()} | {module, Module :: module()}.
-type loaded_filename() :: (Filename :: file:filename()) | loaded_ret_atoms().
-type loaded_ret_atoms() :: cover_compiled | preloaded.
-type module_status() :: not_loaded | loaded | modified | removed.
-opaque prepared_code()
一個不透明的術語,保存預備好的程式碼。
-type replace_path_ret() :: true | {error, bad_directory | bad_name | {badarg, _}}.
-type set_path_ret() :: true | {error, bad_directory}.
函式
-spec add_path(Dir) -> add_path_ret() when Dir :: file:filename().
-spec add_path(Dir, cache()) -> add_path_ret() when Dir :: file:filename().
-spec add_patha(Dir) -> add_path_ret() when Dir :: file:filename().
-spec add_patha(Dir, cache()) -> add_path_ret() when Dir :: file:filename().
將 Dir
加入到程式碼路徑的開頭。
如果 Dir
存在,它會從程式碼路徑中的舊位置移除。
引數 Cache
控制是否應在第一次遍歷時快取目錄的內容。如果 Cache
是 cache
,目錄內容將被快取;如果 Cache
是 nocache
,則不會被快取。
如果成功,則返回 true
,如果 Dir
不是目錄名稱,則返回 {error, bad_directory}
。
-spec add_paths(Dirs) -> ok when Dirs :: [Dir :: file:filename()].
-spec add_paths(Dirs, cache()) -> ok when Dirs :: [Dir :: file:filename()].
-spec add_pathsa(Dirs) -> ok when Dirs :: [Dir :: file:filename()].
-spec add_pathsa(Dirs, cache()) -> ok when Dirs :: [Dir :: file:filename()].
遍歷 Dirs
並將每個 Dir
加入到程式碼路徑的開頭。
這表示 Dirs
的順序會在產生的程式碼路徑中反轉。例如,如果 Dirs
是 [Dir1,Dir2]
,產生的路徑將會是 [Dir2,Dir1|OldCodePath]
。
如果程式碼路徑中已存在 Dir
,它會從舊位置移除。
引數 Cache
控制是否應在第一次遍歷時快取目錄的內容。如果 Cache
是 cache
,目錄內容將被快取;如果 Cache
是 nocache
,則不會被快取。
無論每個單獨的 Dir
的有效性為何,皆一律返回 ok
。
-spec add_pathsz(Dirs) -> ok when Dirs :: [Dir :: file:filename()].
-spec add_pathsz(Dirs, cache()) -> ok when Dirs :: [Dir :: file:filename()].
將 Dirs
中的目錄加入到程式碼路徑的結尾。
路徑中已存在的目錄將不會被新增。
引數 Cache
控制是否應在第一次遍歷時快取目錄的內容。如果 Cache
是 cache
,目錄內容將被快取;如果 Cache
是 nocache
,則不會被快取。
無論每個單獨的 Dir
的有效性為何,皆一律返回 ok
。
-spec add_pathz(Dir) -> add_path_ret() when Dir :: file:filename().
-spec add_pathz(Dir, cache()) -> add_path_ret() when Dir :: file:filename().
將 Dir
作為程式碼路徑中的最後一個目錄加入。
如果路徑中已存在 Dir
,則不會新增。
引數 Cache
控制是否應在第一次遍歷時快取目錄的內容。如果 Cache
是 cache
,目錄內容將被快取;如果 Cache
是 nocache
,則不會被快取。
如果成功,則返回 true
,如果 Dir
不是目錄名稱,則返回 {error, bad_directory}
。
-spec all_available() -> [{Module, Filename, Loaded}] when Module :: string(), Filename :: loaded_filename(), Loaded :: boolean().
傳回所有可用模組的元組清單 {Module, Filename, Loaded}
。
如果模組已載入或在呼叫時會被載入,則視為可用。Filename
通常是絕對檔案名稱,如 is_loaded/1
所述。
-spec all_loaded() -> [{Module, Loaded}] when Module :: module(), Loaded :: loaded_filename().
傳回所有已載入模組的元組清單 {Module, Loaded}
。
Loaded
通常是絕對檔案名稱,如 is_loaded/1
所述。
-spec atomic_load(Modules) -> ok | {error, [{Module, What}]} when Modules :: [Module | {Module, Filename, Binary}], Module :: module(), Filename :: file:filename(), Binary :: binary(), What :: badfile | nofile | on_load_not_allowed | duplicated | not_purged | sticky_directory | pending_on_load.
嘗試以原子方式載入清單 Modules
中的所有模組。
這表示如果任何模組發生問題,所有模組會同時載入,或都不載入。
載入可能會因為下列原因之一而失敗
badfile
- 物件程式碼的格式不正確,或物件程式碼中的模組名稱不是預期的模組名稱。nofile
- 沒有目標碼的檔案存在。on_load_not_allowed
- 模組包含 -on_load 函式。duplicated
-Modules
中多次包含模組。not_purged
- 因為程式碼的舊版本已存在,所以無法載入目標碼。sticky_directory
- 物件程式碼位於黏性目錄中。pending_on_load
- 先前載入的模組包含從未完成的-on_load
函式。
如果變更程式碼時最小化應用程式不活動的時間很重要,請使用 prepare_loading/1
和 finish_loading/1
,而不是 atomic_load/1
。以下是一個範例
{ok,Prepared} = code:prepare_loading(Modules),
%% Put the application into an inactive state or do any
%% other preparation needed before changing the code.
ok = code:finish_loading(Prepared),
%% Resume the application.
-spec clash() -> ok.
在程式碼路徑中的所有目錄中搜尋具有相同名稱的模組名稱,並將報告寫入 stdout
。
-spec clear_cache() -> ok.
清除程式碼路徑快取。
如果目錄被快取,其快取會清除一次,然後在未來的遍歷中重新計算並再次快取。
若要清除單一路徑的快取,請將其重新新增至程式碼路徑(使用 add_path/2
)或取代它(使用 replace_path/3
)。若要停用所有快取,請使用 code:set_path(code:get_path())
重設程式碼路徑。
一律返回 ok
。
-spec compiler_dir() -> file:filename().
傳回編譯器程式庫目錄。
-spec coverage_support() -> Supported when Supported :: boolean().
如果系統支援涵蓋率,則傳回 true
,否則傳回 false
。
另請參閱: 原生覆蓋率支援
-spec del_path(NameOrDir) -> boolean() | {error, What} when NameOrDir :: Name | Dir, Name :: atom(), Dir :: file:filename(), What :: bad_name.
從程式碼路徑中刪除目錄。
引數可以是原子 Name
,在這種情況下,名稱為 .../Name[-Vsn][/ebin]
的目錄會從程式碼路徑中刪除。此外,完整的目錄名稱 Dir
可以指定為引數。
返回
true
- 如果成功false
- 如果找不到目錄{error, bad_name}
- 如果引數無效
-spec del_paths(NamesOrDirs) -> ok when NamesOrDirs :: [Name | Dir], Name :: atom(), Dir :: file:filename().
從程式碼路徑中刪除多個目錄。
引數是原子或完整目錄名稱的列表。如果 Name
是原子,則名稱為 .../Name[-Vsn][/ebin]
的目錄會從程式碼路徑中刪除。
無論每個單獨的 NamesOrDirs
的有效性為何,皆一律返回 ok
。
移除 Module
的目前程式碼,也就是說,Module
的目前程式碼會變成舊的。
這表示程序可以繼續執行模組中的程式碼,但無法對其進行外部函式呼叫。
如果成功,則返回 true
,如果 Module
有舊程式碼必須先清除,或者如果 Module
不是(已載入的)模組,則返回 false
。
-spec ensure_loaded(Module) -> {module, Module} | {error, What} when Module :: module(), What :: embedded | badfile | nofile | on_load_failure.
嘗試以與 load_file/1
相同的方式載入模組,除非模組已經載入。
如果同時呼叫此函式,則會確保在給定時間內只有一個程序嘗試載入該模組。
在嵌入模式下,它不會載入尚未載入的模組,而是返回 {error, embedded}
。有關其他可能的錯誤原因描述,請參閱程式碼載入函式的錯誤原因。
-spec ensure_modules_loaded([Module]) -> ok | {error, [{Module, What}]} when Module :: module(), What :: badfile | nofile | on_load_failure.
嘗試以與 load_file/1
相同的方式載入清單 Modules
中尚未載入的任何模組。
與 ensure_loaded/1
不同,即使在 embedded
模式下,也會載入模組。
如果成功則返回 ok
,如果載入某些模組失敗,則返回 {error,[{Module,Reason}]}
。有關其他可能的錯誤原因描述,請參閱程式碼載入函式的錯誤原因。
-spec finish_loading(Prepared) -> ok | {error, [{Module, What}]} when Prepared :: prepared_code(), Module :: module(), What :: not_purged | sticky_directory | pending_on_load.
嘗試載入先前由 prepare_loading/1
準備的所有模組的程式碼。
載入操作是原子性的,這表示要么所有模組同時載入,要么所有模組都不載入。
此函式可能會因以下錯誤原因之一而失敗
not_purged
- 因為程式碼的舊版本已存在,所以無法載入目標碼。sticky_directory
- 物件程式碼位於黏性目錄中。pending_on_load
- 先前載入的模組包含從未完成的-on_load
函式。
-spec get_coverage(Level, module()) -> Result when Level :: function | line | cover_id_line, Result :: [{Entity, CoverageInfo}], Entity :: {Function, Arity} | Line | CoverId, CoverageInfo :: Covered | Counter, Function :: atom(), Arity :: arity(), Line :: non_neg_integer(), CoverId :: pos_integer(), Covered :: boolean(), Counter :: non_neg_integer().
傳回模組 Module
的 function
或 line
涵蓋率資料。
如果 Level 為 function
,則根據給定模組的覆蓋模式返回該模組的函式覆蓋率。
function
- 對於模組 Module 中的每個函式,返回一個布林值,指示該函式是否至少執行過一次。function_counters
- 對於模組 Module 中的每個函式,返回一個整數,表示該行已執行的次數。line
- 對於模組 Module 中的每個函式,返回一個布林值,指示該函式是否至少執行過一次。line_counters
- 對於模組 Module 中的每個函式,返回一個布林值,指示該函式是否至少執行過一次(請注意,在此模式下,無法擷取每個函式已執行的次數)。
如果 Level 為 line
,則根據給定模組的覆蓋模式返回該模組的程式碼行覆蓋率。
line
- 對於模組中的每個可執行行,返回一個布林值,指示該行是否至少執行過一次。line_counters
- 對於模組中的每個可執行行,返回一個整數,表示該行已執行的次數。
Level cover_id_line
由 cover
工具使用。
失敗情況
badarg
- 如果Level
不是function
或line
。badarg
- 如果Module
不是原子。badarg
- 如果Module
沒有指向已載入的模組。badarg
- 如果Module
不是以none
以外的其他覆蓋模式載入的。badarg
- 如果 Level 為line
且Module
未以啟用line
或line_counters
的模式載入。badarg
- 如果執行階段系統不支援覆蓋率。
另請參閱: 原生覆蓋率支援
-spec get_coverage_mode() -> Mode when Mode :: coverage_mode().
傳回由 erl
的選項 +JPcover 或 set_coverage_mode/1
設定的涵蓋率模式。
失敗
badarg
- 如果執行階段系統不支援覆蓋率。
另請參閱: 原生覆蓋率支援
-spec get_coverage_mode(Module) -> Mode when Module :: module(), Mode :: coverage_mode().
取得指定模組的涵蓋率模式。
失敗情況
badarg
- 如果Module
不是原子。badarg
- 如果Module
沒有指向已載入的模組。badarg
- 如果執行階段系統不支援覆蓋率。
另請參閱: 原生覆蓋率支援
-spec get_doc(Mod) -> {ok, Res} | {error, Reason} when Mod :: module(), Res :: #docs_v1{anno :: term(), beam_language :: term(), format :: term(), module_doc :: term(), metadata :: term(), docs :: term()}, Reason :: non_existing | missing | file:posix().
如果可用,則傳回 Module
的 EEP 48 風格文件。
如果在程式碼路徑中找不到 Module
,此函式將返回 {error,non_existing}
。
如果找不到文件,此函式會嘗試從模組中的除錯資訊產生文件。如果沒有除錯資訊,此函式將返回 {error,missing}
。
有關文件區塊的更多資訊,請參閱 Kernel 使用者指南中的文件儲存和格式。
-spec get_mode() -> embedded | interactive.
傳回描述程式碼伺服器模式的原子:interactive
或 embedded
。
當外部實體(例如 IDE)為正在執行的節點提供額外程式碼時,此資訊非常有用。如果程式碼伺服器處於互動模式,則只需將路徑新增至程式碼。如果程式碼伺服器處於嵌入模式,則必須使用 load_binary/3
載入程式碼。
-spec get_object_code(Module) -> {Module, Binary, Filename} | error when Module :: module(), Binary :: binary(), Filename :: file:filename().
如果在程式碼路徑中找到,則傳回模組 Module
的物件程式碼。
如果成功,則返回 {Module, Binary, Filename}
,否則返回 error
。Binary
是一個二進位資料物件,其中包含模組的物件碼。如果要將程式碼載入分散式系統中的遠端節點,這非常有用。例如,在節點 Node
上載入模組 Module
的方式如下
...
{_Module, Binary, Filename} = code:get_object_code(Module),
erpc:call(Node, code, load_binary, [Module, Filename, Binary]),
...
-spec get_path() -> Path when Path :: [Dir :: file:filename()].
傳回程式碼路徑。
-spec is_loaded(Module) -> {file, Loaded} | false when Module :: module(), Loaded :: loaded_filename().
檢查是否已載入 Module
。
如果是,則返回 {file, Loaded}
,否則返回 false
。
通常,Loaded
是從中取得程式碼的絕對檔案名稱 Filename
。如果模組是預先載入的(請參閱 script(4)
),則 Loaded =:= preloaded
。如果模組是 Cover 編譯的(請參閱 cover
),則 Loaded =:= cover_compiled
。
如果 Module
是從黏性目錄載入的模組名稱(換句話說:嘗試重新載入該模組將會失敗),則傳回 true
;如果 Module
不是已載入的模組或不是黏性的,則傳回 false
。
-spec lib_dir() -> file:filename().
傳回程式庫目錄 $OTPROOT/lib
,其中 $OTPROOT
是 Erlang/OTP 的根目錄。
範例
1> code:lib_dir().
"/usr/local/otp/lib"
-spec lib_dir(Name) -> file:filename() | {error, bad_name} when Name :: atom().
傳回應用程式 Name
的程式庫目錄(頂層目錄)路徑,該應用程式位於 $OTPROOT/lib
下或以環境變數 ERL_LIBS
參照的目錄中。
如果程式碼路徑中存在一個名為 Name
或 Name-Vsn
的常規目錄,且其中包含 ebin
子目錄,則返回此目錄的路徑(而不是 ebin
目錄)。
如果該目錄指向封存檔中的目錄,則會在返回路徑之前移除封存檔名稱。例如,如果路徑中存在目錄 /usr/local/otp/lib/mnesia-4.2.2.ez/mnesia-4.2.2/ebin
,則返回 /usr/local/otp/lib/mnesia-4.2.2/ebin
。這表示無論應用程式是否位於封存檔中,應用程式的程式庫目錄都相同。
警告
封存檔是實驗性的。在未來的版本中,可能會移除它們或變更其行為。
範例
> code:lib_dir(mnesia).
"/usr/local/otp/lib/mnesia-4.23"
如果 Name
不是 $OTPROOT/lib
下或透過環境變數 ERL_LIBS
指向的目錄中的應用程式名稱,則返回 {error, bad_name}
。如果 Name
的類型錯誤,則會出現例外狀況而失敗。
警告
為了保持回溯相容性,也允許
Name
為字串。這在未來版本中可能會變更。
-spec lib_dir(Name, SubDir) -> file:filename() | {error, bad_name} when Name :: atom(), SubDir :: atom().
傳回應用程式頂層目錄下的子目錄路徑。
變更
此函式是封存檔支援的一部分,封存檔支援是一個實驗性功能,將在未來的版本中變更或移除。
通常,子目錄位於應用程式的頂層目錄下,但是當應用程式至少部分位於封存檔中時,情況會有所不同。某些子目錄可以以常規目錄的形式存在,而其他子目錄則位於封存檔中。不會檢查此目錄是否存在。
請改用 code:lib_dir/1
和 filename:join/2
,而不是使用此函式。
範例
1> filename:join(code:lib_dir(megaco), "priv").
"/usr/local/otp/lib/megaco-3.9.1.1/priv"
如果 Name
或 SubDir
的類型錯誤,則會出現例外狀況而失敗。
-spec load_abs(Filename) -> load_ret() when Filename :: file:filename().
等同於 load_file(Module)
,不同之處在於 Filename
是絕對或相對檔名。
不會搜尋程式碼路徑。它返回的值與 load_file/1
的方式相同。請注意,Filename
不得包含副檔名(例如,.beam
),因為 load_abs/1
會新增正確的副檔名。
-spec load_binary(Module, Filename, Binary) -> {module, Module} | {error, What} when Module :: module(), Filename :: loaded_filename(), Binary :: binary(), What :: badarg | load_error_rsn().
從二進位資料載入物件程式碼。
此函式可用於在遠端 Erlang 節點上載入物件碼。引數 Binary
必須包含 Module
的物件碼。Filename
僅供程式碼伺服器記錄 Module
的物件碼來自哪個檔案。因此,程式碼伺服器不會開啟和讀取 Filename
。
如果成功,則返回 {module, Module}
,如果載入失敗,則返回 {error, Reason}
。有關可能的錯誤原因描述,請參閱程式碼載入函式的錯誤原因。
嘗試使用程式碼路徑載入 Erlang 模組 Module
。
它會搜尋與所使用 Erlang 機器相對應的副檔名的物件碼檔案,例如 Module.beam
。如果在物件碼中找到的模組名稱與名稱 Module
不同,則載入會失敗。請使用 load_binary/3
載入模組名稱與檔案名稱不同的物件碼。
如果成功,則返回 {module, Module}
,如果載入失敗,則返回 {error, Reason}
。有關可能的錯誤原因描述,請參閱程式碼載入函式的錯誤原因。
-spec modified_modules() -> [module()].
傳回目前已載入的所有模組的清單,其中 module_status/1
傳回 modified
。
另請參閱 all_loaded/0
。
-spec module_status() -> [{module(), module_status()}].
詳細資訊請參閱 module_status/1
和 all_loaded/0
。
-spec module_status(Module :: module() | [module()]) -> module_status() | [{module(), module_status()}].
傳回 Module
相對於磁碟上物件檔案的狀態。
模組的狀態可以是下列其中之一
not_loaded
- 如果目前未載入Module
。loaded
- 如果已載入Module
,且物件檔案存在並包含相同的程式碼。removed
- 如果已載入Module
,但在程式碼路徑中找不到對應的物件檔案。modified
- 如果已載入Module
,但物件檔案包含具有不同 MD5 檢查碼的程式碼。
預先載入的模組一律報告為 loaded
,而不檢查磁碟上的內容。如果物件檔案存在,則 Cover 編譯的模組一律報告為 modified
,否則報告為 removed
。載入路徑為空字串(這是自動產生程式碼的慣例)的模組只會報告為 loaded
或 not_loaded
。
另請參閱 modified_modules/0
。
-spec objfile_extension() -> nonempty_string().
返回對應於所使用 Erlang 機器的目標碼檔案副檔名。
對於官方 Erlang/OTP 版本,傳回值一律為 .beam
。
-spec prepare_loading(Modules) -> {ok, Prepared} | {error, [{Module, What}]} when Modules :: [Module | {Module, Filename, Binary}], Module :: module(), Filename :: file:filename(), Binary :: binary(), Prepared :: prepared_code(), What :: badfile | nofile | on_load_not_allowed | duplicated.
準備載入列表 Modules
中的模組。
呼叫 finish_loading(Prepared) 以完成載入。
此函式可能會因以下錯誤原因之一而失敗
badfile
- 物件程式碼的格式不正確,或物件程式碼中的模組名稱不是預期的模組名稱。nofile
- 沒有目標碼的檔案存在。on_load_not_allowed
- 模組包含 -on_load 函式。duplicated
-Modules
中多次包含模組。
-spec priv_dir(Name) -> file:filename() | {error, bad_name} when Name :: atom().
返回應用程式中 priv
目錄的路徑。
警告
為了保持回溯相容性,也允許
Name
為字串。這在未來版本中可能會變更。
清除 Module
的程式碼,也就是移除標記為舊的程式碼。
如果某些程序仍然停留在舊程式碼中,這些程序會在移除程式碼之前被終止。
變更
自 Erlang/OTP 20.0 起,只有當程序直接參考程式碼時,才被視為停留在程式碼中。如需更多資訊,請參閱
erlang:check_process_code/3
的文件,該文件用於判斷程序是否停留在程式碼中。
如果成功且需要終止任何程序,則返回 true
,否則返回 false
。
-spec replace_path(Name, Dir) -> replace_path_ret() when Name :: atom(), Dir :: file:filename().
-spec replace_path(Name, Dir, cache()) -> replace_path_ret() when Name :: atom(), Dir :: file:filename().
將程式碼路徑中名為 .../Name[-Vsn][/ebin]
的舊目錄出現位置,取代為 Dir
。
如果 Name
不存在,它會在程式碼路徑的最後新增新的目錄 Dir
。新目錄也必須命名為 .../Name[-Vsn][/ebin]
。如果將新版本的目錄(函式庫)新增至執行中的系統,則應使用此函式。
引數 Cache
控制是否應在第一次遍歷時快取目錄的內容。如果 Cache
是 cache
,目錄內容將被快取;如果 Cache
是 nocache
,則不會被快取。
返回
true
- 如果成功{error, bad_name}
- 如果找不到Name
{error, bad_directory}
- 如果Dir
不存在{error, {badarg, [Name, Dir]}}
- 如果Name
或Dir
無效
-spec reset_coverage(Module) -> ok when Module :: module().
重設模組 Module
的覆蓋率資訊。
如果 涵蓋率模式 為 function
或 line
,則所有用於追蹤已執行函式或行的 Module
布林值都會設定為 false
。
如果涵蓋率模式為 function_counters
或 line_counters
,則 Module
的所有計數器都會重設為零。
失敗情況
badarg
- 如果Module
不是原子。badarg
- 如果Module
沒有指向已載入的模組。badarg
- 如果Module
未啟用涵蓋率載入。badarg
- 如果執行階段系統不支援覆蓋率。
另請參閱: 原生覆蓋率支援
-spec root_dir() -> file:filename().
返回 Erlang/OTP 的根目錄,也就是其安裝所在的目錄。
範例
1> code:root_dir().
"/usr/local/otp"
-spec set_coverage_mode(Mode) -> OldMode when Mode :: coverage_mode(), OldMode :: coverage_mode().
設定後續載入模組的覆蓋率模式,類似於 erl
的選項 +JPcover。
涵蓋率模式將對此呼叫後載入的程式碼產生以下影響
function
- 所有載入的模組都將被檢測,以追蹤已執行哪些函式。可以透過呼叫get_coverage(function, Module)
來擷取有關已執行哪些函式的資訊。function_counters
- 所有載入的模組都將被檢測,以計算每個函式執行的次數。可以透過呼叫get_coverage(function, Module)
來擷取有關每個函式已執行多少次的資訊。line
- 當載入使用line_coverage
選項編譯的模組時,它們將被檢測以追蹤已執行哪些程式碼行。可以透過呼叫get_coverage(line, Module)
來擷取有關已執行哪些行的資訊,並且可以透過呼叫get_coverage(function, Module)
來擷取有關已執行哪些函式的資訊。line_counters
- 當載入使用line_coverage
選項編譯的模組時,它們將被檢測以計算每行程式碼執行的次數。可以透過呼叫get_coverage(line, Module)
來擷取有關每行程式碼已執行多少次的資訊,並且可以透過呼叫get_coverage(function, Module)
來擷取有關已執行哪些函式的資訊(請注意,在此模式下,**無法**擷取每個函式已執行次數的計數器)。none
- 將載入模組,而不會進行涵蓋率檢測。
返回先前的涵蓋率模式。
失敗情況
badarg
- 如果Mode
不是有效的涵蓋率模式。badarg
- 如果執行階段系統不支援覆蓋率。
另請參閱: 原生覆蓋率支援
-spec set_path(Path) -> set_path_ret() when Path :: [Dir :: file:filename()].
-spec set_path(Path, cache()) -> set_path_ret() when Path :: [Dir :: file:filename()].
將程式碼路徑設定為目錄列表 Path
。
引數 Cache
控制是否應在第一次遍歷時快取目錄的內容。如果 Cache
是 cache
,目錄內容將被快取;如果 Cache
是 nocache
,則不會被快取。
返回
true
- 如果成功{error, bad_directory}
- 如果任何Dir
不是目錄名稱
清除 Module
的程式碼,也就是移除標記為舊的程式碼,但僅限於其中沒有持續執行的程序。
變更
自 Erlang/OTP 20.0 起,只有當程序直接參考程式碼時,才被視為停留在程式碼中。如需更多資訊,請參閱
erlang:check_process_code/3
的文件,該文件用於判斷程序是否停留在程式碼中。
如果因為舊程式碼中仍有程序停留而無法清除模組,則返回 false
,否則返回 true
。
-spec stick_dir(Dir) -> ok | error when Dir :: file:filename().
將 Dir
標記為黏性的。
如果成功,則返回 ok
,否則返回 error
。
-spec unstick_dir(Dir) -> ok | error when Dir :: file:filename().
取消標記為黏性的目錄。
如果成功,則返回 ok
,否則返回 error
。
-spec where_is_file(Filename) -> non_existing | Absname when Filename :: file:filename(), Absname :: file:filename().
在程式碼路徑中搜尋 Filename
,這是一個任意類型的檔案。
如果找到,則返回完整名稱。如果找不到該檔案,則返回 non_existing
。此函式可能很有用,例如,用於尋找應用程式資源檔案。
-spec which(Module) -> Which when Module :: module(), Which :: loaded_filename() | non_existing.
如果模組尚未載入,此函式會在程式碼路徑中搜尋第一個包含 Module
目標碼的檔案,並返回絕對檔案名稱。
如果載入模組,則返回包含已載入物件程式碼的檔案名稱。
如果模組是預先載入的,則返回
preloaded
。如果模組是 Cover 編譯的,則返回
cover_compiled
。如果找不到模組,則返回
non_existing
。