是否可以从OCaml调用C函数,而不包含类型?

我正试图在OCaml中编写一个(极其微小,简单 – 我不知道我在做什么,让我们真实!)编译器。

我真的想避免在项目中检查任何 ISO-C代码(尽管很好地了解C;这里的目标是专门学习和使用OCaml。)根据这一点,我需要为编译编写一个“运行时” OCaml中的语言,与主项目分开编译,然后将其与编译器本身的输出相关联。

不幸的是,它看起来像任何外部函数 – 甚至那些不接触任何OCaml数据结构/ OCaml堆的函数 – 都应该使用OCaml的C宏构建:

CAMLprim value scheme_entry(value unit) { int i; i = 42; return Val_int(i); } 

如果我自己发出assembly说明,这可能不是一个选择。 (至少,直到我学到更多东西!)

是否有任何方法(包括hacky – 这是一个个人学习项目)来调用OCaml中的以下非常简单的函数?

 _scheme_entry: movl $42 %eax ret 

作为参考,我正在通过Ghuloum的IACC: http ://ell.io/tt$ocameel

不幸的是,它看起来像任何外部函数 – 甚至那些不接触任何OCaml数据结构/ OCaml堆的函数 – 都应该使用OCaml的C宏构建:

不,他们不是。 如果您的函数根本没有触及OCaml,或者没有分配或使用分配的值,那么您可以直接调用函数,例如,

 value scheme_entry(value unit) { int i; i = 42; return Val_int(i); } 

在OCaml方面:

 external scheme_entry : unit -> int = "scheme_entry" [@@noalloc] 

在OCaml的最新版本中,我们获得了更多的控制权,因此我们可以在没有装箱/拆箱的情况下传递浮点数和更大的整数。 请阅读此处了解更多信息。

注意, Val_int只是一个宏,它将C整数向左移一位,并将最低有效位设置为1,即(((unsigned)(x) << 1)) + 1) 。 因此,如果您不需要将OCaml整数转换为C整数和反之​​,那么您甚至不需要使用此宏,因此运行时可能完全不知道OCaml,例如:

  void runtime_init(void) { printf("Hello from runtime"); } 

在OCaml方面:

  val runtime_init : unit -> unit = "runtime_init" [@@noalloc] 

注意: [@@noalloc]属性是在OCaml 4.03中添加的,在该版本之前,你应该使用"noalloc" ,例如,

  val runtime_init : unit -> unit = "runtime_init" "noalloc" 

当然,您非常简单的函数应遵循适合您的特定体系结构和操作系统的C调用约定。 因此,如果你的函数破坏了一些应该保留的寄存器,你应该会遇到麻烦,例如在amd64 ABI上你应该保留rbp,rbx,r12-r15。 OCaml没有特定于此要求,只是一个普通的C调用约定。

您可能希望研究使用可通过OPAM获得的ctypes库和相关软件包。

 opam install ctypes ctypes-foreign posix-types 

例:

 open Foreign open Ctypes open Posix_types let getpid = foreign "getpid" (void @-> returning pid_t) let () = Printf.printf "%d\n" (Pid.to_int (getpid ())) 

(编译它需要包ctypesctypes.foreignposix-types 。)