使用不同的库版本:修复接口上不一致的假设
Using different library versions: fixing inconsistent assumptions over interface
问题
在创建依赖于 sqlite3.cm*a
的库 my_lib.cm*a
后,尝试使用 my_lib.cm*a
构建新项目,但使用旧版本的 sqlite3.cm*a
我得到了编译时间错误 "inconsistent assumptions over interface Sqlite3"。尝试将 my_lib.cma
与顶层中较旧的 sqlite3.cma
一起使用时会发生类似的错误。这两个不同的版本实际上在不同的系统上,my_lib.cm*a
被复制到旧版本。
issue的测试与探索
我 运行 比较了两个 sqlite3.mli 文件,发现问题似乎是一行。在较新版本的 sqlite3 中是:
external enable_load_extension :
db -> bool -> bool = "caml_sqlite3_enable_load_extension"
但在旧系统上有 "noalloc" 选项:
external enable_load_extension :
db -> bool -> bool = "caml_sqlite3_enable_load_extension" "noalloc"
所以我所做的是将较新版本的 sqlite3.mli 复制到具有旧 sqlite3 的系统(在临时目录中),将其编译成 sqlite3.cmi,复制旧的 sqlite3.cma 和 sqlite3.cmxa 到临时目录。现在,如果在顶层我做
#load "sqratch/dir/sqlite3.cma"
#load "my_lib.cma"
my_lib.do_stuff
它突然起作用了——没有错误报告。我还可以编译一个程序 prog.ml
,它使用 my_lib.cma
和 ocamlc sratch/dir/sqlite.cma my_lib.cma prog.ml -o prog
,它编译没有错误并且运行得很好。
虽然我不太明白编译器是如何将接口文件与字节码文件一起使用的,但在我看来,字节码库使用.cmi文件来定义接口而不是它本身不包含任何接口信息,因此到目前为止我所描述的行为似乎是有道理的。
我感到困惑的地方是当我尝试使用本机编译器时。如果我尝试 ocamlopt sratch/dir/sqlite.cmxa my_lib.cmxa prog.ml -o prog
然后编译器再次抱怨 my_lib.cmxa
和 sratch/dir/sqlite3.cmxa
在接口 Sqlite3 上做出不一致的假设。由此我推断,本机编译单元(这是正确的术语吗?)或至少本机档案包含其中的接口信息。不过,这对我来说似乎很奇怪,因为 manual 没有说明以任何方式包含接口的 cmxa 文件(尽管它确实讨论了包含的其他文件类型)。
所以现在我的问题...
- 我的推论正确吗?
- 我对 toplevel/byte 代码编译器的黑客攻击(即将 mli 编辑为预期的然后使用它)是否可以 generally/often 工作或者我偶然发现了一个罕见的情况
- 是否有类似的 hack 来使本机编译正常工作?
- 对于所有此类编译器业务的参考有什么好的建议吗? (我一直在努力寻找有关 compilation/linking 如何工作的好参考资料)我发现的所有内容似乎都没有真正解释东西(即使是 manual 我本以为会是一些巨大的参考文档这对我来说是完全无法理解的。)也许没有我正在寻找的类型的真正引用,我必须了解 C 编译器的工作原理 for/instead? (我之前只用 C 写过 "hello world" 级别的程序,而 ocaml 是我用来生成本机可执行文件的第一种语言)。
- 是否有一种标准方法可以使库更加独立于系统(不依赖于 opam),例如以某种方式将
sqlite3.cmxa
包含在 my_lib.cmxa
中? (我想使用 -for-pack/-pack 但我需要实际的 sqlite3.ml 文件,不是吗?)
- 此行为是否在某种程度上特定于
external
函数(我真的不知道如何将 ocaml 与 C 接口)?
- 这是我在这一点上超级懒惰(因为我没有精力去查看 sqlite3 的文档,它不是 sqlite3.mli 并且它不是特别相关),但是如果有人知道他们的头顶; "noalloc" 实际上是做什么的?不知道
external
关键字 is/does 我假设 "noalloc" 是 C 库中外部函数的参数,但我不知道 pros/cons 使用它可能是。
最后一点,我知道这不是 'right' 处理这种情况的方法;我想通常要做的是使用 opam 切换到用于制作 my_lib.cm*a
的同一编译器,然后使用 opam 安装相同版本的 sqlite3,但这不是我想要的for(主要是因为我想更好地理解编译过程,但当我尝试在旧系统上安装它时,opam 似乎 work/it 也没有吐出错误)。基本上,我会说我不是在寻找归结为 "use opam on the older system".
的答案
编辑
- 好吧,再花几分钟就得到了一个不错的解决方案(我想这基本上是 'normal'/显而易见的方法)来解决这个问题,我想这通常应该可行(除非外部库的接口实际上发生了变化)。在旧系统上从源代码构建
my_lib.cm*a
使一切正常。我想这应该是我对 compiling/distributing 软件的新鲜感,尽管这并没有回答一些 "conceptual" 问题。
Are my deductions correct?
或多或少。
Is my hack for the toplevel/byte code compiler (i.e. editing the mli to the expected one and then using that) something that will generally/often work or have I stumbled across a rare case where it does.
您遇到了一个罕见的案例。实际上你只是提供了更多信息,允许编译器更有效地调用这个外部函数。一般来说,它当然不应该工作,因为你破坏了实现与其接口之间的一致性。
Is there a similar hack to get native compilation to work?
您可以像重新编译 cmi
文件一样重新编译 cmxa
(库)文件。但这已经不是黑客了。
Any good suggestions for references about all this sort of compiler business?
编译器代码本身。有一个 OCaml Compiler Hacking wiki,其中包含一些有用的信息,但不包括链接。
Is there a standard way to make libraries more system independent (that does not depend on opam), like somehow including sqlite3.cmxa in my_lib.cmxa?
没有标准方法,但您可以将所有文件复制到一个文件夹中。 (顺便说一句,cmxa
不包含二进制代码,它在 .a
文件中。cmxa
和 cmx
只包含有关一个或多个编译单元的额外信息).
I would think using -for-pack/-pack...
for-pack
和pack
是为了解决命名空间问题而设计的,在引擎盖下,包仍然是同一套cmxa
、cmx
、a
和 o
个文件。
but I need the actual sqlite3.ml files for this don't I?
从技术上讲是的,除非您打算使用编译器工具来破解它。
Is this behaviour in some way specific to the external function (I really don't know anything about interfacing ocaml with C)?.
没有。不一致性检查只是比较编译接口和实现的 md5 总和。
... but if someone knows off the top of their head; what does the "noalloc" actually do?
noalloc
向编译器指定此外部 C 函数不分配任何 OCaml 值。这意味着编译器在调用该函数时不需要为 GC 框架 table 插入特殊的序言和结尾代码。这实际上使调用非常快,只是一个汇编 call
指令。此限定符应记录在下一版本的 OCaml (4.03) 中。
From this I deduce that native compilation units (is that the right term?) or at least native archives contain the interface information in them.
是的,这是一个正确的术语。是的,它们包含一些关于接口的信息:导入接口的名称和 md5sum。您可以使用 ocamlobjinfo
程序来转储此信息。
Though I don't really understand exactly how the compiler makes use of the interface files with the byte code files, from this it seems to me that a byte code library uses a .cmi file to define to interface and doesn't include any interface information itself, so the behaviour I've described so far seems to make sense.
库代码至少包含接口的 md5 和。您刚刚绕过了在链接阶段进行的一致性检查,并打破了编译器的假设,即如果检查一个单元与一些 cmi
,那么以后没有人会替换这个 cmi。所以 cma
文件仍然认为它使用旧的 cmi
.
问题
在创建依赖于 sqlite3.cm*a
的库 my_lib.cm*a
后,尝试使用 my_lib.cm*a
构建新项目,但使用旧版本的 sqlite3.cm*a
我得到了编译时间错误 "inconsistent assumptions over interface Sqlite3"。尝试将 my_lib.cma
与顶层中较旧的 sqlite3.cma
一起使用时会发生类似的错误。这两个不同的版本实际上在不同的系统上,my_lib.cm*a
被复制到旧版本。
issue的测试与探索
我 运行 比较了两个 sqlite3.mli 文件,发现问题似乎是一行。在较新版本的 sqlite3 中是:
external enable_load_extension :
db -> bool -> bool = "caml_sqlite3_enable_load_extension"
但在旧系统上有 "noalloc" 选项:
external enable_load_extension :
db -> bool -> bool = "caml_sqlite3_enable_load_extension" "noalloc"
所以我所做的是将较新版本的 sqlite3.mli 复制到具有旧 sqlite3 的系统(在临时目录中),将其编译成 sqlite3.cmi,复制旧的 sqlite3.cma 和 sqlite3.cmxa 到临时目录。现在,如果在顶层我做
#load "sqratch/dir/sqlite3.cma"
#load "my_lib.cma"
my_lib.do_stuff
它突然起作用了——没有错误报告。我还可以编译一个程序 prog.ml
,它使用 my_lib.cma
和 ocamlc sratch/dir/sqlite.cma my_lib.cma prog.ml -o prog
,它编译没有错误并且运行得很好。
虽然我不太明白编译器是如何将接口文件与字节码文件一起使用的,但在我看来,字节码库使用.cmi文件来定义接口而不是它本身不包含任何接口信息,因此到目前为止我所描述的行为似乎是有道理的。
我感到困惑的地方是当我尝试使用本机编译器时。如果我尝试 ocamlopt sratch/dir/sqlite.cmxa my_lib.cmxa prog.ml -o prog
然后编译器再次抱怨 my_lib.cmxa
和 sratch/dir/sqlite3.cmxa
在接口 Sqlite3 上做出不一致的假设。由此我推断,本机编译单元(这是正确的术语吗?)或至少本机档案包含其中的接口信息。不过,这对我来说似乎很奇怪,因为 manual 没有说明以任何方式包含接口的 cmxa 文件(尽管它确实讨论了包含的其他文件类型)。
所以现在我的问题...
- 我的推论正确吗?
- 我对 toplevel/byte 代码编译器的黑客攻击(即将 mli 编辑为预期的然后使用它)是否可以 generally/often 工作或者我偶然发现了一个罕见的情况
- 是否有类似的 hack 来使本机编译正常工作?
- 对于所有此类编译器业务的参考有什么好的建议吗? (我一直在努力寻找有关 compilation/linking 如何工作的好参考资料)我发现的所有内容似乎都没有真正解释东西(即使是 manual 我本以为会是一些巨大的参考文档这对我来说是完全无法理解的。)也许没有我正在寻找的类型的真正引用,我必须了解 C 编译器的工作原理 for/instead? (我之前只用 C 写过 "hello world" 级别的程序,而 ocaml 是我用来生成本机可执行文件的第一种语言)。
- 是否有一种标准方法可以使库更加独立于系统(不依赖于 opam),例如以某种方式将
sqlite3.cmxa
包含在my_lib.cmxa
中? (我想使用 -for-pack/-pack 但我需要实际的 sqlite3.ml 文件,不是吗?) - 此行为是否在某种程度上特定于
external
函数(我真的不知道如何将 ocaml 与 C 接口)? - 这是我在这一点上超级懒惰(因为我没有精力去查看 sqlite3 的文档,它不是 sqlite3.mli 并且它不是特别相关),但是如果有人知道他们的头顶; "noalloc" 实际上是做什么的?不知道
external
关键字 is/does 我假设 "noalloc" 是 C 库中外部函数的参数,但我不知道 pros/cons 使用它可能是。
最后一点,我知道这不是 'right' 处理这种情况的方法;我想通常要做的是使用 opam 切换到用于制作 my_lib.cm*a
的同一编译器,然后使用 opam 安装相同版本的 sqlite3,但这不是我想要的for(主要是因为我想更好地理解编译过程,但当我尝试在旧系统上安装它时,opam 似乎 work/it 也没有吐出错误)。基本上,我会说我不是在寻找归结为 "use opam on the older system".
编辑
- 好吧,再花几分钟就得到了一个不错的解决方案(我想这基本上是 'normal'/显而易见的方法)来解决这个问题,我想这通常应该可行(除非外部库的接口实际上发生了变化)。在旧系统上从源代码构建
my_lib.cm*a
使一切正常。我想这应该是我对 compiling/distributing 软件的新鲜感,尽管这并没有回答一些 "conceptual" 问题。
Are my deductions correct?
或多或少。
Is my hack for the toplevel/byte code compiler (i.e. editing the mli to the expected one and then using that) something that will generally/often work or have I stumbled across a rare case where it does.
您遇到了一个罕见的案例。实际上你只是提供了更多信息,允许编译器更有效地调用这个外部函数。一般来说,它当然不应该工作,因为你破坏了实现与其接口之间的一致性。
Is there a similar hack to get native compilation to work?
您可以像重新编译 cmi
文件一样重新编译 cmxa
(库)文件。但这已经不是黑客了。
Any good suggestions for references about all this sort of compiler business?
编译器代码本身。有一个 OCaml Compiler Hacking wiki,其中包含一些有用的信息,但不包括链接。
Is there a standard way to make libraries more system independent (that does not depend on opam), like somehow including sqlite3.cmxa in my_lib.cmxa?
没有标准方法,但您可以将所有文件复制到一个文件夹中。 (顺便说一句,cmxa
不包含二进制代码,它在 .a
文件中。cmxa
和 cmx
只包含有关一个或多个编译单元的额外信息).
I would think using -for-pack/-pack...
for-pack
和pack
是为了解决命名空间问题而设计的,在引擎盖下,包仍然是同一套cmxa
、cmx
、a
和 o
个文件。
but I need the actual sqlite3.ml files for this don't I?
从技术上讲是的,除非您打算使用编译器工具来破解它。
Is this behaviour in some way specific to the external function (I really don't know anything about interfacing ocaml with C)?.
没有。不一致性检查只是比较编译接口和实现的 md5 总和。
... but if someone knows off the top of their head; what does the "noalloc" actually do?
noalloc
向编译器指定此外部 C 函数不分配任何 OCaml 值。这意味着编译器在调用该函数时不需要为 GC 框架 table 插入特殊的序言和结尾代码。这实际上使调用非常快,只是一个汇编 call
指令。此限定符应记录在下一版本的 OCaml (4.03) 中。
From this I deduce that native compilation units (is that the right term?) or at least native archives contain the interface information in them.
是的,这是一个正确的术语。是的,它们包含一些关于接口的信息:导入接口的名称和 md5sum。您可以使用 ocamlobjinfo
程序来转储此信息。
Though I don't really understand exactly how the compiler makes use of the interface files with the byte code files, from this it seems to me that a byte code library uses a .cmi file to define to interface and doesn't include any interface information itself, so the behaviour I've described so far seems to make sense.
库代码至少包含接口的 md5 和。您刚刚绕过了在链接阶段进行的一致性检查,并打破了编译器的假设,即如果检查一个单元与一些 cmi
,那么以后没有人会替换这个 cmi。所以 cma
文件仍然认为它使用旧的 cmi
.