模块 Misc.Magic_number

module Magic_number: sig .. end

一个典型的魔数是 "Caml1999I011";它由一个字母数字前缀(此处为 Caml1990I)和一个版本号(此处为 011)组成。前缀标识版本化数据的类型:此处 I 表示它是 .cmi 文件的魔数。

所有魔数都具有相同的字节长度,magic_length,这对用户来说非常重要,因为它告诉他们需要读取多少个字节才能获取应该作为魔数的字节序列。典型的用户代码如下所示

        let ic = open_in_bin path in
        let magic =
          try really_input_string ic Magic_number.magic_length
          with End_of_file -> ... in
        match Magic_number.parse magic with
        | Error parse_error -> ...
        | Ok info -> ...
      

给定的编译器版本期望每种类型的目标文件都使用一个特定的版本,如果给定不支持的版本,则会失败。由于版本单调递增,因此您可以将解析的版本与某种类型的预期“当前版本”进行比较,以判断错误魔数的目标文件来自过去还是未来。

以下是一个代码块示例,该代码块期望给定类型的魔数的“当前支持版本”,此处为 Cmxa

        let ic = open_in_bin path in
        begin
          try Magic_number.(expect_current Cmxa (get_info ic)) with
          | Parse_error error -> ...
          | Unexpected error -> ...
        end;
        ...
      

解析错误区分输入是 Not_a_magic_number str(这可能是由于文件完全不同造成的)和 Truncated str(由作为有效魔数的前缀(可能是空前缀)的头文件引发)。

意外错误对应于不是预期魔数的有效魔数,这可能是因为它们对应于不同的类型,或者对应于更新或旧的版本。

辅助函数 explain_parse_errorexplain_unexpected_error 将生成每个错误的文本解释,供错误消息使用。

type native_obj_config = {
   flambda : bool;
}

原生目标文件的格式和魔数取决于某些原生编译器配置参数。此配置空间由 native_obj_config 类型表示。

val native_obj_config : native_obj_config

活动/已配置编译器的原生目标文件配置。

type version = int 
type kind = 
| Exec
| Cmi
| Cmo
| Cma
| Cmx of native_obj_config
| Cmxa of native_obj_config
| Cmxs
| Cmt
| Ast_impl
| Ast_intf
type info = {
   kind : kind;
   version : version; (*

注意:某些版本的编译器对所有类型使用相同的 version 后缀,但其他编译器对不同类型使用不同的版本计数器。我们只能假设版本在编译器版本之间单调递增(不一定是每次递增 1)。

*)
}
type raw = string 

原始魔数的类型,例如 OCaml 4.10 的 .cma 文件的 "Caml1999A027"

解析魔数

type parse_error = 
| Truncated of string
| Not_a_magic_number of string
val explain_parse_error : kind option -> parse_error -> string

生成解析错误的解释。如果没有提供类型,我们将使用一种不特定的表述,表明任何编译器生成的输出文件都应该能够满足要求。

val parse : raw ->
(info, parse_error) result

解析原始魔数

val read_info : in_channel ->
(info, parse_error) result

从输入通道读取原始魔数。

如果读取的数据 str 不是有效的魔数,则可以从 Truncated str | Not_a_magic_number str 负载的 Error parse_error 案例中恢复它。

如果解析成功并得到 Ok info 结果,我们知道已从 input_channel 中消耗了正好 magic_length 个字节。

如果您还想强制魔数处于当前版本,请参阅下面的 Misc.Magic_number.read_current_info

val magic_length : int

所有魔数都占用相同数量的字节

检查魔数是否为当前版本

type 'a unexpected = {
   expected : 'a;
   actual : 'a;
}
type unexpected_error = 
| Kind of kind unexpected
| Version of kind
* version unexpected
val check_current : kind ->
info ->
(unit, unexpected_error) result

check_current kind info 检查提供的魔数 info 是否为 kind 的魔数头的当前版本。

val explain_unexpected_error : unexpected_error -> string

提供 unexpected_error 的解释。

type error = 
| Parse_error of parse_error
| Unexpected_error of unexpected_error
val read_current_info : expected_kind:kind option ->
in_channel ->
(info, error) result

将魔数读取为 read_info,并检查它是否为其类型的当前版本。如果 expected_kind 参数为 None,则接受任何类型。

关于魔数的信息

val string_of_kind : kind -> string

类型的用户可打印字符串,例如 "exec" 或 "cmo",用于错误消息。

val human_name_of_kind : kind -> string

类型的用户友好的名称,例如 "可执行文件" 或 "字节码目标文件",用于错误消息。

val current_raw : kind -> raw

每种类型的当前魔数

val current_version : kind -> version

每种类型的当前版本

原始表示

主要用于内部使用和测试。

type raw_kind = string 

原始魔数类型的类型,例如 .cma 文件的 "Caml1999A"

val parse_kind : raw_kind -> kind option

将原始类型解析为类型。

val raw_kind : kind -> raw_kind

类型的当前原始表示。

在某些情况下,类型的原始表示在编译器版本之间发生了变化,因此相同类型的其他文件可能具有不同的原始类型。请注意,所有当前已知的案例都由 parse_kind 正确解析。

val raw : info -> raw

魔数的有效原始表示。

由于魔数字符串表示形式的过去和未来更改,我们无法保证为过去和未来版本返回的原始字符串是否实际与这些编译器的期望相匹配。该表示对于当前版本是准确的,并且通过上述解析函数可以将其正确地解析回所需的版本。

val all_kinds : kind list