第 16 章 本机代码编译 (ocamlopt)

本章介绍 OCaml 高性能本机代码编译器 ocamlopt,它将 OCaml 源文件编译成本机代码目标文件,并将这些目标文件链接起来生成独立的可执行文件。

本机代码编译器仅在某些平台上可用。它生成的代码运行速度比 ocamlc 生成的字节码快,但代价是编译时间和可执行文件大小增加。与字节码编译器的兼容性非常高:相同的源代码在使用 ocamlcocamlopt 编译时应该运行相同。

无法将 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 -llibname
-llibname 选项传递给链接器。这会导致将给定的 C 库链接到程序中。
-ccopt option
将给定的选项传递给 C 编译器和链接器。例如,-ccopt -Ldir 会导致 C 链接器在目录 dir 中搜索 C 库。
-cmi-file filename
使用给定的接口文件来类型检查要编译的 ML 源文件。当未指定此选项时,编译器会在与正在编译的实现文件同名的目录中搜索一个 .mli 文件。如果找到此文件,编译器将在包含的目录中搜索对应的 .cmi 文件,如果未找到则报告错误。
-color mode
启用或禁用编译器消息(尤其是警告和错误)中的颜色。支持以下模式
auto
使用启发式方法仅在输出支持颜色时启用颜色(兼容 ANSI 的 tty 终端);
always
无条件启用颜色;
never
禁用颜色输出。

如果未提供 -color,则会考虑环境变量 OCAML_COLOR。其值如上所述为 auto/always/never。

如果未提供 -colorOCAML_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..cmxa.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.cmxP.oP.cmi,描述一个具有三个子模块 ABC 的编译单元,对应于对象文件 A.cmxB.cmxC.cmx 的内容。这些内容可以在程序的其余部分中作为 P.AP.BP.C 来引用。

要组合的 .cmx 对象文件必须使用适当的 -for-pack 选项进行编译。在上面的示例中,A.cmxB.cmxC.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.QP.Q.AP.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
强制执行类型 stringbytes 之间的分离,从而使字符串成为只读的。这是默认设置,并且从 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
识别stringbytes类型,从而使字符串可写。这旨在与旧版源代码兼容,不应在新的软件中使用。从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
可疑的未使用变量:使用letas绑定的未使用变量,并且不以下划线(_)字符开头。
27 unused-var-strict
无害的未使用变量:未使用letas绑定的未使用变量,并且不以下划线(_)字符开头。
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 与字节码编译器的兼容性

本节列出了字节码编译器和本机代码编译器之间已知的兼容性问题。除了这些方面之外,这两个编译器应该生成行为相同的代码。