创建依赖于my_lib.cm*a
的库sqlite3.cm*a
之后,尝试使用my_lib.cm*a
构建新项目但是sqlite3.cm*a
的旧版本我得到编译时错误& #34;对接口Sqlite3"的不一致假设。尝试在顶层中使用较早的my_lib.cma
sqlite3.cma
时会发生类似的错误。这两个版本实际上位于不同的系统上,my_lib.cm*a
被复制到较旧的版本。
我运行了两个sqlite3.mli文件的差异,并确定问题似乎是一行。在较新版本的sqlite3中,它是:
external enable_load_extension :
db -> bool -> bool = "caml_sqlite3_enable_load_extension"
但是有#34; 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文件来定义接口并且不会#39; t包括任何接口信息本身,所以我到目前为止所描述的行为似乎有意义。
当我尝试使用本机编译器时,我感到困惑。如果我尝试ocamlopt sratch/dir/sqlite.cmxa my_lib.cmxa prog.ml -o prog
,那么编译器会再次抱怨my_lib.cmxa
和sratch/dir/sqlite3.cmxa
对接口Sqlite3做出不一致的假设。从这里我推断出本机编译单元(正确的术语?)或至少本机存档包含其中的接口信息。这对我来说似乎很奇怪,因为manual没有说任何关于以任何方式包含接口的cmxa文件(尽管它确实讨论了包含的其他文件类型)。
sqlite3.cmxa
中包含my_lib.cmxa
一样? (我会认为使用-for-pack / -pack但我需要实际的sqlite3.ml文件,因为这不是吗?)external
函数的(我真的不知道关于ocaml与C的接口)吗?。external
关键字是什么/我是否假设" noalloc"是C库中外部函数的参数,但我不知道使用它的优点/缺点是什么。 作为最后一点,我知道这不是正确的'处理这种情况的方法;我想通常要做的是使用opam切换到用于制作my_lib.cm*a
的相同编译器,然后使用opam安装相同版本的sqlite3,但这不是我&#t; t 39;我正在寻找(主要是因为我希望更好地理解编译过程,但是当我尝试在旧系统上安装时,opam似乎无法正常工作/它会发出错误) 。基本上,我说我没有找到可以归结为在老系统上使用opam的答案"。
my_lib.cm*a
会使一切正常。我想这应该是我编译/分发软件的新鲜事,尽管这并没有回答一些概念"的问题。答案 0 :(得分:1)
我的扣除是否正确?
或多或少。
我的顶级/字节代码编译器的攻击(即将mli编辑为预期的那个然后使用它)通常/经常工作的东西,或者偶然发现它遇到的罕见情况。
你偶然发现了一个罕见的案例。实际上,您只是提供了更多信息,允许编译器更有效地调用此外部函数。一般来说,当你打破实现与其界面之间的一致性时,它当然不应该工作。
是否有类似的hack才能使本机编译工作?
您可以像重新编译cmxa
文件一样重新编译cmi
(库)文件。但它已经不是黑客了。
有关所有这类编译器业务的参考资料的任何好建议吗?
编译器代码本身。有一个OCaml编译器黑客wiki,其中包含一些有用的信息,但它们不包含链接。
是否有一种标准的方法可以使库更加独立于系统(不依赖于opam),就像某种方式在my_lib.cmxa中包含sqlite3.cmxa一样?
没有标准方法,但您可以将所有文件复制到文件夹中。 (顺便说一下,cmxa
不包含二进制代码,它位于.a
文件中。cmxa
以及cmx
只包含有关编译单元的eXtra信息或单位)。
我认为使用-for-pack / -pack ...
for-pack
和pack
旨在解决命名空间问题,在背后,包仍然是同一组cmxa
,cmx
,a
和o
个文件。
但我需要实际的sqlite3.ml文件,因为这不是我吗?
技术上是的,除非你打算使用编译工具来破解它。
这种行为是否特定于外部功能(我真的不知道有关将ocaml与C接口的事情)?。
没有。不一致性检查只是比较编译接口和实现的md5总和。
......但是,如果有人知道他们的头顶;什么是" noalloc"实际上呢?
noalloc
指示编译器此外部C函数不分配任何OCaml值。这意味着编译器在调用函数时不需要为GC帧表插入特殊的序言和结尾代码。这实际上是一个非常快速的调用,只是一个汇编call
指令。此限定符应记录在下一版OCaml(4.03)中。
由此我推断出本机编译单元(正确的术语?)或至少本机存档包含其中的接口信息。
是的,这是一个正确的术语。是的,它们包含有关接口的一些信息:导入接口的名称和md5sum。您可以使用ocamlobjinfo
程序转储此信息。
虽然我并不完全理解编译器如何使用带有字节代码文件的接口文件,但在我看来,字节代码库使用.cmi文件来定义接口并且不会#39; t包括任何接口信息本身,所以我到目前为止所描述的行为似乎有意义。
库代码至少包含md5个接口。您刚刚绕过了在链接阶段进行的一致性检查,并且打破了编译器的假设,即如果检查单元与某些cmi
,那么之后没有人会替换此cmi。因此,cma
文件仍然认为它使用的是旧cmi
。