☰ OCaml 工具
第 16 章 本机代码编译 (ocamlopt)
本章介绍 OCaml 高性能本机代码编译器 ocamlopt ,它将 OCaml 源文件编译成本机代码目标文件,并将这些目标文件链接起来生成独立的可执行文件。
本机代码编译器仅在某些平台上可用。它生成的代码运行速度比 ocamlc 生成的字节码快,但代价是编译时间和可执行文件大小增加。与字节码编译器的兼容性非常高:相同的源代码在使用 ocamlc 和 ocamlopt 编译时应该运行相同。
无法将 ocamlopt 生成的本机代码目标文件与 ocamlc 生成的字节码目标文件混合:程序必须完全使用 ocamlopt 或完全使用 ocamlc 编译。由 ocamlopt 生成的本机代码目标文件无法加载到顶层系统 ocaml 中。
1 编译器的概述
ocamlopt 命令的命令行界面与 ocamlc 的命令行界面非常接近。它接受相同类型的参数,并在处理完所有选项后按顺序处理它们。
链接阶段的输出是常规的 Unix 或 Windows 可执行文件。它不需要 ocamlrun 即可运行。
编译器能够在其内部阶段发出一些信息。
2 选项
ocamlopt 识别以下命令行选项。选项 -pack 、-a 、-shared 、-c 、-output-obj 和 -output-complete-obj 是互斥的。
-a 使用命令行上给定的目标文件 (.cmx 和 .o /.obj 文件) 构建库 (.cmxa 和 .a /.lib 文件),而不是将它们链接到可执行文件中。库的名称必须使用 -o 选项设置。如果在命令行上传递了 -cclib 或 -ccopt 选项,则这些选项将存储在生成的 .cmxa 库中。然后,使用此库进行链接会自动添加回 -cclib 和 -ccopt 选项,就像它们是在命令行上提供的,除非给出了 -noautolink 选项。
-absname 强制错误消息显示文件名的绝对路径。 -no-absname 不要尝试在错误消息中显示绝对文件名。 -annot 自 OCaml 4.11 起已弃用。请改用 -bin-annot 。 -args filename 从 filename 读取其他以换行符结尾的命令行参数。 -args0 filename 从 filename 读取其他以空字符结尾的命令行参数。 -bin-annot 以二进制格式转储有关编译的详细信息(类型、绑定、尾调用等)。文件 src .ml (或 src .mli )的信息将放入文件 src .cmt (或 src .cmti )中。在发生类型错误的情况下,转储类型检查器在错误之前推断的所有信息。*.cmt 和 *.cmti 由 -bin-annot 生成,包含更多信息,并且比 -annot 生成文件更紧凑。 -c 仅编译。禁止编译的链接阶段。源代码文件将转换为编译后的文件,但不会生成可执行文件。此选项可用于单独编译模块。 -cc ccomp
使用 ccomp 作为构建最终可执行文件的 C 链接器,以及编译 .c 源文件的 C 编译器。当链接由 C++ 编译器(例如 g++ 或 clang++ )生成的 .o 文件时,建议使用 -cc c++ 。 -cclib -l libname 将 -l libname 选项传递给链接器。这会导致将给定的 C 库链接到程序中。 -ccopt option 将给定的选项传递给 C 编译器和链接器。例如,-ccopt -L dir 会导致 C 链接器在目录 dir 中搜索 C 库。 -cmi-file filename 使用给定的接口文件来类型检查要编译的 ML 源文件。当未指定此选项时,编译器会在与正在编译的实现文件同名的目录中搜索一个 .mli 文件。如果找到此文件,编译器将在包含的目录中搜索对应的 .cmi 文件,如果未找到则报告错误。 -color mode 启用或禁用编译器消息(尤其是警告和错误)中的颜色。支持以下模式
auto 使用启发式方法仅在输出支持颜色时启用颜色(兼容 ANSI 的 tty 终端); always 无条件启用颜色; never 禁用颜色输出。 如果未提供 -color ,则会考虑环境变量 OCAML_COLOR 。其值如上所述为 auto/always/never。
如果未提供 -color ,OCAML_COLOR 未设置且环境变量 NO_COLOR 已设置,则禁用颜色输出。否则,默认设置为“auto”,并且当前启发式检查 TERM 环境变量是否存在且不为空或为 dumb ,以及“isatty(stderr)”是否成立。
-error-style mode 控制错误消息和警告的打印方式。支持以下模式
short 仅打印错误及其位置; contextual 类似于 short ,但还会显示与错误位置对应的源代码片段。 默认设置为 contextual 。如果未提供 -error-style ,则会考虑环境变量 OCAML_ERROR_STYLE 。其值如上所述为 short/contextual。
-compact 优化生成的代码以节省空间而不是时间。这将导致程序稍小但稍慢。默认情况下,优化速度。 -config 打印 ocamlopt 的版本号及其配置的详细摘要,然后退出。 -config-var var 打印来自 -config 输出的特定配置变量的值,然后退出。如果变量不存在,则退出代码为非零。此选项仅在 OCaml 4.08 及更高版本中可用,因此脚本作者应该为旧版本提供备用方案。 -depend ocamldep-args 计算依赖项,就像 ocamldep 命令一样。其余参数被解释为如果它们传递给 ocamldep 命令。 -for-pack module-path 生成一个对象文件(.cmx 和 .o /.obj 文件),稍后可以将其作为编译单元(使用 -pack 构造)的子模块(使用给定的访问路径)包含。例如,ocamlopt -for-pack P -c A.ml 将生成 a..cmx 和 a.o 文件,稍后可与 ocamlopt -pack -o P.cmx a.cmx 一起使用。注意:您仍然可以打包未使用 -for-pack 编译的模块,但在这种情况下,异常将使用错误的名称打印。 -g 在编译和链接时添加调试信息。此选项是必需的,以便在程序因未捕获的异常终止时生成堆栈回溯(参见第 15.2 节)。 -no-g 不记录调试信息(默认值)。 -i 导致编译器在编译实现文件(.ml 文件)时打印所有定义的名称(及其推断的类型或定义)。不生成编译文件(.cmo 和 .cmi 文件)。这对于检查编译器推断的类型很有用。此外,由于输出遵循接口的语法,因此它可以帮助编写文件的显式接口(.mli 文件):只需将编译器的标准输出重定向到 .mli 文件,然后编辑该文件以删除所有未导出名称的声明。 -I directory 将给定的目录添加到用于搜索编译接口文件(.cmi )、编译对象代码文件(.cmx )和库(.cmxa )的目录列表中。默认情况下,首先搜索当前目录,然后搜索标准库目录。使用 -I 添加的目录在当前目录之后搜索,按照它们在命令行上给出的顺序,但在标准库目录之前。另请参见选项 -nostdlib 。如果给定的目录以 + 开头,则将其视为相对于标准库目录。例如,-I +unix 将标准库的子目录 unix 添加到搜索路径。
-H directory 行为与 -I 完全相同,除了 (a) 程序可能无法直接引用以这种方式添加到搜索路径的模块,以及 (b) 这些目录在任何 -I 目录之后搜索。这使得可以为当前程序的传递依赖项(其依赖项的依赖项)提供编译的接口和对象代码文件,而无需允许它们静默地成为直接依赖项。 -impl filename 将文件 filename 编译为实现文件,即使其扩展名不是 .ml 。 -inline n 将内联的激进程度设置为 n ,其中 n 是一个正整数。指定 -inline 0 将阻止所有函数内联,除了其主体小于调用位置的函数。因此,内联不会导致代码大小扩展。默认激进程度 -inline 1 允许稍微更大的函数内联,从而导致代码大小略微扩展。-inline 选项的较高值会导致越来越大的函数成为内联的候选对象,但可能导致代码大小大幅增加。 -intf filename 将文件 filename 编译为接口文件,即使其扩展名不是 .mli 。 -intf-suffix string 将以 string 结尾的文件名识别为接口文件(而不是默认的 .mli )。 -labels 在类型中不忽略标签,标签可以在应用程序中使用,并且带标签的参数可以以任何顺序给出。这是默认设置。 -linkall 强制链接库中包含的所有模块。如果未给出此标志,则不会链接未引用的模块。在构建库(选项 -a )时,设置 -linkall 选项会强制随后涉及该库的所有程序链接都链接库中包含的所有模块。在编译模块(选项 -c )时,设置 -linkall 选项可确保如果将此模块放入库中并链接此库,则始终链接此模块。 -linscan 使用线性扫描寄存器分配。使用此分配器编译比使用通常的图着色分配器更快,有时对于长函数和模块来说快得多。另一方面,生成的代码可能会稍微慢一些。 -match-context-rows 设置在模式匹配编译期间用于优化的上下文行数。默认值为 32。较低的值会导致编译速度更快,但代码优化程度较低。此高级选项用于模式匹配密集型程序导致编译时间显着增加的情况。 -no-alias-deps 不记录模块别名的依赖项。有关更多信息,请参见第 12.8 节。 -no-app-funct 停用函子的应用行为。使用此选项,每个函子应用都会在其结果中生成新的类型,并且将同一个函子应用两次到同一个参数会产生两个不兼容的结构。 -no-float-const-prop 停用浮点运算的常量传播。如果程序在执行期间更改浮点舍入模式,则应给出此选项。 -noassert 不编译断言检查。请注意,特殊形式 assert false 始终被编译,因为它被特殊类型化。此标志在链接已编译的文件时无效。 -noautolink 在链接 .cmxa 库时,忽略库中可能包含的 -cclib 和 -ccopt 选项(如果在构建库时给出了这些选项)。如果库包含不正确的 C 库或 C 选项规范,这将很有用;在这种情况下,在链接期间,设置 -noautolink 并通过命令行传递正确的 C 库和选项。 -nodynlink 允许编译器使用一些仅对静态链接的代码有效的优化以生成不可重定位的可执行文件。生成的代码不能链接以生成共享库或位置无关的可执行文件 (PIE)。许多操作系统默认生成 PIE,这会导致在链接使用 -nodynlink 编译的代码时出错。要么不要使用 -nodynlink ,要么在链接时传递选项 -ccopt -no-pie 。 -nolabels
忽略类型中的非可选标签。标签无法在应用程序中使用,并且参数顺序变得严格。 -nostdlib 不要自动将标准库目录添加到用于搜索编译接口文件(.cmi )、编译对象代码文件(.cmx )和库文件(.cmxa )的目录列表中。另请参见选项 -I 。 -o 输出文件 指定要生成的输出文件的名称。对于可执行文件,在 Unix 下默认输出名称为 a.out ,在 Windows 下为 camlprog.exe 。如果给出了 -a 选项,则指定生成的库的名称。如果给出了 -pack 选项,则指定生成的打包对象文件的名称。如果给出了 -output-obj 或 -output-complete-obj 选项,则指定生成的输出文件的名称。如果给出了 -shared 选项,则指定生成的插件文件的名称。 -opaque 当原生编译器编译实现时,默认情况下它会生成一个包含跨模块优化信息的 .cmx 文件。它还期望 .cmx 文件存在于当前编译源的依赖项中,并使用它们进行优化。从 OCaml 4.03 开始,如果编译器无法找到其中一个依赖项的 .cmx 文件,它将发出警告。自 4.04 版本起提供的 -opaque 选项会禁用当前编译单元的跨模块优化信息。在编译 .mli 接口时,使用 -opaque 会标记编译后的 .cmi 接口,以便随后编译依赖它的模块不会依赖于相应的 .cmx 文件,也不会在该文件不存在时发出警告。当原生编译器编译 .ml 实现时,使用 -opaque 会生成一个不包含任何跨模块优化信息的 .cmx 文件。
使用此选项可能会降低生成代码的质量,但它会减少编译时间,无论是在干净构建还是增量构建中。实际上,使用原生编译器时,当编译单元的实现发生更改时,所有依赖它的单元可能都需要重新编译,因为跨模块信息可能已更改。如果实现发生更改的编译单元是用 -opaque 编译的,则无需进行此类重新编译。因此,此选项可用于获得更快的编辑-编译-测试反馈循环,例如。
-open 模块 在处理接口或实现文件之前打开给定的模块。如果给出了多个 -open 选项,则按顺序处理它们,就像在每个文件的顶部添加了语句 open! 模块1 ;; ... open! 模块N ;; 一样。 -output-obj 使链接器生成 C 对象文件而不是可执行文件。这对于将 OCaml 代码包装为 C 库很有用,可以从任何 C 程序调用。参见第 22 章,第 22.7.5 节。输出对象文件的名称必须使用 -o 选项设置。此选项也可用于生成编译后的共享/动态库(.so 扩展名,在 Windows 下为 .dll )。 -output-complete-obj 与 -output-obj 选项相同,只是生成的输出文件包含运行时库和自动链接库。 -pack 构建一个对象文件(.cmx 和 .o /.obj 文件)及其关联的编译接口(.cmi ),它组合了命令行上给出的 .cmx 对象文件,使它们看起来像是输出 .cmx 文件的子模块。输出 .cmx 文件的名称必须使用 -o 选项给出。例如, ocamlopt -pack -o P.cmx A.cmx B.cmx C.cmx
生成编译文件 P.cmx 、P.o 和 P.cmi ,描述一个具有三个子模块 A 、B 和 C 的编译单元,对应于对象文件 A.cmx 、B.cmx 和 C.cmx 的内容。这些内容可以在程序的其余部分中作为 P.A 、P.B 和 P.C 来引用。要组合的 .cmx 对象文件必须使用适当的 -for-pack 选项进行编译。在上面的示例中,A.cmx 、B.cmx 和 C.cmx 必须使用 ocamlopt -for-pack P 进行编译。
可以通过组合 -pack 和 -for-pack 来实现多级打包。考虑以下示例
ocamlopt -for-pack P.Q -c A.ml
ocamlopt -pack -o Q.cmx -for-pack P A.cmx
ocamlopt -for-pack P -c B.ml
ocamlopt -pack -o P.cmx Q.cmx B.cmx
生成的 P.cmx 对象文件具有子模块 P.Q 、P.Q.A 和 P.B 。
-pp 命令 使编译器调用给定的 命令 作为每个源文件的预处理器。 命令 的输出重定向到一个中间文件,该文件会被编译。如果没有编译错误,则随后会删除中间文件。 -ppx 命令 解析后,通过预处理器 命令 传递抽象语法树。模块 Ast_mapper (在第 30 章中描述): Ast_mapper ,实现了预处理器的外部接口。 -principal 在类型检查期间检查信息路径,以确保所有类型都以主要方式派生。在使用带标签的参数和/或多态方法时,此标志是确保编译器的未来版本能够正确推断类型所必需的,即使内部算法发生更改也是如此。在 -principal 模式下接受的所有程序也在默认模式下接受,具有等效类型,但二进制签名不同,这可能会减慢类型检查速度;但是,在发布源代码之前使用一次是个好主意。 -rectypes 在类型检查期间允许任意递归类型。默认情况下,仅支持递归遍历对象类型的递归类型。请注意,一旦使用此标志创建了接口,就必须对所有依赖项再次使用它。 -runtime-variant 后缀 将 后缀 字符串添加到程序使用的运行时库的名称中。当前,仅支持一个这样的后缀:d ,并且仅当 OCaml 编译器在配置时使用了选项 -with-debug-runtime 时才支持。此后缀提供运行时的调试版本,这对于调试底层代码(例如 C 存根)中的指针问题很有用。 -S 保留编译期间生成的汇编代码。源文件 x .ml 的汇编代码保存在文件 x .s 中。 -safe-string 强制执行类型 string 和 bytes 之间的分离,从而使字符串成为只读的。这是默认设置,并且从 OCaml 5.0 开始强制执行。 -safer-matching 不要使用类型信息来优化模式匹配。这允许检测匹配失败,即使模式匹配被错误地认为是详尽的。这仅影响 GADT 和多态变体编译。 -save-ir-after 过程 在给定的编译过程之后将中间表示保存到文件中。当前支持的过程和相应的扩展名是:调度 (.cmir-linear )。此实验性功能使外部工具能够使用 compiler-libs 库检查和操作编译器程序的中间表示(参见第 30 章和 Compiler_libs )。
-shared
构建一个插件(通常为.cmxs ),可以使用Dynlink 模块动态加载。插件名称必须使用-o 选项设置。插件可以包含多个OCaml模块和库,以及额外的原生对象(.o 、.obj 、.a 、.lib 文件)。构建原生插件仅在某些操作系统上受支持。在某些系统(目前仅限Linux AMD 64)下,链接到插件中的所有OCaml代码都必须在不使用-nodynlink 标志的情况下进行编译。对额外原生对象的编译方式也可能存在一些限制(在Linux AMD 64下,它们必须仅包含位置无关代码)。 -short-paths 当一个类型在多个模块路径下可见时,在打印类型名称(推断接口以及错误和警告信息中)时,使用最短的路径。以下划线_ 开头或包含双下划线__ 的标识符名称,在计算其长度时,会额外增加10的惩罚。 -stop-after pass 在给定的编译阶段停止编译。当前支持的阶段包括:parsing (解析)、typing (类型检查)、scheduling (调度)、emit (生成)。 -strict-sequence 强制每个序列的左侧部分具有unit类型。 -strict-formats 拒绝在旧版格式实现中被接受的无效格式。您应该使用此标志来检测和修复此类无效格式,因为未来的OCaml版本将拒绝它们。 -unboxed-types 当一个类型可取消装箱(即只有一个参数的记录或只有一个参数的构造函数的具体数据类型)时,除非使用[@@ocaml.boxed] 进行注释,否则它将被取消装箱。 -no-unboxed-types 当一个类型可取消装箱时,除非使用[@@ocaml.unboxed] 进行注释,否则它将被装箱。这是默认设置。 -unsafe 关闭数组和字符串访问的边界检查(v.(i) 和s.[i] 构造)。因此,使用-unsafe 编译的程序速度更快,但也不安全:如果程序访问数组或字符串超出其边界,则可能发生任何事情。此外,关闭整数除法和模运算中零除数的检查。使用-unsafe 时,整数除以零可能会停止程序或继续执行并产生未指定的结果,而不是引发Division_by_zero 异常。 -unsafe-string 识别string 和bytes 类型,从而使字符串可写。这旨在与旧版源代码兼容,不应在新的软件中使用。从OCaml 5.0开始,此选项将无条件地引发错误。 -v 打印编译器的版本号和标准库目录的位置,然后退出。 -verbose 在执行之前打印所有外部命令,特别是汇编器、C编译器和链接器的调用。这有助于调试C库问题。 -version 或 -vnum 以简短形式打印编译器的版本号(例如3.11.0 ),然后退出。 -w warning-list 启用、禁用或将参数warning-list 指定的警告标记为致命。每个警告可以被启用 或禁用 ,并且每个警告可以是致命 或非致命 的。如果禁用某个警告,则不会显示它,也不会以任何方式影响编译(即使它是致命的)。如果启用某个警告,则编译器在源代码触发它时会正常显示它。如果它被启用并且是致命的,编译器在显示它后也会停止并报错。warning-list 参数是一系列警告说明符,它们之间没有分隔符。警告说明符是以下之一
+ num 启用警告编号num 。 - num 禁用警告编号num 。 @ num 启用并标记警告编号num 为致命。 + num1 ..num2 启用给定范围内的警告。 - num1 ..num2 禁用给定范围内的警告。 @ num1 ..num2 启用并标记给定范围内的警告为致命。 + letter 启用与letter 对应的警告集。字母可以是大写或小写。 - letter 禁用与letter 对应的警告集。字母可以是大写或小写。 @ letter 启用并标记与letter 对应的警告集为致命。字母可以是大写或小写。 uppercase-letter 启用与uppercase-letter 对应的警告集。 lowercase-letter 禁用与lowercase-letter 对应的警告集。 或者,warning-list 可以使用其助记符名称(见下文)指定单个警告,如下所示
+ name 启用警告name 。 - name 禁用警告name 。 @ name 启用并标记警告name 为致命。 当前未定义的警告编号、字母和名称将被忽略。警告如下所示(每个编号后面的名称指定该警告的助记符)。
1 comment-start 可疑的注释开头标记。 2 comment-not-end 可疑的注释结尾标记。 3 “已弃用”警告的已弃用同义词。 4 fragile-match 脆弱的模式匹配:即使向匹配的变体类型添加其他构造函数,匹配也将保持完整。 5 ignored-partial-application 部分应用函数:结果具有函数类型且被忽略的表达式。 6 labels-omitted 函数应用中省略的标签。 7 method-override 重写的方法。 8 partial-match 部分匹配:模式匹配中缺少的案例。 9 missing-record-field-pattern 记录模式中缺少的字段。 10 non-unit-statement 序列左侧的表达式类型不是unit (并且不是函数,请参见警告编号5)。 11 redundant-case 模式匹配中冗余的案例(未使用的匹配案例)。 12 redundant-subpat 模式匹配中冗余的子模式。 13 instance-variable-override 重写的实例变量。 14 illegal-backslash 字符串常量中非法的反斜杠转义。 15 implicit-public-methods 隐式公开的私有方法。 16 unerasable-optional-argument 不可擦除的可选参数。 17 undeclared-virtual-method 未声明的虚方法。 18 not-principal 非主要类型。 19 non-principal-labels 没有主要性的类型。 20 ignored-extra-argument 未使用的函数参数。 21 nonreturning-statement 非返回语句。 22 preprocessor 预处理器警告。 23 useless-record-with 无用的记录with 子句。 24 bad-module-name 错误的模块名称:源文件名不是有效的OCaml模块名称。 25 已忽略:现在是警告8的一部分。 26 unused-var 可疑的未使用变量:使用let 或as 绑定的未使用变量,并且不以下划线(_ )字符开头。 27 unused-var-strict 无害的未使用变量:未使用let 或as 绑定的未使用变量,并且不以下划线(_ )字符开头。 28 wildcard-arg-to-constant-constr 将通配符模式作为参数传递给常量构造函数。 29 eol-in-string 字符串常量中存在未转义的行尾(不可移植的代码)。 30 duplicate-definitions 在两个相互递归的类型中定义了两个同名的标签或构造函数。 31 module-linked-twice 同一个可执行文件中链接了同一个模块两次。 I 被忽略:现在是一个硬错误(自 5.1 版起)。 32 unused-value-declaration 未使用的值声明。(自 4.00 版起) 33 unused-open 未使用的 open 语句。(自 4.00 版起) 34 unused-type-declaration 未使用的类型声明。(自 4.00 版起) 35 unused-for-index 未使用的 for 循环索引。(自 4.00 版起) 36 unused-ancestor 未使用的祖先变量。(自 4.00 版起) 37 unused-constructor 未使用的构造函数。(自 4.00 版起) 38 unused-extension 未使用的扩展构造函数。(自 4.00 版起) 39 unused-rec-flag 未使用的 rec 标志。(自 4.00 版起) 40 name-out-of-scope 在作用域之外使用了构造函数或标签名称。(自 4.01 版起) 41 ambiguous-name 构造函数或标签名称不明确。(自 4.01 版起) 42 disambiguated-name 消歧的构造函数或标签名称(兼容性警告)。(自 4.01 版起) 43 nonoptional-label 将非可选标签用作可选标签。(自 4.01 版起) 44 open-shadow-identifier open 语句隐藏了已定义的标识符。(自 4.01 版起) 45 open-shadow-label-constructor open 语句隐藏了已定义的标签或构造函数。(自 4.01 版起) 46 bad-env-variable 环境变量错误。(自 4.01 版起) 47 attribute-payload 属性有效负载非法。(自 4.02 版起) 48 eliminated-optional-arguments 隐式消除了可选参数。(自 4.02 版起) 49 no-cmi-file 查找模块别名时缺少 cmi 文件。(自 4.02 版起) 50 unexpected-docstring 意外的文档注释。(自 4.03 版起) 51 wrong-tailcall-expectation 函数调用使用错误的 @tailcall 属性进行注释。(自 4.03 版起) 52 fragile-literal-pattern (参见 13.5.3 ) 脆弱的常量模式。(自 4.03 版起) 53 misplaced-attribute 属性不能出现在此上下文中。(自 4.03 版起) 54 duplicated-attribute 在表达式上多次使用了属性。(自 4.03 版起) 55 inlining-impossible 内联操作无法执行。(自 4.03 版起) 56 unreachable-case 模式匹配中的不可达情况(基于类型信息)。(自 4.03 版起) 57 ambiguous-var-in-pattern-guard (参见 13.5.4 ) 受保护的不明确或模式变量。(自 4.03 版起) 58 no-cmx-file 缺少 cmx 文件。(自 4.03 版起) 59 flambda-assignment-to-non-mutable-value 对不可变值进行赋值。(自 4.03 版起) 60 unused-module 未使用的模块声明。(自 4.04 版起) 61 unboxable-type-in-prim-decl 在基本类型声明中使用了不可拆箱的类型。(自 4.04 版起) 62 constraint-on-gadt GADT 类型声明上的类型约束。(自 4.06 版起) 63 erroneous-printed-signature 打印的签名错误。(自 4.08 版起) 64 unsafe-array-syntax-without-parsing -unsafe 与返回语法树的预处理器一起使用。(自 4.08 版起) 65 redefining-unit 类型声明定义了一个新的 '()' 构造函数。(自 4.08 版起) 66 unused-open-bang 未使用的 open! 语句。(自 4.08 版起) 67 unused-functor-parameter 未使用的函子参数。(自 4.10 版起) 68 match-on-mutable-state-prevent-uncurry 依赖于可变状态的模式匹配阻止了剩余参数被展开。(自 4.12 版起) 69 unused-field 未使用的记录字段。(自 4.13 版起) 70 missing-mli 缺少接口文件。(自 4.13 版起) 71 unused-tmc-attribute 未使用的 @tail_mod_cons 属性。(自 4.14 版起) 72 tmc-breaks-tailcall @tail_mod_cons 变换将尾调用转换为非尾调用。(自 4.14 版起) 73 generative-application-expects-unit 生成式函子应用于空结构体(struct end)而不是 ()。(自 5.1 版起) A 所有警告 C 警告 1、2。 D 警告 3 的别名。 E 警告 4 的别名。 F 警告 5 的别名。 K 警告 32、33、34、35、36、37、38、39。 L 警告 6 的别名。 M 警告 7 的别名。 P 警告 8 的别名。 R 警告 9 的别名。 S 警告 10 的别名。 U 警告 11、12。 V 警告 13 的别名。 X 警告 14、15、16、17、18、19、20、21、22、23、24、30。 Y 警告 26 的别名。 Z 警告 27 的别名。 默认设置为 -w +a-4-6-7-9-27-29-32..42-44-45-48-50-60 。它由 ocamlopt -help 显示。请注意,警告 5 和 10 并不总是触发,具体取决于类型检查器的内部机制。
-warn-error warning-list 将参数 warning-list 中指定的警告标记为致命错误。当发出这些警告之一时,编译器将停止并报错。warning-list 与 -w 选项的含义相同:+ 符号(或大写字母)将相应的警告标记为致命错误,- 符号(或小写字母)将它们恢复为非致命警告,@ 符号同时启用并将其标记为致命警告。注意:不建议在生产代码中使用警告集(即字母)作为 -warn-error 的参数,因为这可能会在 OCaml 的未来版本添加一些新警告时破坏您的构建。
默认设置为 -warn-error -a (没有警告是致命的)。
-warn-help 显示所有可用警告编号的描述。 -where 打印标准库的位置,然后退出。 -with-runtime 在生成的程序中包含运行时系统。这是默认设置。 -without-runtime 编译器不会在生成的程序中包含运行时系统(也不包含对它的引用);它必须单独提供。 - file 处理 file 作为文件名,即使它以连字符 (- ) 字符开头。 -help 或 --help 显示简短的使用摘要并退出。
64 位 x86 架构的选项
Intel/AMD x86 处理器(amd64 架构)的 64 位代码生成器支持以下附加选项
-fPIC 生成位置无关的机器代码。这是默认设置。 -fno-PIC 生成位置相关的机器代码。
命令行选项的上下文控制
可以使用以下机制“从外部”修改编译器命令行。这些是实验性的,可能会发生变化。它们仅应用于实验和开发工作,不应用于发布的软件包。
OCAMLPARAM (环境变量) 一组将在命令行参数之前或之后插入的参数。参数以逗号分隔的 name=value 对列表的形式指定。_ 用于指定命令行参数的位置,例如 a=x,_,b=y 表示应在解析参数之前执行 a=x ,并在之后执行 b=y 。最后,可以在字符串的第一个字符中指定备用分隔符,该字符位于 :|; , 集中。 ocaml_compiler_internal_params (stdlib 目录中的文件)文件名到参数列表的映射,这些参数将添加到命令行(以及 OCAMLPARAM )参数中。
3 常见错误
错误消息与 ocamlc 的错误消息几乎相同。参见第 13.4 节。
4 运行由 ocamlopt 生成的可执行文件
由 ocamlopt 生成的可执行文件是本机独立的可执行文件,可以直接调用。它们不依赖于 ocamlrun 字节码运行时系统,也不依赖于动态加载的 C/OCaml 存根库。
在执行 ocamlopt 生成的可执行文件期间,还会参考以下环境变量
OCAMLRUNPARAM 与 ocamlrun 中的使用方式相同(参见第 15.2 节),除了选项 l 被忽略(使用操作系统的堆栈大小限制)。 CAMLRUNPARAM 如果在环境中找不到 OCAMLRUNPARAM ,则将改为使用 CAMLRUNPARAM 。如果找不到 CAMLRUNPARAM ,则将使用默认值。
5 与字节码编译器的兼容性
本节列出了字节码编译器和本机代码编译器之间已知的兼容性问题。除了这些方面之外,这两个编译器应该生成行为相同的代码。
信号仅在程序在堆上执行分配时检测到。也就是说,如果在不执行分配的代码段中传递了信号,则其处理程序将不会被调用,直到下一次堆分配。 在 ARM 和 PowerPC 处理器(32 位和 64 位)上,可以为浮点乘法后跟浮点加法或减法生成融合乘加 (FMA) 指令,如 x *. y +. z 。FMA 指令避免对中间结果 x *. y 进行舍入,这通常是有益的,但会产生与字节码解释器产生的浮点结果略有不同的结果。 原生代码编译器执行了许多字节码编译器不执行的优化,尤其是在 Flambda 优化器处于活动状态时。特别是,原生代码编译器识别并消除了“死代码”,即不影响程序结果的计算。例如, let _ = ignore M.f
在编译为字节码时包含对编译单元 M 的引用。此引用强制链接 M 并执行其初始化代码。原生代码编译器消除了对 M 的引用,因此编译单元 M 可能不会被链接和执行。解决方法是使用 -linkall 标志编译 M ,以便即使没有引用,它也会始终被链接和执行。另请参阅来自 Sys 标准库模块的 Sys.opaque_identity 函数。 在 4.10 之前,堆栈溢出(通常由过深的递归引起)并不总是像字节码编译器那样转换为 Stack_overflow 异常。运行时系统尽最大努力捕获堆栈溢出并引发 Stack_overflow 异常,但有时会失败,并导致“段错误”或其他系统故障。
版权所有 © 2024 法国国家信息与自动化研究所