查看源代码 code (内核 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
原子作为可选参数,以选择性地启用缓存。
从归档文件加载代码
更改
对归档文件的现有实验性支持将在未来版本中更改。截至 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 参考手册》中的“编译和代码加载”部分: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
,则不会缓存。
始终返回 ok
,无论每个单独的 Dir
是否有效。
-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
,则不会缓存。
始终返回 ok
,无论每个单独的 Dir
是否有效。
-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]
的目录将被删除。
始终返回 ok
,无论每个单独的 NamesOrDirs
是否有效。
删除 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
- 对于模块中的每个可执行行,返回一个整数,表示该行被执行的次数。
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
。